git_ls 0.4.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ef6ee0fb0ab70df2190d65de7389011c84036fff2993ebf65d90913746f7ff3
4
- data.tar.gz: 25c8eb1f6d58e830311b531f3aedb5f5302801bec42aded9e3df8d8e06f938a1
3
+ metadata.gz: 723546fbde74cd69c51631aafbb7fee4b4dbe12915f969855dcc6d1b577834bf
4
+ data.tar.gz: 3b9d5b1c58209e1a799864a71a875b059eef1e315c53e56351c44026f4c07931
5
5
  SHA512:
6
- metadata.gz: 31f293dba3526adcad121f36dd7afe09ca114a559581566e25ea6f60b071c566f29840aa2be46b61f6c3291f3da896b81f9b199e341ea535bb25695ae67381e8
7
- data.tar.gz: 79401fdfd2f6ac2497f3554ceff5d27b9e690f31e2395dbf84a429f4ae8b2c257cd3c6a4cff35f3f5768f662566951edb1e28f59b8efe4abeb22f4ca9569b922
6
+ metadata.gz: a4d9fb5d7c4f84057007dbc9052c011f165e191c0c7e4bfc533cf9319ce61f8103d65b936abc884e44fd1ecae666d665c160f9ab39a2f35ec1f115a871a8fd9c
7
+ data.tar.gz: 71a87a2b4946e2a499dba2c673507951a95eb4fb8a499f3737d037ed428121314d2c5e7fef0356bc8ea7070f4877e69f6b0ed13bd4cffaecacd8a0b757b26d56
@@ -0,0 +1,82 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+
11
+ jobs:
12
+ rspec:
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ ruby: [2.4, 2.5, 2.6, 2.7, '3.0', 3.1, 3.2, 3.3, 3.4, ruby-head, jruby, jruby-head]
17
+ continue-on-error: ${{ endsWith(matrix.ruby, 'head') }}
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby }}
24
+ bundler-cache: true
25
+ - run: bundle exec rspec
26
+
27
+ coverage:
28
+ runs-on: ubuntu-latest
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: ruby/setup-ruby@v1
32
+ with:
33
+ ruby-version: 3.4
34
+ bundler-cache: true
35
+ - run: COVERAGE=1 bundle exec rspec
36
+
37
+ - uses: actions/upload-artifact@v4
38
+ with:
39
+ name: coverage-report
40
+ path: 'coverage/*'
41
+ retention-days: 1
42
+ if: ${{ failure() }}
43
+
44
+ rubocop:
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+ - uses: ruby/setup-ruby@v1
49
+ with:
50
+ ruby-version: 3.4
51
+ bundler-cache: true
52
+ - run: bundle exec rubocop
53
+
54
+ spellr:
55
+ runs-on: ubuntu-latest
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+ - uses: ruby/setup-ruby@v1
59
+ with:
60
+ ruby-version: 3.4
61
+ bundler-cache: true
62
+ - run: bundle exec spellr
63
+
64
+ leftovers:
65
+ runs-on: ubuntu-latest
66
+ steps:
67
+ - uses: actions/checkout@v4
68
+ - uses: ruby/setup-ruby@v1
69
+ with:
70
+ ruby-version: 3.4
71
+ bundler-cache: true
72
+ - run: bundle exec leftovers
73
+
74
+ build:
75
+ runs-on: ubuntu-latest
76
+ steps:
77
+ - uses: actions/checkout@v4
78
+ - uses: ruby/setup-ruby@v1
79
+ with:
80
+ ruby-version: 3.4
81
+ bundler-cache: true
82
+ - run: bundle exec rake build
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  /.rspec_status
12
12
  /.ruby-version
13
13
  Gemfile.lock
14
+ /sorbet/rbi/hidden-definitions/errors.txt
data/.leftovers.yml CHANGED
@@ -1,2 +1,3 @@
1
1
  exclude_paths:
2
2
  - vendor
3
+ - sorbet
data/.rubocop.yml CHANGED
@@ -1,4 +1,6 @@
1
- require: rubocop-rspec
1
+ require:
2
+ - rubocop-rspec
3
+ - rubocop-rake
2
4
 
3
5
  # Reference:
4
6
  # https://rubocop.readthedocs.io/en/latest/
@@ -113,11 +115,12 @@ Metrics:
113
115
  CountComments: false
