gitingest 0.6.2 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7a2497f7fc876e9ea8294b4625442c16b1ad0316136a2db7c6a3a8701304eb5
4
- data.tar.gz: b1065ca858fb550c5ea24afdf5c7287f667fae05c41f5de97fceb9409998edd1
3
+ metadata.gz: 0c5544ec1d956710315693490fddc60f26452452ca674739d9a343f0418b26c6
4
+ data.tar.gz: 6d9dd377e78788bf3f3b0a6511cc38cfc9a5e85bba787f905f879235d767dc8c
5
5
  SHA512:
6
- metadata.gz: cc193ab674be65cb24a35888e0dd95dedec91b27f76c5cde23a57b93d4fde0e7d0eddb31e50eda9603059f7996db72c5f669df04d6551e57569b437a118b74e4
7
- data.tar.gz: 6ca8be13b8b25056185ae66cb4cfcde7d947356531b4905e43e40296a299c62dd26ca3044f8577483f4bb889aaacf9e89996b4b70b55b4d894ff6506fa8df17f
6
+ metadata.gz: 96154003ef92d35503ddb9488ee25f147c0809f88226a3554d818e43b6692908fae94e00d56a525a8c31327f7be3b0323486bb79227dac5fe36709cd99f09a11
7
+ data.tar.gz: 25d6c8de3537f84f27feedc6fb3ec812e14ad3ebf1cbe708b3931e757741d00a69d7e43a86f08bb5198cf1532f92b44d64bdf9c53afa2ec802c7013cb54bf366
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.0] - 2025-06-04
4
+
5
+ ### Changed
6
+ - Improved file exclusion logic for glob patterns to correctly match files at any directory depth (e.g., `*.md` now correctly matches `docs/file.md`).
7
+ - Refined internal handling of exclusion patterns for clarity and robustness, using `File.fnmatch` for all custom glob patterns.
8
+ - Enhanced debug logging for file exclusion to show the specific pattern that caused a match.
9
+
10
+ ## [0.6.3] - 2025-04-14
11
+
12
+ ### Fixed
13
+ - Fixed directory exclusion pattern to properly handle paths ending with slash
14
+
3
15
  ## [0.6.2] - 2025-04-11
4
16
 
5
17
  ### Changed
@@ -11,8 +23,6 @@
11
23
  ### Fixed
12
24
  - Fixed error "target of repeat operator is not specified" when using `--exclude` with glob patterns like `*.md`
13
25
 
14
- ---
15
-
16
26
  ## [0.6.0] - 2025-03-18
17
27
 
18
28
  ### Changed
@@ -21,8 +31,6 @@
21
31
  - Updated documentation to reflect the correct default branch behavior
22
32
  - Fixed issues with repository validation in tests
23
33
 
24
- ---
25
-
26
34
  ## [0.5.0] - 2025-03-10
27
35
 
28
36
  ### Added
@@ -35,8 +43,6 @@
35
43
  - Enhanced documentation with directory structure visualization examples
36
44
  - Updated CLI help with the new option
37
45
 
38
- ---
39
-
40
46
  ## [0.4.0] - 2025-03-03
41
47
 
42
48
  ### Added
@@ -55,8 +61,6 @@
55
61
  - Fixed race conditions in progress indicator updates
56
62
  - Addressed timing inconsistencies in multithreaded test scenarios
57
63
 
58
- ---
59
-
60
64
  ## [0.3.1] - 2025-03-03
61
65
 
62
66
  ### Added
@@ -77,8 +81,6 @@
77
81
  - Ensured thread pool shutdown respects the configured timeout.
78
82
  - Resolved potential race conditions in file content retrieval.
79
83
 
80
- ---
81
-
82
84
  ## [0.3.0] - 2025-03-02
83
85
 
84
86
  ### Added
@@ -91,8 +93,6 @@
91
93
  - Optimized thread pool size calculation for improved performance.
92
94
  - Improved error handling in concurrent operations.
93
95
 
94
- ---
95
-
96
96
  ## [0.2.0] - 2025-03-02
97
97
 
98
98
  ### Added
@@ -106,8 +106,6 @@
106
106
  - Enforced a 1000-file limit to prevent memory overload.
107
107
  - Updated version to `0.2.0`.
108
108
 
109
- ---
110
-
111
109
  ## [0.1.0] - 2025-03-02
112
110
 
113
111
  ### Added
data/index.html CHANGED
@@ -716,7 +716,7 @@
716
716
  <div class="header-container">
717
717
  <div class="logo">
718
718
  <div class="logo-icon">G</div>
719
- <div class="logo-text">Gitingest <span class="version-tag">v0.6.2</span></div>
719
+ <div class="logo-text">Gitingest <span class="version-tag">v0.7.0</span></div>
720
720
  </div>
