gitingest 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/gitingest/generator.rb +81 -28
- data/lib/gitingest/version.rb +1 -1
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd7a1e5d5ced0b5449fa30671b0d9a536685d37c3d0d34d33437f652df24c199
|
4
|
+
data.tar.gz: c49a7c6489f7074e3870a05b5d1e47b0ea3e6b7a6eadce405db3c300d8165434
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64b73ea01bc836a500c82a260c41be6f87e6f0c72bf868bee059407eea45466ad4892d905b7b69f5c6151e40e92d2553c8b8f678bfe1155fef968486648ae871
|
7
|
+
data.tar.gz: 7c18261e6fdb279916d2f8bff4557de76eb6ec0c039861d646f5f56dadacbef536b176d2a48fb25d142b70e30e868fb431f9cde6aad69262ee6f8dc37232ea0a
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## [0.3.0] - 2025-03-02
|
6
|
+
- Added `faraday-retry` gem dependency for better API rate limit handling
|
7
|
+
- Implemented thread-safe buffer management with mutex locks
|
8
|
+
- Added new `ProgressIndicator` class for better CLI progress reporting (showing percentages)
|
9
|
+
- Improved memory efficiency with configurable buffer size
|
10
|
+
- Enhanced code organization with dedicated methods for file content formatting
|
11
|
+
- Added comprehensive method documentation and parameter descriptions
|
12
|
+
- Optimized thread pool size calculation for better performance
|
13
|
+
- Improved error handling in concurrent operations
|
14
|
+
|
5
15
|
## [0.2.0] - 2025-03-02
|
6
16
|
- Added support for quiet and verbose modes in the command-line interface
|
7
17
|
- Added the ability to specify a custom output file for the prompt
|
data/lib/gitingest/generator.rb
CHANGED
@@ -67,9 +67,21 @@ module Gitingest
|
|
67
67
|
|
68
68
|
# Maximum number of files to process to prevent memory overload
|
69
69
|
MAX_FILES = 1000
|
70
|
+
BUFFER_SIZE = 100 # Write every 100 files to reduce I/O operations
|
70
71
|
|
71
72
|
attr_reader :options, :client, :repo_files, :excluded_patterns, :logger
|
72
73
|
|
74
|
+
# Initialize a new Generator with the given options
|
75
|
+
#
|
76
|
+
# @param options [Hash] Configuration options
|
77
|
+
# @option options [String] :repository GitHub repository in format "username/repo"
|
78
|
+
# @option options [String] :token GitHub personal access token
|
79
|
+
# @option options [String] :branch Repository branch (default: "main")
|
80
|
+
# @option options [String] :output_file Output file path
|
81
|
+
# @option options [Array<String>] :exclude Additional patterns to exclude
|
82
|
+
# @option options [Boolean] :quiet Reduce logging to errors only
|
83
|
+
# @option options [Boolean] :verbose Increase logging verbosity
|
84
|
+
# @option options [Logger] :logger Custom logger instance
|
73
85
|
def initialize(options = {})
|
74
86
|
@options = options
|
75
87
|
@repo_files = []
|
@@ -80,6 +92,15 @@ module Gitingest
|
|
80
92
|
compile_excluded_patterns
|
81
93
|
end
|
82
94
|
|
95
|
+
# Main execution method
|
96
|
+
def run
|
97
|
+
fetch_repository_contents
|
98
|
+
generate_prompt
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# Set up logging based on verbosity options
|
83
104
|
def setup_logger
|
84
105
|
@logger = @options[:logger] || Logger.new($stdout)
|
85
106
|
@logger.level = if @options[:quiet]
|
@@ -89,11 +110,11 @@ module Gitingest
|
|
89
110
|
else
|
90
111
|
Logger::INFO
|
91
112
|
end
|
92
|
-
#
|
113
|
+
# Simplify logger format for command line usage
|
93
114
|
@logger.formatter = proc { |severity, _, _, msg| "#{severity == "INFO" ? "" : "[#{severity}] "}#{msg}\n" }
|
94
115
|
end
|
95
116
|
|
96
|
-
|
117
|
+
# Validate and set default options
|
97
118
|
def validate_options
|
98
119
|
raise ArgumentError, "Repository is required" unless @options[:repository]
|
99
120
|
|
@@ -103,7 +124,7 @@ module Gitingest
|
|
103
124
|
@excluded_patterns = DEFAULT_EXCLUDES + @options[:exclude]
|
104
125
|
end
|
105
126
|
|
106
|
-
|
127
|
+
# Configure the GitHub API client
|
107
128
|
def configure_client
|
108
129
|
@client = @options[:token] ? Octokit::Client.new(access_token: @options[:token]) : Octokit::Client.new
|
109
130
|
|
@@ -115,17 +136,16 @@ module Gitingest
|
|
115
136
|
end
|
116
137
|
end
|
117
138
|
|
139
|
+
# Convert exclusion patterns to regular expressions
|
118
140
|
def compile_excluded_patterns
|
119
141
|
@excluded_patterns = @excluded_patterns.map { |pattern| Regexp.new(pattern) }
|
120
142
|
end
|
121
143
|
|
122
|
-
|
144
|
+
# Fetch repository contents and apply exclusion filters
|
123
145
|
def fetch_repository_contents
|
124
146
|
@logger.info "Fetching repository: #{@options[:repository]} (branch: #{@options[:branch]})"
|
125
147
|
begin
|
126
|
-
# First validate authentication and repository access
|
127
148
|
validate_repository_access
|
128
|
-
|
129
149
|
repo_tree = @client.tree(@options[:repository], @options[:branch], recursive: true)
|
130
150
|
@repo_files = repo_tree.tree.select { |item| item.type == "blob" && !excluded_file?(item.path) }
|
131
151
|
|
@@ -143,8 +163,8 @@ module Gitingest
|
|
143
163
|
end
|
144
164
|
end
|
145
165
|
|
166
|
+
# Validate repository and branch access
|
146
167
|
def validate_repository_access
|
147
|
-
# Check if we can access the repository
|
148
168
|
begin
|
149
169
|
@client.repository(@options[:repository])
|
150
170
|
rescue Octokit::Unauthorized
|
@@ -153,7 +173,6 @@ module Gitingest
|
|
153
173
|
raise "Repository '#{@options[:repository]}' not found or is private. Check the repository name or provide a valid token."
|
154
174
|
end
|
155
175
|
|
156
|
-
# Check if the branch exists
|
157
176
|
begin
|
158
177
|
@client.branch(@options[:repository], @options[:branch])
|
159
178
|
rescue Octokit::NotFound
|
@@ -161,47 +180,64 @@ module Gitingest
|
|
161
180
|
end
|
162
181
|
end
|
163
182
|
|
183
|
+
# Check if a file should be excluded based on its path
|
164
184
|
def excluded_file?(path)
|
165
185
|
return true if path.start_with?(".") || path.split("/").any? { |part| part.start_with?(".") }
|
166
186
|
|
167
187
|
@excluded_patterns.any? { |pattern| path.match?(pattern) }
|
168
188
|
end
|
169
189
|
|
170
|
-
|
190
|
+
# Generate the consolidated prompt file
|
171
191
|
def generate_prompt
|
172
192
|
@logger.info "Generating prompt..."
|
173
|
-
Concurrent::Array.new(@repo_files)
|
174
193
|
buffer = []
|
175
|
-
|
194
|
+
progress = ProgressIndicator.new(@repo_files.size, @logger)
|
176
195
|
|
177
196
|
# Dynamic thread pool based on core count
|
178
|
-
pool = Concurrent::FixedThreadPool.new([Concurrent.processor_count, 5].
|
197
|
+
pool = Concurrent::FixedThreadPool.new([Concurrent.processor_count, 5].min)
|
179
198
|
|
180
199
|
File.open(@options[:output_file], "w") do |file|
|
181
200
|
@repo_files.each_with_index do |repo_file, index|
|
182
201
|
pool.post do
|
183
202
|
content = fetch_file_content_with_retry(repo_file.path)
|
184
|
-
result =
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
print "\rProcessing: #{index + 1}/#{@repo_files.size} files"
|
203
|
+
result = format_file_content(repo_file.path, content)
|
204
|
+
|
205
|
+
# Thread-safe buffer management
|
206
|
+
buffer_mutex.synchronize do
|
207
|
+
buffer << result
|
208
|
+
write_buffer(file, buffer) if buffer.size >= BUFFER_SIZE
|
209
|
+
end
|
210
|
+
|
211
|
+
progress.update(index + 1)
|
194
212
|
rescue Octokit::Error => e
|
195
213
|
@logger.error "Error fetching #{repo_file.path}: #{e.message}"
|
196
214
|
end
|
197
215
|
end
|
216
|
+
|
198
217
|
pool.shutdown
|
199
218
|
pool.wait_for_termination
|
200
|
-
|
219
|
+
|
220
|
+
# Write any remaining files in buffer
|
221
|
+
buffer_mutex.synchronize do
|
222
|
+
write_buffer(file, buffer) unless buffer.empty?
|
223
|
+
end
|
201
224
|
end
|
202
|
-
|
225
|
+
|
226
|
+
@logger.info "Prompt generated and saved to #{@options[:output_file]}"
|
203
227
|
end
|
204
228
|
|
229
|
+
# Format a file's content for the prompt
|
230
|
+
def format_file_content(path, content)
|
231
|
+
<<~TEXT
|
232
|
+
================================================================
|
233
|
+
File: #{path}
|
234
|
+
================================================================
|
235
|
+
#{content}
|
236
|
+
|
237
|
+
TEXT
|
238
|
+
end
|
239
|
+
|
240
|
+
# Fetch file content with retry logic for rate limiting
|
205
241
|
def fetch_file_content_with_retry(path, retries = 3)
|
206
242
|
content = @client.contents(@options[:repository], path: path, ref: @options[:branch])
|
207
243
|
Base64.decode64(content.content)
|
@@ -214,15 +250,32 @@ module Gitingest
|
|
214
250
|
fetch_file_content_with_retry(path, retries - 1)
|
215
251
|
end
|
216
252
|
|
253
|
+
# Write buffer contents to file and clear buffer
|
217
254
|
def write_buffer(file, buffer)
|
218
255
|
file.puts(buffer.join)
|
219
256
|
buffer.clear
|
220
257
|
end
|
221
258
|
|
222
|
-
|
223
|
-
def
|
224
|
-
|
225
|
-
|
259
|
+
# Thread-safe mutex for buffer operations
|
260
|
+
def buffer_mutex
|
261
|
+
@buffer_mutex ||= Mutex.new
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Helper class for showing progress in CLI
|
266
|
+
class ProgressIndicator
|
267
|
+
def initialize(total, logger)
|
268
|
+
@total = total
|
269
|
+
@logger = logger
|
270
|
+
@last_percent = 0
|
271
|
+
end
|
272
|
+
|
273
|
+
def update(current)
|
274
|
+
percent = (current.to_f / @total * 100).round
|
275
|
+
return unless percent > @last_percent && ((percent % 5).zero? || current == @total)
|
276
|
+
|
277
|
+
@logger.info "Processing: #{percent}% complete (#{current}/#{@total} files)"
|
278
|
+
@last_percent = percent
|
226
279
|
end
|
227
280
|
end
|
228
281
|
end
|
data/lib/gitingest/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitingest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Davide Santangelo
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday-retry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: octokit
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|