114
116
 
115
117
  Metrics/BlockLength:
116
- ExcludedMethods:
118
+ AllowedMethods:
117
119
  - configure
118
120
  - describe
119
121
  - context
120
122
  - shared_examples
123
+ - benchmark
121
124
 
122
125
  Metrics/CyclomaticComplexity:
123
126
  Enabled: false
@@ -125,6 +128,9 @@ Metrics/CyclomaticComplexity:
125
128
  Metrics/PerceivedComplexity:
126
129
  Enabled: false
127
130
 
131
+ Metrics/ClassLength:
132
+ Enabled: false
133
+
128
134
  RSpec:
129
135
  Enabled: true
130
136
  Include:
@@ -140,7 +146,7 @@ RSpec/ExampleLength:
140
146
  RSpec/ExpectActual:
141
147
  Enabled: false
142
148
 
143
- RSpec/FilePath:
149
+ RSpec/SpecFilePathFormat:
144
150
  Enabled: false
145
151
 
146
152
  # Multiple expectations are useful
@@ -224,3 +230,20 @@ Style/HashTransformValues:
224
230
 
225
231
  Style/CommentedKeyword:
226
232
  Enabled: false
233
+
234
+ Style/CaseLikeIf:
235
+ Enabled: false
236
+
237
+ Style/NumericPredicate:
238
+ Enabled: false
239
+
240
+ Style/Semicolon:
241
+ Exclude:
242
+ - bin/benchmark
243
+
244
+ Naming/VariableNumber:
245
+ Enabled: false
246
+
247
+ Lint/Void:
248
+ Exclude:
249
+ - bin/benchmark
data/.simplecov CHANGED
@@ -8,4 +8,8 @@ SimpleCov.start do
8
8
  else
9
9
  minimum_coverage 100
10
10
  end
11
+ self.formatter = SimpleCov::Formatter::MultiFormatter.new([
12
+ SimpleCov::Formatter::HTMLFormatter,
13
+ SimpleCov::Formatter::Console
14
+ ])
11
15
  end
data/.spellr.yml CHANGED
@@ -1,2 +1,3 @@
1
1
  excludes:
2
2
  - vendor
3
+ - sorbet
@@ -1,4 +1,5 @@
1
1
  baz
2
+ bitshift
2
3
  changelog
3
4
  codebase
4
5
  cov
@@ -20,6 +21,7 @@ params
20
21
  pwd
21
22
  quotepath
22
23
  rdoc
24
+ readme
23
25
  rspec
24
26
  rubo
25
27
  rubocop
@@ -27,7 +29,11 @@ rvm
27
29
  sharedindex
28
30
  sherson
29
31
  simplecov
32
+ srb
30
33
  sudo
31
34
  tmp
35
+ txt
32
36
  usr
37
+ utf
38
+ warmup
33
39
  yardoc
@@ -1,2 +1,4 @@
1
1
  ewah
2
+ ips
2
3
  untr
4
+ webpack
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # 0.5.1
2
+ - Test with new ruby versions, meaningless performance tweak using bitshift instead of exponent in one place.
3
+
4
+ # 0.5.0
5
+ - Major Performance Improvements
6
+
1
7
  # 0.4.0
2
8
  - Handles split index files
3
9
 
data/Gemfile CHANGED
@@ -5,5 +5,20 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in git_index.gemspec
6
6
  gemspec
7
7
 
8
- gem 'rake', '>= 12.3.3'
9
- gem 'rspec', '~> 3.0'
8
+ group(:development) do
9
+ gem 'benchmark', require: false
10
+ gem 'benchmark-ips', require: false
11
+ gem 'bundler', '>= 2', require: false
12
+ gem 'fast_ignore', '>= 0.15.1', require: false
13
+ gem 'leftovers', '>= 0.4.0', require: false
14
+ gem 'pry', require: false
15
+ gem 'rake', '>= 12.3.3', require: false
16
+ gem 'rspec', require: false
17
+ gem 'rubocop', '>= 0.93.1', require: false
18
+ gem 'rubocop-performance', '>= 1.8.1', require: false
19
+ gem 'rubocop-rake', require: false
20
+ gem 'rubocop-rspec', '>= 1.44.1', require: false
21
+ gem 'simplecov', '>= 0.18.5', require: false
22
+ gem 'simplecov-console', require: false
23
+ gem 'spellr', require: false, platforms: :ruby
24
+ end
data/README.md CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  Parses the .git/index file like `git ls-files` does.
4
4
 
5
- - for small repos (as in, anything smaller than rails),
6
- it can be faster than doing the system call to git
7
- - still takes less than half a second for very large repos e.g. the linux repo
5
+ - faster than doing the system call to git
8
6
  - doesn't require git to be installed
7
+ - tested against ruby 2.4 - 3.4.1 and jruby
9
8
 
10
9
  ## Installation
11
10
 
@@ -23,23 +22,30 @@ Or install it yourself as:
23
22
 
24
23
  $ gem install git_ls
25
24
 
25
+ And require
26
+ ```ruby
27
+ require 'git_ls'
28
+ ```
29
+
26
30
  ## Usage
27
31
 
28
- `GitLS.files` returns an array of filenames, equivalent to `` `git ls-files -z`.split("\0") ``
32
+ `GitLS.files` reads the `.git/index` file to return an array of file paths, equivalent to `` `git ls-files`.split("\n") ``, but faster, and without requiring git being installed.
33
+
29
34
  `GitLS.files("path/to/repo")` if the repo is not $PWD.
30
35
 
36
+ Strictly speaking it's equivalent to `` `git ls-files -c core.quotepath=off -z`.split("\0") ``, handling file paths with spaces and non-ascii characters, and returning file paths as UTF-8 strings.
37
+
31
38
  ## Development
32
39
 
33
- Have a look in the bin dir for some useful tools.
34
- To install this gem onto your local machine, run `bundle exec rake install`.
40
+ - Have a look in the bin dir for some useful tools.
41
+ - To install this gem onto your local machine, run `bundle exec rake install`.
42
+ - Run `rake` to run all tests & linters.
35
43
 
36
44
  ## Contributing
37
45
 
38
46
  Bug reports and pull requests are welcome on GitHub at https://github.com/robotdana/git_ls.
39
47
  If you're comfortable, please attach `.git/index` (and `.git/sharedindex.<sha>` if applicable) and the output of `git ls-files` where it doesn't match.
40
48
 
41
-
42
49
  ## License
43
50
 
44
51
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
45
- # git_ls
data/Rakefile CHANGED
@@ -1,18 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'bundler/setup'
3
4
  require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
- require 'rubocop/rake_task'
6
- require 'spellr/rake_task'
7
- require 'leftovers/rake_task'
8
5
 
9
- RuboCop::RakeTask.new
6
+ require 'rspec/core/rake_task'
10
7
  RSpec::Core::RakeTask.new(:spec)
11
- Spellr::RakeTask.generate_task
12
- Leftovers::RakeTask.generate_task
8
+ linters = %i{spec}
9
+
10
+ if RUBY_PLATFORM != 'java'
11
+ require 'rubocop/rake_task'
12
+ RuboCop::RakeTask.new
13
+ linters << :rubocop
13
14
 
14
- if RUBY_PLATFORM == 'java'
15
- task default: %i{spec build}
16
- else
17
- task default: %i{spec rubocop spellr leftovers build}
15
+ require 'spellr/rake_task'
16
+ Spellr::RakeTask.generate_task
17
+ linters << :spellr
18
+
19
+ require 'leftovers/rake_task'
20
+ Leftovers::RakeTask.generate_task
21
+ linters << :leftovers
18
22
  end
23
+
24
+ linters << :build
25
+
26
+ desc 'Run all linters'
27
+ task default: linters
data/git_index.gemspec CHANGED
@@ -26,14 +26,5 @@ Gem::Specification.new do |spec|
26
26
  end
27
27
 
28
28
  spec.require_paths = ['lib']
29
-
30
- spec.add_development_dependency 'bundler', '>= 2'
31
- spec.add_development_dependency 'leftovers'
32
- spec.add_development_dependency 'pry', '> 0'
33
- spec.add_development_dependency 'rake', '>= 12.3.3'
34
- spec.add_development_dependency 'rubocop'
35
- spec.add_development_dependency 'rubocop-performance'
36
- spec.add_development_dependency 'rubocop-rspec'
37
- spec.add_development_dependency 'simplecov', '~> 0.18.5'
38
- spec.add_development_dependency 'spellr'
29
+ spec.metadata['rubygems_mfa_required'] = 'true'
39
30
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GitLS
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.1'
5
5
  end
data/lib/git_ls.rb CHANGED
@@ -3,105 +3,105 @@
3
3
  # Usage:
4
4
  # GitLS.files -> Array of strings as files.
5
5
  # This will be identical output to git ls-files
6
+ require 'stringio'
7
+ require_relative 'git_ls/version'
8
+
6
9
  module GitLS # rubocop:disable Metrics/ModuleLength
7
10
  class Error < StandardError; end
8
11
 
9
12
  class << self
10
- def files(path = ::Dir.pwd)
11
- read(path, false)
12
- end
13
+ def files(path = nil)
14
+ path = path ? ::File.join(path, '.git/index') : '.git/index'
13
15
 
14
- def headers(path = ::Dir.pwd)
15
- read(path, true)
16
+ read(path, false)
16
17
  end
17
18
 
18
19
  private
19
20
 
20
- def read(path, return_headers_only) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
21
- path = ::File.join(path, '.git/index') if ::File.directory?(path)
22
- file = ::File.new(path)
21
+ def read(path, _return_headers_only) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
22
+ begin
23
+ # reading the whole file into memory is faster than lots of ::File#read
24
+ # the biggest it's going to be is 10s of megabytes, well within ram.
25
+ file = ::StringIO.new(::File.read(path, mode: 'rb'))
26
+ rescue ::Errno::ENOENT => e
27
+ raise ::GitLS::Error, "Not a git directory: #{e.message}"
28
+ end
29
+
23
30
  buf = ::String.new
24
31
  # 4-byte signature:
25
32
  # The signature is { 'D', 'I', 'R', 'C' } (stands for "dircache")
26
33
  # 4-byte version number:
27
34
  # The current supported versions are 2, 3 and 4.
28
35
  # 32-bit number of index entries.
29
- sig, git_index_version, length = file.read(12, buf).unpack('a4NN')
30
- raise ::GitLS::Error, ".git/index file not found at #{path}" unless sig == 'DIRC'
36
+ file.read(4, buf)
37
+ sig = buf
38
+ raise ::GitLS::Error, ".git/index file not found at '#{path}'" unless sig == 'DIRC'
39
+
40
+ file.read(4, buf)
41
+ git_index_version = buf.unpack1('N')
31
42
 
32
- return { git_index_version: git_index_version, length: length } if return_headers_only
43
+ file.read(4, buf)
44
+ entries = buf.unpack1('N')
33
45
 
34
- files = ::Array.new(length)
35
- case git_index_version
46
+ files = ::Array.new(entries)
47
+ files = case git_index_version
36
48
  when 2 then files_2(files, file)
37
49
  when 3 then files_3(files, file)
38
50
  when 4 then files_4(files, file)
39
- else raise ::GitLS::Error, 'Unrecognized git index version'
51
+ else raise ::GitLS::Error, "Unrecognized git index version '#{git_index_version}'"
40
52
  end
41
53
 
42
- extensions(files, file, buf)
43
- files
44
- rescue ::Errno::ENOENT => e
45
- raise ::GitLS::Error, "Not a git directory: #{e.message}"
46
- ensure
47
- # :nocov:
48
- # coverage tracking for branches in ensure blocks is weird
49
- file&.close
50
- # :nocov:
51
- files
54
+ read_extensions(files, file, path, buf)
52
55
  end
53
56
 
54
- def extensions(files, file, buf)
55
- case file.read(4, buf)
56
- when 'link' then link_extension(files, file, buf)
57
- when /[A-Z]{4}/ then ignored_extension(files, file, buf)
57
+ def read_extensions(files, file, path, buf) # rubocop:disable Metrics/MethodLength
58
+ extension = file.read(4, buf)
59
+ if extension == 'link'
60
+ read_link_extension(files, file, path, buf)
61
+ elsif extension.match?(/\A[A-Z]{4}\z/)
62
+ size = file.read(4, buf).unpack1('N')
63
+ file.seek(size, 1)
64
+ read_extensions(files, file, path, buf)
58
65
  else
59
- return if (file.pos += 16) && file.eof?
66
+ return files if file.seek(16, 1) && file.eof?
60
67
 
61
- raise ::GitLS::Error, "Unrecognized .git/index extension #{buf.inspect}"
68
+ raise ::GitLS::Error, "Unrecognized .git/index extension #{extension.inspect}"
62
69
  end
63
70
  end
64
71
 
65
- def ignored_extension(files, file, buf)
66
- size = file.read(4, buf).unpack1('N')
67
- file.pos += size
68
- extensions(files, file, buf)
69
- end
70
-
71
- def link_extension(files, file, buf) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
72
- file.pos += 4 # size = file.read(4, buf).unpack1('N')
72
+ def read_link_extension(files, file, path, buf) # rubocop:disable Metrics/MethodLength
73
+ file.seek(4, 1) # skip size
73
74
 
74
75
  sha = file.read(20, buf)
75
76
 
76
- new_files = files.dup
77
-
78
- files.replace files("#{::File.dirname(file.path)}/sharedindex.#{sha.unpack1('H*')}")
77
+ split_files = read("#{::File.dirname(path)}/sharedindex.#{sha.unpack1('H*')}", false)
79
78
 
80
79
  ewah_each_value(file, buf) do |pos|
81
- files[pos] = nil
80
+ split_files[pos] = nil
82
81
  end
83
82
 
84
83
  ewah_each_value(file, buf) do |pos|
85
- replacement_file = new_files.shift
84
+ replacement_file = files.shift
86
85
  # the documentation *implies* that this *may* get a new filename
87
86
  # i can't get it to happen though
88
87
  # :nocov:
89
- files[pos] = replacement_file unless replacement_file.empty?
88
+ split_files[pos] = replacement_file unless replacement_file.empty?
90
89
  # :nocov:
91
90
  end
92
91
 
93
- files.compact!
94
- files.concat(new_files)
95
- files.sort!
92
+ split_files.compact!
93
+ split_files.concat(files)
94
+ split_files.sort!
96
95
 
97
- extensions(files, file, buf)
96
+ read_extensions(split_files, file, path, buf)
98
97
  end
99
98
 
100
99
  # format is defined here:
101
100
  # https://git-scm.com/docs/bitmap-format#_appendix_a_serialization_format_for_an_ewah_bitmap
102
101
  def ewah_each_value(file, buf) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
103
102
  uncompressed_pos = 0
104
- file.pos += 4 # uncompressed_bits_count = file.read(4, buf).unpack1('N')
103
+
104
+ file.seek(4, 1) # skip 4 byte uncompressed_bits_count.
105
105
  compressed_bytes = file.read(4, buf).unpack1('N') * 8
106
106
 
107
107
  final_file_pos = file.pos + compressed_bytes
@@ -110,10 +110,10 @@ module GitLS # rubocop:disable Metrics/ModuleLength
110
110
  run_length_word = file.read(8, buf).unpack1('Q>')
111
111
  # 1st bit
112
112
  run_bit = run_length_word & 1
113
- # the next 32 bits, masked, multiplied by 64 (which is shifted by 6 places)
114
- run_length = ((run_length_word >> 1) & 0xFFFF_FFFF) << 6
113
+ # the next 32 bits, masked, multiplied by 64
114
+ run_length = ((run_length_word / 0b1_0) & 0xFFFF_FFFF) * 64
115
115
  # the next 31 bits
116
- literal_length = (run_length_word >> 33)
116
+ literal_length = (run_length_word / 0b100000000_00000000_00000000_00000000_0)
117
117
 
118
118
  if run_bit == 1
119
119
  run_length.times do
@@ -124,9 +124,12 @@ module GitLS # rubocop:disable Metrics/ModuleLength
124
124
  uncompressed_pos += run_length
125
125
  end
126
126
 
127
- literal_length.times do
128
- word = file.read(8, buf).unpack1('B*').reverse
129
- word.each_char do |char|
127
+ next unless literal_length > 0
128
+
129
+ file.read(8 * literal_length, buf)
130
+ words = buf.unpack('B64' * literal_length)
131
+ words.each do |word|
132
+ word.each_char.reverse_each do |char|
130
133
  yield(uncompressed_pos) if char == '1'
131
134
 
132
135
  uncompressed_pos += 1
@@ -134,59 +137,64 @@ module GitLS # rubocop:disable Metrics/ModuleLength
134
137
  end
135
138
  end
136
139
 
137
- file.pos += 4 # bitmap metadata for adding to bitmaps
140
+ file.seek(4, 1) # bitmap metadata for adding to bitmaps
138
141
  end