721
721
  <nav>
722
722
  <ul>
@@ -765,7 +765,7 @@
765
765
  <span class="terminal-command">gem install gitingest</span>
766
766
  </div>
767
767
  <div class="terminal-output">
768
- Successfully installed gitingest-0.6.2<br />
768
+ Successfully installed gitingest-0.7.0<br />
769
769
  1 gem installed
770
770
  </div>
771
771
  <div class="terminal-line">
@@ -902,6 +902,47 @@ gitingest --repository user/repo --show-structure</code></pre>
902
902
  <div class="container">
903
903
  <h2>Changelog</h2>
904
904
  <div class="timeline">
905
+ <div class="timeline-item">
906
+ <div class="timeline-date">
907
+ <span class="timeline-month">Jun</span>
908
+ <span class="timeline-day">04</span>
909
+ </div>
910
+ <div class="timeline-content">
911
+ <h3 class="timeline-version">v0.7.0</h3>
912
+ <p class="timeline-desc">Improved file exclusion logic and debug logging.</p>
913
+ <div class="timeline-list">
914
+ <ul>
915
+ <li>Improved file exclusion logic for glob patterns to correctly match files at any
916
+ directory depth (e.g., <code>*.md</code> now correctly matches
917
+ <code>docs/file.md</code>).
918
+ </li>
919
+ <li>Refined internal handling of exclusion patterns for clarity and robustness, using
920
+ <code>File.fnmatch</code> for all custom glob patterns.
921
+ </li>
922
+ <li>Enhanced debug logging for file exclusion to show the specific pattern that caused a
923
+ match.</li>
924
+ </ul>
925
+ </div>
926
+ </div>
927
+ </div>
928
+ <div class="timeline-item">
929
+ <div class="timeline-date">
930
+ <span class="timeline-month">Apr</span>
931
+ <span class="timeline-day">14</span>
932
+ </div>
933
+ <div class="timeline-content">
934
+ <h3 class="timeline-version">v0.6.3</h3>
935
+ <p class="timeline-desc">Fixed directory exclusion pattern to properly handle paths ending with
936
+ slash.</p>
937
+ <div class="timeline-list">
938
+ <ul>
939
+ <li>Enhanced file exclusion logic to correctly filter directories when patterns end with
940
+ '/'</li>
941
+ <li>Improved spec test coverage for directory exclusion patterns</li>
942
+ </ul>
943
+ </div>
944
+ </div>
945
+ </div>
905
946
  <div class="timeline-item">
906
947
  <div class="timeline-date">
907
948
  <span class="timeline-month">Apr</span>
@@ -958,7 +999,7 @@ gitingest --repository user/repo --show-structure</code></pre>
958
999
  <div class="timeline-item">
959
1000
  <div class="timeline-date">
960
1001
  <span class="timeline-month">Mar</span>
961
- <span class="timeline-day">04</span>
1002
+ <span class="timeline-day">10</span> <!-- Corrected day based on CHANGELOG.md -->
962
1003
  </div>
963
1004
  <div class="timeline-content">
964
1005
  <h3 class="timeline-version">v0.5.0</h3>
@@ -976,7 +1017,7 @@ gitingest --repository user/repo --show-structure</code></pre>
976
1017
  <div class="timeline-item">
977
1018
  <div class="timeline-date">
978
1019
  <span class="timeline-month">Mar</span>
979
- <span class="timeline-day">04</span>
1020
+ <span class="timeline-day">03</span> <!-- Corrected day based on CHANGELOG.md -->
980
1021
  </div>
981
1022
  <div class="timeline-content">
982
1023
  <h3 class="timeline-version">v0.4.0</h3>
@@ -1011,6 +1052,7 @@ gitingest --repository user/repo --show-structure</code></pre>
1011
1052
  </div>
1012
1053
  </div>
1013
1054
  </div>
1055
+ </div>
1014
1056
  </section>
1015
1057
 
1016
1058
  <footer class="footer">
@@ -86,10 +86,12 @@ module Gitingest
86
86
  def initialize(options = {})
87
87
  @options = options
88
88
  @repo_files = []
89
- @excluded_patterns = []
89
+ # @excluded_patterns = [] # This will be set after validate_options
90
90
  setup_logger
91
91
  validate_options
92
92
  configure_client
93
+ # Populate @excluded_patterns with raw patterns after options are validated
94
+ @excluded_patterns = DEFAULT_EXCLUDES + @options.fetch(:exclude, [])
93
95
  compile_excluded_patterns
94
96
  end
95
97
 
@@ -150,11 +152,11 @@ module Gitingest
150
152
 
151
153
  @options[:output_file] ||= "#{@options[:repository].split("/").last}_prompt.txt"
