fcom 0.14.0 → 0.14.2

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: 8ccd462b5eba731015724f453657a0bb8cb84e522ce79ca1160c229e0c60d98c
4
- data.tar.gz: b8dceaf22e3956c7a70792e344375f4b7dde581530f24f59fc4edb9835a89d9e
3
+ metadata.gz: 4071568074fd24d7c0a576634a4157c0435de4fd8003e06aa04ffcf638986cf6
4
+ data.tar.gz: 2a9aa2def6078ad23040f8be5b72cb8a5b847ec712487056343f555523dfce95
5
5
  SHA512:
6
- metadata.gz: eb772d1c4d3bb2d7e58d80d9da239787b9d7b0c0ddd744ef5a091315a45ad0b6e2e30b86c3f42616b7be6a590af58ebb21584b36ed22cf25f1389f97cf5efa6c
7
- data.tar.gz: 25210b7240a44a1e4598960fe8b6410a38811c58f58fa865056ae459be7839d719122711f255d67e08dcf90e2e9d3fe068216add5e702a7bff49ec7ad404de37
6
+ metadata.gz: c68874cbbfcf90422e0be737e3cef764cf6e167c9180d8fb301f99ab8fd77286bac66313d42a66d3b06cff941327447a4f21d880db939350c55bdae536243f83
7
+ data.tar.gz: 642dd889c30b45dffba2b24cd3e99f3eb91e30053997e2aa9c71441810c0f48ab4c99a55b62cecf90be64d2d6334692f1a71f422a5b186369be3a792a1813d8a
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.3.6
1
+ 3.4.1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## v0.14.2 (2025-02-14)
2
+ - When using `--debug`, print the command used to query for renames and the parsed result.
3
+ - Track renames even across bulk renames. Fixes a bug where we might fail to track back through a rename that occurred in a commit with other renames.
4
+ - Search the git renaming history of the entire repo when filtering with a directory path. Fixes a bug wherein we failed to track renames into the specified target directory.
5
+ - Search over the diff of commits at the start of a search range, using `git rev-list`. This fixes a bug wherein sometimes a change in a commit renaming a file would not be included in the results.
6
+ - Only consider renames from outside of target directory. Fixes a bug wherein some commits could appear twice in the search results (and also performance was negatively impacted).
7
+
8
+ ## v0.14.1 (2025-01-24)
9
+ - Stream results progressively. ([#757](https://github.com/davidrunger/fcom/pull/757))
10
+
1
11
  ## v0.14.0 (2024-12-10)
2
12
  - Remove upper bounds on versions for all dependencies.
3
13
 
data/Gemfile CHANGED
@@ -12,7 +12,8 @@ gemspec
12
12
  group :development, :test do
13
13
  gem 'bundler', require: false
14
14
  gem 'pry'
15
- gem 'pry-byebug'
15
+ # Go back to upstream if/when https://github.com/deivid-rodriguez/pry-byebug/pull/ 428 is merged.
16
+ gem 'pry-byebug', github: 'davidrunger/pry-byebug'
16
17
  gem 'rake', require: false
17
18
  gem 'rspec', require: false
18
19
  gem 'rubocop', require: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,15 @@
1
+ GIT
2
+ remote: https://github.com/davidrunger/pry-byebug
3
+ revision: 3ac27ef70a1b16a461db9f7572d3fe1a205effd4
4
+ specs:
5
+ pry-byebug (3.10.1)
6
+ pry (>= 0.13)
7
+ runger_byebug (>= 11.0)
8
+
1
9
  PATH
2
10
  remote: .
3
11
  specs:
4
- fcom (0.14.0)
12
+ fcom (0.14.2)
5
13
  activesupport (>= 6)
6
14
  memo_wise (>= 1.7)
7
15
  rainbow (>= 3.0)
@@ -10,7 +18,7 @@ PATH
10
18
  GEM
11
19
  remote: https://rubygems.org/
12
20
  specs:
13
- activesupport (7.2.2)
21
+ activesupport (8.0.1)
14
22
  base64
15
23
  benchmark (>= 0.3)
16
24
  bigdecimal
@@ -22,44 +30,57 @@ GEM
22
30
  minitest (>= 5.1)
23
31
  securerandom (>= 0.3)
24
32
  tzinfo (~> 2.0, >= 2.0.5)
33
+ uri (>= 0.13.1)
25
34
  ast (2.4.2)
26
35
  base64 (0.2.0)
27
36
  benchmark (0.4.0)
28
- bigdecimal (3.1.8)
29
- byebug (11.1.3)
37
+ bigdecimal (3.1.9)
30
38
  coderay (1.1.3)
31
- concurrent-ruby (1.3.4)
32
- connection_pool (2.4.1)
33
- diff-lcs (1.5.1)
39
+ concurrent-ruby (1.3.5)
40
+ connection_pool (2.5.0)
41
+ date (3.4.1)
42
+ diff-lcs (1.6.0)
34
43
  drb (2.2.1)
35
- i18n (1.14.6)
44
+ i18n (1.14.7)
36
45
  concurrent-ruby (~> 1.0)
37
- json (2.9.0)
38
- language_server-protocol (3.17.0.3)
39
- logger (1.6.2)
46
+ io-console (0.8.0)
47
+ irb (1.15.1)
48
+ pp (>= 0.6.0)
49
+ rdoc (>= 4.0.0)
50
+ reline (>= 0.4.2)
51
+ json (2.10.1)
52
+ language_server-protocol (3.17.0.4)
53
+ logger (1.6.6)
40
54
  memo_wise (1.10.0)
41
55
  method_source (1.1.0)
42
56
  minitest (5.25.4)
43
57
  parallel (1.26.3)
44
- parser (3.3.6.0)
58
+ parser (3.3.7.1)
45
59
  ast (~> 2.4.1)
46
60
  racc
47
- prism (1.2.0)
48
- pry (0.14.2)
61
+ pp (0.6.2)
62
+ prettyprint
63
+ prettyprint (0.2.0)
64
+ prism (1.3.0)
65
+ pry (0.15.2)
49
66
  coderay (~> 1.1)
50
67
  method_source (~> 1.0)
51
- pry-byebug (3.10.1)
52
- byebug (~> 11.0)
53
- pry (>= 0.13, < 0.15)
68
+ psych (5.2.3)
69
+ date
70
+ stringio
54
71
  racc (1.8.1)
55
72
  rainbow (3.1.1)
56
73
  rake (13.2.1)
57
- regexp_parser (2.9.3)
74
+ rdoc (6.12.0)
75
+ psych (>= 4.0.0)
76
+ regexp_parser (2.10.0)
77
+ reline (0.6.0)
78
+ io-console (~> 0.5)
58
79
  rspec (3.13.0)
59
80
  rspec-core (~> 3.13.0)
60
81
  rspec-expectations (~> 3.13.0)
61
82
  rspec-mocks (~> 3.13.0)
62
- rspec-core (3.13.2)
83
+ rspec-core (3.13.3)
63
84
  rspec-support (~> 3.13.0)
64
85
  rspec-expectations (3.13.3)
65
86
  diff-lcs (>= 1.2.0, < 2.0)
@@ -68,39 +89,46 @@ GEM
68
89
  diff-lcs (>= 1.2.0, < 2.0)
69
90
  rspec-support (~> 3.13.0)
70
91
  rspec-support (3.13.2)
71
- rubocop (1.66.1)
92
+ rubocop (1.71.2)
72
93
  json (~> 2.3)
73
94
  language_server-protocol (>= 3.17.0)
74
95
  parallel (~> 1.10)
75
96
  parser (>= 3.3.0.2)
76
97
  rainbow (>= 2.2.2, < 4.0)
77
- regexp_parser (>= 2.4, < 3.0)
78
- rubocop-ast (>= 1.32.2, < 2.0)
98
+ regexp_parser (>= 2.9.3, < 3.0)
99
+ rubocop-ast (>= 1.38.0, < 2.0)
79
100
  ruby-progressbar (~> 1.7)
80
- unicode-display_width (>= 2.4.0, < 3.0)
81
- rubocop-ast (1.36.2)
101
+ unicode-display_width (>= 2.4.0, < 4.0)
102
+ rubocop-ast (1.38.0)
82
103
  parser (>= 3.3.1.0)
83
- rubocop-performance (1.23.0)
104
+ rubocop-performance (1.23.1)
84
105
  rubocop (>= 1.48.1, < 2.0)
85
106
  rubocop-ast (>= 1.31.1, < 2.0)
86
107
  rubocop-rake (0.6.0)
87
108
  rubocop (~> 1.0)
88
- rubocop-rspec (3.2.0)
109
+ rubocop-rspec (3.4.0)
89
110
  rubocop (~> 1.61)
90
111
  ruby-progressbar (1.13.0)
91
- runger_release_assistant (0.12.0)
92
- activesupport (>= 6, < 8)
93
- memo_wise (>= 1.7, < 2)
94
- rainbow (>= 3.0, < 4)
112
+ runger_byebug (11.4.0)
113
+ irb
114
+ reline
115
+ runger_release_assistant (2.0.0)
116
+ activesupport (>= 6)
117
+ memo_wise (>= 1.7)
118
+ rainbow (>= 3.0)
95
119
  slop (~> 4.8)
96
- runger_style (2.17.0)
120
+ runger_style (5.1.0)
97
121
  prism (>= 0.24.0)
98
- rubocop (>= 1.38.0, < 2)
99
- securerandom (0.4.0)
122
+ rubocop (>= 1.68.0)
123
+ securerandom (0.4.1)
100
124
  slop (4.10.1)
125
+ stringio (3.1.2)
101
126
  tzinfo (2.0.6)
102
127
  concurrent-ruby (~> 1.0)
103
- unicode-display_width (2.6.0)
128
+ unicode-display_width (3.1.4)
129
+ unicode-emoji (~> 4.0, >= 4.0.4)
130
+ unicode-emoji (4.0.4)
131
+ uri (1.0.2)
104
132
 
105
133
  PLATFORMS
106
134
  ruby
@@ -109,7 +137,7 @@ DEPENDENCIES
109
137
  bundler
110
138
  fcom!
111
139
  pry
112
- pry-byebug
140
+ pry-byebug!
113
141
  rake
114
142
  rspec
115
143
  rubocop
@@ -119,8 +147,66 @@ DEPENDENCIES
119
147
  runger_release_assistant
120
148
  runger_style
121
149
 
150
+ CHECKSUMS
151
+ activesupport (8.0.1) sha256=fd5bc74641c24ac3541055c2879789198ff42adee3e39c2933289ba008912e37
152
+ ast (2.4.2) sha256=1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12
153
+ base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507
154
+ benchmark (0.4.0) sha256=0f12f8c495545e3710c3e4f0480f63f06b4c842cc94cec7f33a956f5180e874a
155
+ bigdecimal (3.1.9) sha256=2ffc742031521ad69c2dfc815a98e426a230a3d22aeac1995826a75dabfad8cc
156
+ coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b
157
+ concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6
158
+ connection_pool (2.5.0) sha256=233b92f8d38e038c1349ccea65dd3772727d669d6d2e71f9897c8bf5cd53ebfc
159
+ date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f
160
+ diff-lcs (1.6.0) sha256=a1e7f7b272962f8fc769358ad00001b87cdcf32ba349d6c70c6b544613d2da2e
161
+ drb (2.2.1) sha256=e9d472bf785f558b96b25358bae115646da0dbfd45107ad858b0bc0d935cb340
162
+ fcom (0.14.2)
163
+ i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f
164
+ io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2
165
+ irb (1.15.1) sha256=d9bca745ac4207a8b728a52b98b766ca909b86ff1a504bcde3d6f8c84faae890
166
+ json (2.10.1) sha256=ddc88ad91a1baf3f0038c174f253af3b086d30dc74db17ca4259bbde982f94dc
167
+ language_server-protocol (3.17.0.4) sha256=c484626478664fd13482d8180947c50a8590484b1258b99b7aedb3b69df89669
168
+ logger (1.6.6) sha256=dd618d24e637715472732e7eed02e33cfbdf56deaad225edd0f1f89d38024017
169
+ memo_wise (1.10.0) sha256=ae40ff8e7799697ff5d59d739b8766f76be22eba69c7c8468edb42ab83c94c3f
170
+ method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
171
+ minitest (5.25.4) sha256=9cf2cae25ac4dfc90c988ebc3b917f53c054978b673273da1bd20bcb0778f947
172
+ parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef
173
+ parser (3.3.7.1) sha256=7dbe61618025519024ac72402a6677ead02099587a5538e84371b76659e6aca1
174
+ pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff
175
+ prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
176
+ prism (1.3.0) sha256=b11620829831b1cb7e6c9b46c81ff8a6e36ccb3f888f164485eb7351f386273a
177
+ pry (0.15.2) sha256=12d54b8640d3fa29c9211dd4ffb08f3fd8bf7a4fd9b5a73ce5b59c8709385b6b
178
+ pry-byebug (3.10.1)
179
+ psych (5.2.3) sha256=84a54bb952d14604fea22d99938348814678782f58b12648fcdfa4d2fce859ee
180
+ racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
181
+ rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
182
+ rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
183
+ rdoc (6.12.0) sha256=7d6f706e070bffa5d18a448f24076cbfb34923a99c1eab842aa18e6ca69f56e0
184
+ regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61
185
+ reline (0.6.0) sha256=57620375dcbe56ec09bac7192bfb7460c716bbf0054dc94345ecaa5438e539d2
186
+ rspec (3.13.0) sha256=d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993
187
+ rspec-core (3.13.3) sha256=25136507f4f9cf2e8977a2851e64e438b4331646054e345998714108745cdfe4
188
+ rspec-expectations (3.13.3) sha256=0e6b5af59b900147698ea0ff80456c4f2e69cac4394fbd392fbd1ca561f66c58
189
+ rspec-mocks (3.13.2) sha256=2327335def0e1665325a9b617e3af9ae20272741d80ac550336309a7c59abdef
190
+ rspec-support (3.13.2) sha256=cea3a2463fd9b84b9dcc9685efd80ea701aa8f7b3decb3b3ce795ed67737dbec
191
+ rubocop (1.71.2) sha256=9a7b7501aac661a338ed7ff2a5eba78e581759e1f0d3c82362b2ca217ed3f97f
192
+ rubocop-ast (1.38.0) sha256=4fdf6792fe443a9a18acb12dbc8225d0d64cd1654e41fedb30e79c18edbb26ae
193
+ rubocop-performance (1.23.1) sha256=f22f86a795f5e6a6180aac2c6fc172534b173a068d6ed3396d6460523e051b82
194
+ rubocop-rake (0.6.0) sha256=56b6f22189af4b33d4f4e490a555c09f1281b02f4d48c3a61f6e8fe5f401d8db
195
+ rubocop-rspec (3.4.0) sha256=8721c13b6a8c9530a7ac481cea9423022f946fcf72428bda8289f8b57e4d4885
196
+ ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
197
+ runger_byebug (11.4.0) sha256=569e22ba2215f57e7f69e145fcb63be401e29fcd312f7936d813e12d0c7bbee6
198
+ runger_release_assistant (2.0.0) sha256=f4f5708291eaeef1b881208f87a494877fe768739d6e96b7293fc335b28a3865
199
+ runger_style (5.1.0) sha256=2518b1f636c87889acf3539b33fea8ab0703f3adcfac814985f4f0e91d13a400
200
+ securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
201
+ slop (4.10.1) sha256=844322b5ffcf17ed4815fdb173b04a20dd82b4fd93e3744c88c8fafea696d9c7
202
+ stringio (3.1.2) sha256=204f1828f85cdb39d57cac4abc6dc44b04505a223f131587f2e20ae3729ba131
203
+ tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
204
+ unicode-display_width (3.1.4) sha256=8caf2af1c0f2f07ec89ef9e18c7d88c2790e217c482bfc78aaa65eadd5415ac1
205
+ unicode-emoji (4.0.4) sha256=2c2c4ef7f353e5809497126285a50b23056cc6e61b64433764a35eff6c36532a
206
+ uri (1.0.2) sha256=b303504ceb7e5905771fa7fa14b649652fa949df18b5880d69cfb12494791e27
207
+
122
208
  RUBY VERSION
123
- ruby 3.3.6p108
209
+ ruby 3.4.1p0
124
210
 
125
211
  BUNDLED WITH
126
- 2.5.23
212
+ 2.6.2
data/README.md CHANGED
@@ -9,6 +9,26 @@ davidrunger/fcom`, I get this output:
9
9
 
10
10
  ![](https://s3.amazonaws.com/screens.davidrunger.com/2019-12-28-20-50-09-oect2(1).png)
11
11
 
12
+ ## Table of Contents
13
+
14
+ <!--ts-->
15
+ * [Table of Contents](#table-of-contents)
16
+ * [Installation](#installation)
17
+ * [Dependencies](#dependencies)
18
+ * [Basic usage](#basic-usage)
19
+ * [Available options and examples](#available-options-and-examples)
20
+ * [The .fcom.yml config file](#the-fcomyml-config-file)
21
+ * [Example .fcom.yml config file](#example-fcomyml-config-file)
22
+ * [Performance considerations for -p/--path option](#performance-considerations-for--p--path-option)
23
+ * [Development](#development)
24
+ * [Contributing](#contributing)
25
+ * [License](#license)
26
+
27
+ <!-- Created by https://github.com/ekalinin/github-markdown-toc -->
28
+ <!-- Added by: david, at: Fri Feb 14 02:37:37 AM CST 2025 -->
29
+
30
+ <!--te-->
31
+
12
32
  ## Installation
13
33
 
14
34
  ```
@@ -27,7 +47,7 @@ This gem assumes that you have `git` and [`rg` (ripgrep)][ripgrep] installed.
27
47
  $ fcom <search string> [options]
28
48
  ```
29
49
 
30
- #### Available options and examples
50
+ ### Available options and examples
31
51
 
32
52
  After installing, execute `fcom --help` to see usage examples and available options.
33
53
 
@@ -57,7 +77,7 @@ Examples:
57
77
  -h, --help print this help information
58
78
  ```
59
79
 
60
- ## `.fcom.yml` config file
80
+ ## The `.fcom.yml` config file
61
81
  We highly recommend that you create an `.fcom.yml` file in any repository that you plan to search
62
82
  with `fcom`.
63
83
 
@@ -67,7 +87,8 @@ repo/directory.
67
87
  (You might (or might not) want to add `.fcom.yml` to your `~/.gitignore_global` file, so that this
68
88
  file is not tracked by `git`.)
69
89
 
70
- #### Example `.fcom.yml` config file
90
+ ### Example `.fcom.yml` config file
91
+
71
92
  ```yaml
72
93
  repo: githubusername/reponame
73
94
  ```
@@ -77,6 +98,14 @@ more quickly, because time will not be wasted parsing the output of `git remote
77
98
  determine the URL of the repo's remote repository (which is used to construct links to matching
78
99
  commits).
79
100
 
101
+ ## Performance considerations for `-p`/`--path` option
102
+
103
+ The performance of `fcom`'s querying and parsing of git history can significantly depend upon the `-p`/`--path` option provided (or lack thereof):
104
+
105
+ 1. **fastest:** provide a _file_ path as the `-p`/`--path` option
106
+ 2. **medium:** do not provide any `-p`/`--path` option (i.e. search the whole repository)
107
+ 3. **slowest:** provide a _subdirectory_ `-p`/`--path` option
108
+
80
109
  ## Development
81
110
 
82
111
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run
@@ -4,5 +4,6 @@ set -euo pipefail # exit on any error, don't allow undefined variables, pipes do
4
4
 
5
5
  lint gitleaks
6
6
 
7
+ background-and-notify lint newlines
7
8
  background-and-notify lint rubocop
8
9
  background-and-notify lint shellcheck
data/lib/fcom/querier.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'pp'
4
+ require 'pty'
5
+
3
6
  require_relative 'options_helpers.rb'
4
7
 
5
8
  # This class executes a system command to retrieve the git history, which is passed through `rg`
@@ -28,16 +31,27 @@ class Fcom::Querier
28
31
 
29
32
  commands =
30
33
  filename_by_most_recent_containing_commit.map do |commit, path_at_commit|
34
+ commit_without_caret = commit.first(40)
35
+
36
+ start_of_log =
37
+ filtered_renames.
38
+ drop_while { it.first != commit_without_caret }.
39
+ detect { it.last == path_at_commit }&.
40
+ first ||
41
+ first_commit_sha
42
+
31
43
  <<~COMMAND.squish
44
+ git rev-list #{start_of_log} #{commit} |
45
+
32
46
  git log
33
47
  --format="commit %s|%H|%an|%cr (%ci)"
34
48
  --patch
35
49
  --full-diff
36
50
  --topo-order
37
51
  --no-textconv
52
+ --stdin
38
53
  #{%(--author="#{author}") if author}
39
54
  #{days_limiter}
40
- #{commit}
41
55
  --
42
56
  #{path_at_commit}
43
57
  |
@@ -63,18 +77,34 @@ class Fcom::Querier
63
77
 
64
78
  commands.each do |command|
65
79
  Fcom.logger.debug("Executing command: #{command}")
66
- output = `#{command}`
67
80
 
68
- if output.empty?
69
- previous_command_generated_output = false
70
- else
71
- if previous_command_generated_output
72
- puts("\n\n") # print blank lines for spacing
73
- end
81
+ # Add spacing if needed
82
+ if previous_command_generated_output
83
+ print "\n\n"
84
+ end
85
+
86
+ PTY.spawn(command) do |stdout, _stdin, _pid|
87
+ any_bytes_seen_for_command = false
88
+
89
+ # Read first byte to detect any output
90
+ first_byte = stdout.read(1)
91
+
92
+ any_bytes_seen_for_command = true
93
+
94
+ if first_byte
95
+ previous_command_generated_output = true
74
96
 
75
- previous_command_generated_output = true
97
+ print(first_byte)
76
98
 
77
- puts(output)
99
+ # Now read the rest line by line
100
+ stdout.each_line { puts(it) }
101
+ else
102
+ previous_command_generated_output = false
103
+ end
104
+ rescue Errno::EIO
105
+ if !any_bytes_seen_for_command
106
+ previous_command_generated_output = false
107
+ end
78
108
  end
79
109
  end
80
110
  end
@@ -86,9 +116,11 @@ class Fcom::Querier
86
116
 
87
117
  memo_wise \
88
118
  def filename_by_most_recent_containing_commit
89
- {
90
- most_recent_commit_with_file => path,
91
- }.merge(renames.transform_keys { "#{_1}^" })
119
+ [
120
+ [most_recent_commit_with_file, path],
121
+ ] + filtered_renames.map do |commit, previous_name|
122
+ ["#{commit}^", previous_name]
123
+ end
92
124
  end
93
125
 
94
126
  memo_wise \
@@ -100,25 +132,59 @@ class Fcom::Querier
100
132
  end
101
133
  end
102
134
 
135
+ # rubocop:disable Metrics/CyclomaticComplexity
136
+ # rubocop:disable Metrics/PerceivedComplexity
103
137
  memo_wise \
104
- def renames
105
- if path == Fcom::ROOT_PATH
106
- {}
107
- else
108
- command =
109
- 'git log HEAD ' \
110
- "--format=%H --name-status --follow --diff-filter=R #{days_limiter} " \
111
- "-- '#{path}'"
112
-
113
- `#{command}`.
114
- split(/\n(?=[0-9a-f]{40})/).
115
- to_h do |sha_and_name_info|
116
- sha_and_name_info.
117
- match(/(?<sha>[0-9a-f]{40})\n\nR\d+\s+(?<previous_name>\S+)?/).
118
- named_captures.
119
- values_at('sha', 'previous_name')
138
+ def filtered_renames
139
+ filtered_renames =
140
+ if path == Fcom::ROOT_PATH
141
+ []
142
+ elsif path == path_for_git_log_renames_query
143
+ # (Path is a file.)
144
+ full_renames_history_for_path_for_git_log_renames_query
145
+ else
146
+ # (Path is a non-root directory.)
147
+ already_selected = Set.new
148
+ path_with_trailing_slash = File.join(path, '/').to_s
149
+
150
+ renames_landing_in_target_directory_from_outside_of_it =
151
+ full_renames_history_for_path_for_git_log_renames_query.
152
+ select do |(_commit, previous_name, new_name)|
153
+ (
154
+ !previous_name.start_with?(path_with_trailing_slash) &&
155
+ new_name.start_with?(path_with_trailing_slash) &&
156
+ !already_selected.include?(new_name)
157
+ ).tap do |is_most_recent_rename_into_target_directory|
158
+ if is_most_recent_rename_into_target_directory
159
+ already_selected << new_name
160
+ end
161
+ end
162
+ end
163
+
164
+ traced_back_renames(renames_landing_in_target_directory_from_outside_of_it.map(&:last))
165
+ end
166
+
167
+ Fcom.logger.debug(<<~LOG)
168
+ Filtered renames:
169
+ #{filtered_renames.pretty_inspect}
170
+ LOG
171
+
172
+ filtered_renames
173
+ end
174
+ # rubocop:enable Metrics/PerceivedComplexity
175
+ # rubocop:enable Metrics/CyclomaticComplexity
176
+
177
+ def traced_back_renames(new_file_names)
178
+ new_file_names_of_interest = Set.new(new_file_names)
179
+
180
+ full_renames_history_for_path_for_git_log_renames_query.
181
+ select do |(_commit, previous_name, new_name)|
182
+ new_file_names_of_interest.include?(new_name).tap do |is_rename_of_interest|
183
+ if is_rename_of_interest
184
+ new_file_names_of_interest << previous_name
185
+ end
120
186
  end
121
- end
187
+ end
122
188
  end
123
189
 
124
190
  memo_wise \
@@ -127,4 +193,49 @@ class Fcom::Querier
127
193
  "--since=#{days}.day"
128
194
  end
129
195
  end
196
+
197
+ memo_wise \
198
+ def full_renames_history_for_path_for_git_log_renames_query
199
+ command =
200
+ 'git log HEAD ' \
201
+ "--format=%H --name-status --follow --diff-filter=R #{days_limiter} " \
202
+ "-- '#{path_for_git_log_renames_query}'"
203
+
204
+ Fcom.logger.debug("Querying renames with: #{command}")
205
+
206
+ `#{command}`.
207
+ split(/\n(?=[0-9a-f]{40})/).
208
+ flat_map do |sha_and_rename_info_lines|
209
+ sha, rename_info_lines =
210
+ sha_and_rename_info_lines.
211
+ match(/(?<sha>[0-9a-f]{40})\n\n(?<rename_info_lines>R\d+.*)/m).
212
+ named_captures.
213
+ values_at('sha', 'rename_info_lines')
214
+
215
+ rename_info_lines.lines.map do |rename_info_line|
216
+ previous_name, new_name =
217
+ rename_info_line.
218
+ match(/\AR\d+\s+(?<previous_name>\S+)\s+(?<new_name>\S+)/).
219
+ named_captures.
220
+ values_at('previous_name', 'new_name')
221
+
222
+ [sha, previous_name, new_name]
223
+ end
224
+ end.tap do |renames|
225
+ Fcom.logger.debug(<<~LOG)
226
+ Full renames history for '#{path_for_git_log_renames_query}':
227
+ #{renames.pretty_inspect}
228
+ LOG
229
+ end
230
+ end
231
+
232
+ memo_wise \
233
+ def path_for_git_log_renames_query
234
+ File.directory?(path) ? Fcom::ROOT_PATH : path
235
+ end
236
+
237
+ memo_wise \
238
+ def first_commit_sha
239
+ `git rev-list --max-parents=0 HEAD`.rstrip
240
+ end
130
241
  end
data/lib/fcom/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  # rubocop:disable Style/StaticClass
4
4
  class Fcom
5
- VERSION = '0.14.0'
5
+ VERSION = '0.14.2'
6
6
  end
7
7
  # rubocop:enable Style/StaticClass
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fcom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.14.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Runger
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-12-11 00:00:00.000000000 Z
10
+ date: 2025-02-14 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -66,7 +65,6 @@ dependencies:
66
65
  - - "~>"
67
66
  - !ruby/object:Gem::Version
68
67
  version: '4.8'
69
- description:
70
68
  email:
71
69
  - davidjrunger@gmail.com
72
70
  executables:
@@ -114,7 +112,6 @@ metadata:
114
112
  homepage_uri: https://github.com/davidrunger/fcom
115
113
  source_code_uri: https://github.com/davidrunger/fcom
116
114
  changelog_uri: https://github.com/davidrunger/fcom/blob/main/CHANGELOG.md
117
- post_install_message:
118
115
  rdoc_options: []
119
116
  require_paths:
120
117
  - lib
@@ -122,15 +119,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
119
  requirements:
123
120
  - - ">="
124
121
  - !ruby/object:Gem::Version
125
- version: 3.3.0
122
+ version: 3.4.0
126
123
  required_rubygems_version: !ruby/object:Gem::Requirement
127
124
  requirements:
128
125
  - - ">="
129
126
  - !ruby/object:Gem::Version
130
127
  version: '0'
131
128
  requirements: []
132
- rubygems_version: 3.5.23
133
- signing_key:
129
+ rubygems_version: 3.6.2
134
130
  specification_version: 4
135
131
  summary: CLI tool for parsing git history
136
132
  test_files: []