139
142
 
140
143
  def files_2(files, file) # rubocop:disable Metrics/MethodLength
141
144
  files.map! do
142
- file.pos += 60 # skip 60 bytes (40 bytes of stat, 20 bytes of sha)
143
- length = ((file.getbyte & 0b0000_1111) << 8) + file.getbyte # find the 12 byte length
145
+ file.seek(60, 1) # skip 60 bytes (40 bytes of stat, 20 bytes of sha)
146
+
147
+ length = ((file.getbyte & 0xF) * 256) + file.getbyte # find the 12 byte length
144
148
  if length < 0xFFF
145
149
  path = file.read(length)
146
150
  # :nocov:
147
151
  else
148
152
  # i can't test this i just get ENAMETOOLONG a lot
149
- path = file.readline("\0").chop
150
- file.pos -= 1
153
+ # I'm not sure it's even possible to get to this path, PATH_MAX is 4096 bytes on linux, 1024 on mac
154
+ # and length is a 12 byte number: 4096 max.
155
+ path = file.readline("\0").chop!
156
+ file.seek(-1, 1)
151
157
  # :nocov:
152
158
  end
153
- file.pos += 8 - ((length - 2) % 8) # 1-8 bytes padding of nuls
159
+ file.seek(8 - ((length - 2) % 8), 1) # 1-8 bytes padding of nuls
160
+ path.force_encoding(Encoding::UTF_8)
154
161
  path
155
162
  end
156
163
  end
157
164
 
158
165
  def files_3(files, file) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
159
166
  files.map! do
160
- file.pos += 60 # skip 60 bytes (40 bytes of stat, 20 bytes of sha)
167
+ file.seek(60, 1) # skip 60 bytes (40 bytes of stat, 20 bytes of sha)
168
+ flags = file.getbyte
169
+ extended_flag = (flags & 0b0100_0000) > 0
170
+ length = ((flags & 0xF) * 256) + file.getbyte # find the 12 byte length
171
+ file.seek(2, 1) if extended_flag
161
172
 
162
- flags = file.getbyte * 256 + file.getbyte
163
- extended_flag = (flags & 0b0100_0000_0000_0000).positive?
164
- file.pos += 2 if extended_flag
165
-
166
- length = flags & 0b0000_1111_1111_1111
167
173
  if length < 0xFFF
168
174
  path = file.read(length)
169
175
  # :nocov:
170
176
  else
171
177
  # i can't test this i just get ENAMETOOLONG a lot
172
- path = file.readline("\0").chop
173
- file.pos -= 1
178
+ # I'm not sure it's even possible to get to this path, PATH_MAX is 4096 bytes on linux, 1024 on mac
179
+ # and length is a 12 byte number: 4096 max.
180
+ path = file.readline("\0").chop!
181
+ file.seek(-1, 1)
174
182
  # :nocov:
175
183
  end
176
-
177
- file.pos += 8 - ((path.bytesize - (extended_flag ? 0 : 2)) % 8) # 1-8 bytes padding of nuls
184
+ file.seek(8 - ((path.bytesize - (extended_flag ? 0 : 2)) % 8), 1) # 1-8 bytes padding of nuls
185
+ path.force_encoding(Encoding::UTF_8)
178
186
  path
179
187
  end
180
188
  end
181
189
 
182
190
  def files_4(files, file) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
183
191
  prev_entry_path = ''
184
- files.map! do
185
- file.pos += 60 # skip 60 bytes (40 bytes of stat, 20 bytes of sha)
186
- flags = file.getbyte * 256 + file.getbyte
187
- file.pos += 2 if (flags & 0b0100_0000_0000_0000).positive?
188
-
189
- length = flags & 0b0000_1111_1111_1111
192
+ files.map! do # rubocop:disable Metrics/BlockLength
193
+ file.seek(60, 1) # skip 60 bytes (40 bytes of stat, 20 bytes of sha)
194
+ flags = file.getbyte
195
+ extended_flag = (flags & 0b0100_0000) > 0
196
+ length = ((flags & 0xF) * 256) + file.getbyte # find the 12 byte length
197
+ file.seek(2, 1) if extended_flag
190
198
 
191
199
  # documentation for this number from
192
200
  # https://git-scm.com/docs/pack-format#_original_version_1_pack_idx_files_have_the_following_format
@@ -199,9 +207,9 @@ module GitLS # rubocop:disable Metrics/ModuleLength
199
207
  read_offset = 0
200
208
  prev_read_offset = file.getbyte
201
209
  n = 1
202
- while (prev_read_offset & 0b1000_0000).positive?
203
- read_offset += (prev_read_offset - 0b1000_0000)
204
- read_offset += 2**(7 * n)
210
+ while (prev_read_offset & 0b1000_0000) > 0
211
+ read_offset += (prev_read_offset & 0b0111_1111)
212
+ read_offset += 1 << (7 * n)
205
213
  n += 1
206
214
  prev_read_offset = file.getbyte
207
215
  end
@@ -210,16 +218,21 @@ module GitLS # rubocop:disable Metrics/ModuleLength
210
218
  initial_part_length = prev_entry_path.bytesize - read_offset
211
219
 
212
220
  if length < 0xFFF
213
- rest = file.read(length - initial_part_length)
214
- file.pos += 1 # the NUL
221
+ rest = +''
222
+ file.read(length - initial_part_length, rest)
223
+ file.seek(1, 1) # the NUL
215
224
  # :nocov:
216
225
  else
217
226
  # i can't test this i just get ENAMETOOLONG a lot
218
- rest = file.readline("\0").chop
227
+ # I'm not sure it's even possible to get to this path, PATH_MAX is 4096 bytes on linux, 1024 on mac
228
+ # and length is a 12 byte number: 4096 max.
229
+ rest = file.readline("\0").chop!
230
+ file.seek(-1, 1)
219
231
  # :nocov:
220
232
  end
221
233
 
222
- prev_entry_path = prev_entry_path.byteslice(0, initial_part_length) + rest
234
+ prev_entry_path = +"#{prev_entry_path.byteslice(0, initial_part_length)}#{rest}"
235
+ prev_entry_path.force_encoding(::Encoding::UTF_8)
223
236
  end
224
237
  end
225
238
  end
metadata CHANGED
@@ -1,148 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_ls
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dana Sherson
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2020-09-05 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '2'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '2'
27
- - !ruby/object:Gem::Dependency
28
- name: leftovers
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: pry
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">"
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">"
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: rake
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: 12.3.3
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: 12.3.3
69
- - !ruby/object:Gem::Dependency
70
- name: rubocop
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rubocop-performance
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rubocop-rspec
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: simplecov
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 0.18.5
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 0.18.5
125
- - !ruby/object:Gem::Dependency
126
- name: spellr
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- description:
10
+ date: 2025-01-28 00:00:00.000000000 Z
11
+ dependencies: []
140
12
  email:
141
13
  - robot@dana.sh
142
14
  executables: []
143
15
  extensions: []
144
16
  extra_rdoc_files: []
145
17
  files:
18
+ - ".github/workflows/ci.yml"
146
19
  - ".gitignore"
147
20
  - ".leftovers.yml"
148
21
  - ".rspec"
@@ -152,7 +25,6 @@ files:
152
25
  - ".spellr_wordlists/english.txt"
153
26
  - ".spellr_wordlists/ruby.txt"
154
27
  - ".spellr_wordlists/shell.txt"
155
- - ".travis.yml"
156
28
  - CHANGELOG.md
157
29
  - Gemfile
158
30
  - LICENSE.txt
@@ -168,7 +40,7 @@ metadata:
168
40
  homepage_uri: https://github.com/robotdana/git_ls
169
41
  source_code_uri: https://github.com/robotdana/git_ls
170
42
  changelog_uri: https://github.com/robotdana/git_ls/blob/main/CHANGELOG.md
171
- post_install_message:
43
+ rubygems_mfa_required: 'true'
172
44
  rdoc_options: []
173
45
  require_paths:
174
46
  - lib
@@ -183,8 +55,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
55
  - !ruby/object:Gem::Version
184
56
  version: '0'
185
57
  requirements: []
186
- rubygems_version: 3.0.3
187
- signing_key:
58
+ rubygems_version: 3.6.2
188
59
  specification_version: 4
189
60
  summary: Read a .git/index file and list the files
190
61
  test_files: []
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.7
6
- - 2.6
7
- - 2.5
8
- - 2.4
9
- - jruby
10
- before_install: sudo apt-get install git && gem install bundler -v 2.1.4