152
154
  @options[:branch] ||= :default
153
- @options[:exclude] ||= []
155
+ @options[:exclude] ||= [] # Ensure :exclude is always an array
154
156
  @options[:threads] ||= DEFAULT_THREAD_COUNT
155
157
  @options[:thread_timeout] ||= DEFAULT_THREAD_TIMEOUT
156
158
  @options[:show_structure] ||= false
157
- @excluded_patterns = DEFAULT_EXCLUDES + @options[:exclude]
159
+ # NOTE: @excluded_patterns is set in compile_excluded_patterns based on @options[:exclude] # This comment is now incorrect / removed.
158
160
  end
159
161
 
160
162
  def configure_client
@@ -169,35 +171,25 @@ module Gitingest
169
171
 
170
172
  def compile_excluded_patterns
171
173
  @default_patterns = DEFAULT_EXCLUDES.map { |pattern| Regexp.new(pattern) }
172
- @custom_patterns = []
173
- @glob_patterns_with_char_classes = []
174
+ @custom_glob_patterns = [] # For File.fnmatch
175
+ @directory_patterns = []
174
176
 
175
- @options[:exclude].each do |glob_pattern|
176
- if glob_pattern.include?("[") && glob_pattern.include?("]")
177
- @glob_patterns_with_char_classes << glob_pattern
177
+ @options[:exclude].each do |pattern_str|
178
+ if pattern_str.end_with?("/")
179
+ @directory_patterns << pattern_str
178
180
  else
179
- @custom_patterns << Regexp.new(glob_to_regex(glob_pattern))
181
+ # All other custom excludes are treated as glob patterns.
182
+ # If the pattern does not contain a slash, prepend "**/"
183
+ # to make it match at any depth (e.g., "*.md" becomes "**/*.md").
184
+ @custom_glob_patterns << if pattern_str.include?("/")
185
+ pattern_str
186
+ else
187
+ "**/#{pattern_str}"
188
+ end
180
189
  end
181
190
  end
182
191
  end
183
192
 
184
- def glob_to_regex(pattern)
185
- result = "^"
186
- in_brackets = false
187
- pattern.each_char do |c|
188
- case c
189
- when "[" then in_brackets = true
190
- result += c
191
- when "]" then in_brackets = false
192
- result += c
193
- when "*" then result += in_brackets ? "*" : ".*"
194
- when ".", "\\", "+", "?", "|", "{", "}", "(", ")", "^", "$" then result += in_brackets ? c : "\\#{c}"
195
- else result += c
196
- end
197
- end
198
- "#{result}$"
199
- end
200
-
201
193
  def fetch_repository_contents
202
194
  @logger.info "Fetching repository: #{@options[:repository]} (branch: #{@options[:branch]})"
203
195
  validate_repository_access
@@ -239,79 +231,40 @@ module Gitingest
239
231
 
240
232
  def excluded_file?(path)
241
233
  return true if path.match?(DOT_FILE_PATTERN)
242
- return true if @default_patterns.any? { |pattern| path.match?(pattern) }
243
- return true if @custom_patterns.any? { |pattern| path.match?(pattern) }
244
-
245
- @glob_patterns_with_char_classes.any? { |glob_pattern| glob_match?(glob_pattern, path) }
246
- end
247
234
 
248
- def glob_match?(pattern, string)
249
- return true if pattern == string
250
- return false if !pattern.match?(/[*?\[]/) && pattern != string
251
-
252
- pattern_idx = 0
253
- string_idx = 0
254
-
255
- while pattern_idx < pattern.length && string_idx < string.length
256
- case pattern[pattern_idx]
257
- when "*"
258
- pattern_idx += 1 while pattern_idx + 1 < pattern.length && pattern[pattern_idx + 1] == "*"
259
- return true if pattern_idx == pattern.length - 1
260
-
261
- next_char = pattern[pattern_idx + 1]
262
- pattern_idx += 1
263
- while string_idx < string.length
264
- break if string[string_idx] == next_char || next_char == "?" ||
265
- (next_char == "[" && char_class_match?(pattern, pattern_idx, string[string_idx]))
266
-
267
- string_idx += 1
268
- end
269
- when "?" then string_idx += 1
270
- pattern_idx += 1
271
- when "["
272
- return false unless char_class_match?(pattern, pattern_idx, string[string_idx])
273
-
274
- pattern_idx += 1
275
- pattern_idx += 1 while pattern_idx < pattern.length && pattern[pattern_idx] != "]"
276
- pattern_idx += 1
277
- string_idx += 1
278
- when string[string_idx] then string_idx += 1
279
- pattern_idx += 1
280
- else return false
281
- end
235
+ # Check for directory exclusion patterns (ending with '/')
236
+ matched_dir_pattern = @directory_patterns.find { |dir_pattern| path.start_with?(dir_pattern) }
237
+ if matched_dir_pattern
238
+ @logger.debug { "Excluding #{path} (matched directory pattern: #{matched_dir_pattern})" }
239
+ return true
282
240
  end
283
241
 
284
- pattern_idx += 1 while pattern_idx < pattern.length && pattern[pattern_idx] == "*"
285
- pattern_idx == pattern.length && string_idx == string.length
286
- end
242
+ # Check default regex patterns
243
+ matched_default_pattern = @default_patterns.find { |pattern| path.match?(pattern) }
244
+ if matched_default_pattern
245
+ @logger.debug { "Excluding #{path} (matched default pattern: #{matched_default_pattern.source})" }
246
+ return true
247
+ end
287
248
 
288
- def char_class_match?(pattern, class_start_idx, char)
289
- idx = class_start_idx + 1
290
- match = false
291
- negate = pattern[idx] == "^" && (idx += 1)
292
-
293
- while idx < pattern.length && pattern[idx] != "]"
294
- if idx + 2 < pattern.length && pattern[idx + 1] == "-"
295
- range_start = pattern[idx]
296
- range_end = pattern[idx + 2]
297
- match = true if char >= range_start && char <= range_end
298
- idx += 3
299
- else
300
- match = true if pattern[idx] == char
301
- idx += 1
302
- end
303
- break if match
249
+ # Check custom glob patterns using File.fnmatch
250
+ matched_glob_pattern = @custom_glob_patterns.find do |glob_pattern|
251
+ File.fnmatch(glob_pattern, path, File::FNM_PATHNAME | File::FNM_DOTMATCH)
252
+ end
253
+ if matched_glob_pattern
254
+ @logger.debug { "Excluding #{path} (matched custom glob pattern: #{matched_glob_pattern})" }
255
+ return true
304
256
  end
305
- negate ? !match : match
257
+
258
+ false
306
259
  end
307
260
 
308
261
  def process_content_to_output(output)
309
262
  @logger.debug "Using thread pool with #{@options[:threads]} threads"
310
263
  buffer = []
311
264
  progress = ProgressIndicator.new(@repo_files.size, @logger)
312
- thread_buffers = {}
313
- mutex = Mutex.new
314
- errors = []
265
+ thread_buffers = Concurrent::Map.new # Thread-safe map for buffers
266
+ mutex = Mutex.new # Mutex for shared buffer and output operations
267
+ errors = Concurrent::Array.new # Thread-safe array for errors
315
268
  pool = Concurrent::FixedThreadPool.new(@options[:threads])
316
269
  prioritized_files = prioritize_files(@repo_files)
317
270
 
@@ -342,9 +295,10 @@ module Gitingest
342
295
  end
343
296
 
344
297
  pool.shutdown
345
- pool.wait_for_termination(@options[:thread_timeout]) || (@logger.warn "Thread pool timeout, forcing termination"
346
-
347
- pool.kill)
298
+ unless pool.wait_for_termination(@options[:thread_timeout])
299
+ @logger.warn "Thread pool did not shut down gracefully within #{@options[:thread_timeout]}s, forcing termination."
300
+ pool.kill
301
+ end
348
302
 
349
303
  mutex.synchronize do
350
304
  thread_buffers.each_value { |local_buffer| buffer.concat(local_buffer) unless local_buffer.empty? }
@@ -421,12 +375,14 @@ module Gitingest
421
375
  elapsed = now - @start_time
422
376
  progress_chars = (BAR_WIDTH * (current.to_f / @total)).round
423
377
  bar = "[#{"|" * progress_chars}#{" " * (BAR_WIDTH - progress_chars)}]"
424
- eta_string = current > 1 && percent < 100 ? " ETA: #{format_time((elapsed / current) * (@total - current))}" : ""
425
- rate = begin
426
- (current / elapsed).round(1)
427
- rescue StandardError
428
- 0
429
- end
378
+
379
+ rate = if elapsed.positive?
380
+ (current / elapsed).round(1)
381
+ else
382
+ 0 # Avoid division by zero if elapsed time is zero
383
+ end
384
+ eta_string = current.positive? && percent < 100 && rate.positive? ? " ETA: #{format_time((@total - current) / rate)}" : ""
385
+
430
386
  print "\r\e[K#{bar} #{percent}% | #{current}/#{@total} files (#{rate} files/sec)#{eta_string}"
431
387
  print "\n" if current == @total
432
388
  if (percent % 10).zero? && percent != @last_percent || current == @total
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gitingest
4
- VERSION = "0.6.2"
4
+ VERSION = "0.7.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitingest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Davide Santangelo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-11 00:00:00.000000000 Z
11
+ date: 2025-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby