file_tree_visualizer 0.1.0 → 0.2.1
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/README.md +69 -5
- data/file_tree_visualizer.gemspec +5 -3
- data/lib/file_tree_visualizer/cli.rb +125 -12
- data/lib/file_tree_visualizer/i18n.rb +34 -0
- data/lib/file_tree_visualizer/scanner.rb +27 -1
- data/lib/file_tree_visualizer/version.rb +1 -1
- metadata +20 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b48b5d1e8f778bbacb3fb9e05cbcbe01cc2bcfe461a9483e6a26ecee97ea61e4
|
|
4
|
+
data.tar.gz: 871f3db43591f0bed5778d21a42431a50dad4604fc559690a4fe7c469a97ed05
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eac6f7ab5f691589e622b2c595164b6b7f9043d75b5d22ea3e9aa04eba60fa8919f061ece96a824fd02e60c59dfe40f4894c61cf6a45742becc717e3b7c59f18
|
|
7
|
+
data.tar.gz: 5ec9b4396e7c5e2bdb56608091a60f0370655d1b895b15fdff0210a77fd79658ec7969545bdc27068c3a052dc44f9b01fcd3bf7a5482d2deaf69b4c060ae879f
|
data/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# file_tree_visualizer
|
|
2
2
|
|
|
3
|
+
[](https://github.com/JohnBidwellB/file-tree-visualizer/actions/workflows/release.yml)
|
|
4
|
+
[](https://rubygems.org/gems/file_tree_visualizer)
|
|
5
|
+
|
|
3
6
|
Ruby gem to scan file trees from the terminal and generate a fully offline interactive HTML report with the items that consume the most disk space.
|
|
4
7
|
|
|
5
8
|
## What it does
|
|
@@ -30,7 +33,7 @@ file-tree-visualizer /path/to/scan -o report.html
|
|
|
30
33
|
Install a specific version:
|
|
31
34
|
|
|
32
35
|
```bash
|
|
33
|
-
gem install file_tree_visualizer -v 0.1
|
|
36
|
+
gem install file_tree_visualizer -v 0.2.1
|
|
34
37
|
```
|
|
35
38
|
|
|
36
39
|
## Local development install
|
|
@@ -38,7 +41,7 @@ gem install file_tree_visualizer -v 0.1.0
|
|
|
38
41
|
```bash
|
|
39
42
|
bundle install
|
|
40
43
|
gem build file_tree_visualizer.gemspec
|
|
41
|
-
gem install ./file_tree_visualizer-0.1.
|
|
44
|
+
gem install ./file_tree_visualizer-0.2.1.gem
|
|
42
45
|
file-tree-visualizer /path/to/scan -o report.html
|
|
43
46
|
```
|
|
44
47
|
|
|
@@ -55,7 +58,12 @@ During scanning, an interactive terminal shows a progress bar with processed fil
|
|
|
55
58
|
-t, --top N Number of largest files to keep in ranking (default: 200)
|
|
56
59
|
--follow-symlinks Follow symbolic links
|
|
57
60
|
--no-progress Disable progress bar
|
|
61
|
+
--exclude PATTERNS Exclude patterns (comma-separated or repeated)
|
|
62
|
+
--summary Print summary to terminal
|
|
63
|
+
--json FILE Export full result as JSON
|
|
64
|
+
--csv FILE Export top files as CSV
|
|
58
65
|
--lang LANG Language for CLI and report (en|es)
|
|
66
|
+
-v, --version Print version
|
|
59
67
|
-h, --help Show help
|
|
60
68
|
|
|
61
69
|
Language resolution priority:
|
|
@@ -64,12 +72,68 @@ Language resolution priority:
|
|
|
64
72
|
- fallback to English (`en`)
|
|
65
73
|
```
|
|
66
74
|
|
|
75
|
+
## Common workflows
|
|
76
|
+
|
|
77
|
+
Print current gem version:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
file-tree-visualizer --version
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Summary only (no HTML file generated unless `--output` is explicitly provided):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
file-tree-visualizer --summary
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Summary + HTML report:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
file-tree-visualizer . --summary --output report.html
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Exclude directories and files by pattern:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
file-tree-visualizer . --exclude "node_modules,.git,*.log" --exclude "tmp/**"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Export JSON and CSV in one run:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
file-tree-visualizer . --summary --json scan.json --csv top-files.csv
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Contributing
|
|
108
|
+
|
|
109
|
+
1. Create a feature branch from `main`.
|
|
110
|
+
2. Implement your change and run tests locally.
|
|
111
|
+
3. Push your branch and open a Pull Request.
|
|
112
|
+
4. Wait for CI to pass and at least one approval.
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
git checkout -b feat/short-description
|
|
116
|
+
bundle exec rake test
|
|
117
|
+
git push origin feat/short-description
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Branch policy:
|
|
121
|
+
- For collaborators, `main` is protected and requires PR + CI + approval.
|
|
122
|
+
- Repository admins can bypass these rules when needed.
|
|
123
|
+
|
|
67
124
|
## Automatic release to RubyGems
|
|
68
125
|
|
|
69
|
-
- This repository publishes the gem automatically when pushing a tag with format `v*` (for example `v0.
|
|
126
|
+
- This repository publishes the gem automatically when pushing a tag with format `v*` (for example `v0.2.1`).
|
|
70
127
|
- Before using it, configure the `RUBYGEMS_API_KEY` secret in GitHub Actions.
|
|
128
|
+
- You can also trigger the workflow manually from GitHub Actions (`workflow_dispatch`).
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
git tag v0.2.1
|
|
132
|
+
git push origin v0.2.1
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Reusable release notes template:
|
|
71
136
|
|
|
72
137
|
```bash
|
|
73
|
-
|
|
74
|
-
git push origin v0.0.4
|
|
138
|
+
gh release create v0.2.1 --title "v0.2.1" --notes-file .github/release-template.md
|
|
75
139
|
```
|
|
@@ -5,8 +5,8 @@ require_relative 'lib/file_tree_visualizer/version'
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = 'file_tree_visualizer'
|
|
7
7
|
spec.version = FileTreeVisualizer::VERSION
|
|
8
|
-
spec.authors = ['
|
|
9
|
-
spec.email = ['
|
|
8
|
+
spec.authors = ['John Bidwell']
|
|
9
|
+
spec.email = ['johnbidwellb@gmail.com']
|
|
10
10
|
|
|
11
11
|
spec.summary = 'CLI Ruby tool to analyze file sizes and generate an interactive HTML report.'
|
|
12
12
|
spec.description = 'Scans a directory recursively, computes file/directory sizes, and generates an HTML report rendered with React.'
|
|
@@ -14,7 +14,8 @@ Gem::Specification.new do |spec|
|
|
|
14
14
|
spec.license = 'MIT'
|
|
15
15
|
spec.required_ruby_version = '>= 2.7'
|
|
16
16
|
|
|
17
|
-
spec.metadata['source_code_uri'] = spec.homepage
|
|
17
|
+
spec.metadata['source_code_uri'] = "#{spec.homepage}/tree/main"
|
|
18
|
+
spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"
|
|
18
19
|
spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
19
20
|
|
|
20
21
|
spec.files = Dir.chdir(__dir__) do
|
|
@@ -30,4 +31,5 @@ Gem::Specification.new do |spec|
|
|
|
30
31
|
spec.bindir = 'bin'
|
|
31
32
|
spec.executables = ['file-tree-visualizer']
|
|
32
33
|
spec.require_paths = ['lib']
|
|
34
|
+
spec.add_dependency 'csv', '~> 3.3'
|
|
33
35
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'optparse'
|
|
4
|
+
require 'csv'
|
|
5
|
+
require 'json'
|
|
4
6
|
|
|
5
7
|
module FileTreeVisualizer
|
|
6
8
|
class CLI
|
|
@@ -13,6 +15,11 @@ module FileTreeVisualizer
|
|
|
13
15
|
|
|
14
16
|
def run
|
|
15
17
|
options, parser, locale = parse_options(@argv.dup)
|
|
18
|
+
if options[:version]
|
|
19
|
+
puts FileTreeVisualizer::VERSION
|
|
20
|
+
return 0
|
|
21
|
+
end
|
|
22
|
+
|
|
16
23
|
if options[:help]
|
|
17
24
|
puts parser
|
|
18
25
|
return 0
|
|
@@ -24,22 +31,30 @@ module FileTreeVisualizer
|
|
|
24
31
|
t(locale, 'cli.errors.invalid_directory', path: expanded_path)
|
|
25
32
|
end
|
|
26
33
|
|
|
27
|
-
scanner = Scanner.new(
|
|
34
|
+
scanner = Scanner.new(
|
|
35
|
+
top_limit: options[:top],
|
|
36
|
+
follow_symlinks: options[:follow_symlinks],
|
|
37
|
+
excludes: options[:exclude_patterns]
|
|
38
|
+
)
|
|
28
39
|
progress = ProgressRenderer.new(enabled: options[:progress], locale: locale)
|
|
29
40
|
callback = options[:progress] ? progress.method(:render) : nil
|
|
30
41
|
result = scanner.scan(expanded_path, progress: callback)
|
|
31
42
|
progress.finish
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
puts t(locale, 'cli.messages.report_generated', path: output_path)
|
|
38
|
-
puts t(locale, 'cli.messages.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
generated_at = Time.now.utc
|
|
44
|
+
output_path = maybe_write_report(options, expanded_path, result, locale, generated_at)
|
|
45
|
+
json_path = write_json_export(options[:json_output], expanded_path, result, locale, generated_at)
|
|
46
|
+
csv_path = write_csv_export(options[:csv_output], result)
|
|
47
|
+
print_summary(expanded_path, result, locale) if options[:summary]
|
|
48
|
+
puts t(locale, 'cli.messages.report_generated', path: output_path) if output_path
|
|
49
|
+
puts t(locale, 'cli.messages.json_generated', path: json_path) if json_path
|
|
50
|
+
puts t(locale, 'cli.messages.csv_generated', path: csv_path) if csv_path
|
|
51
|
+
unless options[:summary]
|
|
52
|
+
puts t(locale, 'cli.messages.scanned',
|
|
53
|
+
directories: result.stats[:directories],
|
|
54
|
+
files: result.stats[:files],
|
|
55
|
+
skipped: result.stats[:skipped])
|
|
56
|
+
end
|
|
57
|
+
puts t(locale, 'cli.messages.total_size', size: format_bytes(result.stats[:bytes])) unless options[:summary]
|
|
43
58
|
0
|
|
44
59
|
rescue OptionParser::ParseError, ArgumentError => e
|
|
45
60
|
locale = error_locale
|
|
@@ -133,7 +148,13 @@ module FileTreeVisualizer
|
|
|
133
148
|
top: Scanner::DEFAULT_TOP_LIMIT,
|
|
134
149
|
follow_symlinks: false,
|
|
135
150
|
progress: true,
|
|
151
|
+
summary: false,
|
|
152
|
+
output_given: false,
|
|
153
|
+
json_output: nil,
|
|
154
|
+
csv_output: nil,
|
|
155
|
+
exclude_patterns: [],
|
|
136
156
|
lang: nil,
|
|
157
|
+
version: false,
|
|
137
158
|
help: false
|
|
138
159
|
}
|
|
139
160
|
|
|
@@ -164,6 +185,7 @@ module FileTreeVisualizer
|
|
|
164
185
|
|
|
165
186
|
opts.on('-o', '--output FILE', t(locale, 'cli.output_option', default: DEFAULT_OUTPUT)) do |value|
|
|
166
187
|
options[:output] = value
|
|
188
|
+
options[:output_given] = true
|
|
167
189
|
end
|
|
168
190
|
|
|
169
191
|
opts.on('-t', '--top N', Integer, t(locale, 'cli.top_option', default: Scanner::DEFAULT_TOP_LIMIT)) do |value|
|
|
@@ -178,10 +200,30 @@ module FileTreeVisualizer
|
|
|
178
200
|
options[:progress] = false
|
|
179
201
|
end
|
|
180
202
|
|
|
203
|
+
opts.on('--exclude PATTERNS', t(locale, 'cli.exclude_option')) do |value|
|
|
204
|
+
options[:exclude_patterns].concat(split_patterns(value))
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
opts.on('--summary', t(locale, 'cli.summary_option')) do
|
|
208
|
+
options[:summary] = true
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
opts.on('--json FILE', t(locale, 'cli.json_option')) do |value|
|
|
212
|
+
options[:json_output] = value
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
opts.on('--csv FILE', t(locale, 'cli.csv_option')) do |value|
|
|
216
|
+
options[:csv_output] = value
|
|
217
|
+
end
|
|
218
|
+
|
|
181
219
|
opts.on('--lang LANG', t(locale, 'cli.lang_option')) do |value|
|
|
182
220
|
options[:lang] = value
|
|
183
221
|
end
|
|
184
222
|
|
|
223
|
+
opts.on('-v', '--version', t(locale, 'cli.version_option')) do
|
|
224
|
+
options[:version] = true
|
|
225
|
+
end
|
|
226
|
+
|
|
185
227
|
opts.on('-h', '--help', t(locale, 'cli.help_option')) do
|
|
186
228
|
options[:help] = true
|
|
187
229
|
end
|
|
@@ -198,6 +240,10 @@ module FileTreeVisualizer
|
|
|
198
240
|
nil
|
|
199
241
|
end
|
|
200
242
|
|
|
243
|
+
def split_patterns(value)
|
|
244
|
+
value.to_s.split(',').map(&:strip).reject(&:empty?)
|
|
245
|
+
end
|
|
246
|
+
|
|
201
247
|
def t(locale, key, **vars)
|
|
202
248
|
I18n.t(locale, key, **vars)
|
|
203
249
|
end
|
|
@@ -221,5 +267,72 @@ module FileTreeVisualizer
|
|
|
221
267
|
precision = value < 10 ? 2 : 1
|
|
222
268
|
format("%.#{precision}f %s", value, units[unit_index])
|
|
223
269
|
end
|
|
270
|
+
|
|
271
|
+
def maybe_write_report(options, source_path, result, locale, generated_at)
|
|
272
|
+
should_write = !options[:summary] || options[:output_given]
|
|
273
|
+
return nil unless should_write
|
|
274
|
+
|
|
275
|
+
report = ReportBuilder.new(
|
|
276
|
+
result: result,
|
|
277
|
+
source_path: source_path,
|
|
278
|
+
locale: locale,
|
|
279
|
+
generated_at: generated_at
|
|
280
|
+
).build
|
|
281
|
+
output_path = File.expand_path(options[:output])
|
|
282
|
+
File.write(output_path, report)
|
|
283
|
+
output_path
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def write_json_export(target_path, source_path, result, locale, generated_at)
|
|
287
|
+
return nil unless target_path
|
|
288
|
+
|
|
289
|
+
output_path = File.expand_path(target_path)
|
|
290
|
+
payload = {
|
|
291
|
+
source_path: source_path,
|
|
292
|
+
generated_at: generated_at.iso8601,
|
|
293
|
+
locale: locale,
|
|
294
|
+
version: FileTreeVisualizer::VERSION,
|
|
295
|
+
stats: result.stats,
|
|
296
|
+
root: result.root,
|
|
297
|
+
top_files: result.top_files
|
|
298
|
+
}
|
|
299
|
+
File.write(output_path, JSON.pretty_generate(payload))
|
|
300
|
+
output_path
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def write_csv_export(target_path, result)
|
|
304
|
+
return nil unless target_path
|
|
305
|
+
|
|
306
|
+
output_path = File.expand_path(target_path)
|
|
307
|
+
CSV.open(output_path, 'w') do |csv|
|
|
308
|
+
csv << %w[rank path name size_bytes size_human]
|
|
309
|
+
result.top_files.each_with_index do |item, index|
|
|
310
|
+
csv << [index + 1, item[:path], item[:name], item[:size], format_bytes(item[:size])]
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
output_path
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def print_summary(source_path, result, locale)
|
|
317
|
+
puts t(locale, 'cli.summary.heading')
|
|
318
|
+
puts t(locale, 'cli.summary.source', path: source_path)
|
|
319
|
+
puts t(locale, 'cli.summary.total_size', size: format_bytes(result.stats[:bytes]))
|
|
320
|
+
puts t(locale, 'cli.summary.files', count: result.stats[:files])
|
|
321
|
+
puts t(locale, 'cli.summary.directories', count: result.stats[:directories])
|
|
322
|
+
puts t(locale, 'cli.summary.skipped', count: result.stats[:skipped])
|
|
323
|
+
puts t(locale, 'cli.summary.top_files')
|
|
324
|
+
|
|
325
|
+
if result.top_files.empty?
|
|
326
|
+
puts " #{t(locale, 'cli.summary.none')}"
|
|
327
|
+
return
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
result.top_files.each_with_index do |item, index|
|
|
331
|
+
puts format(' %<rank>d. %<size>s %<path>s',
|
|
332
|
+
rank: index + 1,
|
|
333
|
+
size: format_bytes(item[:size]),
|
|
334
|
+
path: item[:path])
|
|
335
|
+
end
|
|
336
|
+
end
|
|
224
337
|
end
|
|
225
338
|
end
|
|
@@ -13,10 +13,17 @@ module FileTreeVisualizer
|
|
|
13
13
|
'top_option' => 'Number of largest files in ranking (default: %<default>s)',
|
|
14
14
|
'follow_symlinks_option' => 'Follow symbolic links during scan',
|
|
15
15
|
'no_progress_option' => 'Disable progress bar',
|
|
16
|
+
'exclude_option' => 'Exclude patterns (comma-separated or repeated)',
|
|
17
|
+
'summary_option' => 'Print terminal summary',
|
|
18
|
+
'json_option' => 'Export scan result as JSON',
|
|
19
|
+
'csv_option' => 'Export top files as CSV',
|
|
16
20
|
'lang_option' => 'Language for CLI and report (en|es)',
|
|
21
|
+
'version_option' => 'Print version',
|
|
17
22
|
'help_option' => 'Show this help',
|
|
18
23
|
'messages' => {
|
|
19
24
|
'report_generated' => 'Report generated at: %<path>s',
|
|
25
|
+
'json_generated' => 'JSON exported at: %<path>s',
|
|
26
|
+
'csv_generated' => 'CSV exported at: %<path>s',
|
|
20
27
|
'scanned' => 'Scanned: %<directories>s directories, %<files>s files, %<skipped>s skipped.',
|
|
21
28
|
'total_size' => 'Total size: %<size>s'
|
|
22
29
|
},
|
|
@@ -30,6 +37,16 @@ module FileTreeVisualizer
|
|
|
30
37
|
'progress' => {
|
|
31
38
|
'preparing' => 'Preparing scan %<spinner>s Files:%<files>s Dirs:%<dirs>s',
|
|
32
39
|
'scanning' => 'Scanning [%<bar>s] %<percent>s%% Files:%<pf>s/%<tf>s Dirs:%<pd>s/%<td>s'
|
|
40
|
+
},
|
|
41
|
+
'summary' => {
|
|
42
|
+
'heading' => 'Summary',
|
|
43
|
+
'source' => 'Source: %<path>s',
|
|
44
|
+
'total_size' => 'Total size: %<size>s',
|
|
45
|
+
'files' => 'Files: %<count>s',
|
|
46
|
+
'directories' => 'Directories: %<count>s',
|
|
47
|
+
'skipped' => 'Skipped entries: %<count>s',
|
|
48
|
+
'top_files' => 'Top files:',
|
|
49
|
+
'none' => '(none)'
|
|
33
50
|
}
|
|
34
51
|
},
|
|
35
52
|
'report' => {
|
|
@@ -72,10 +89,17 @@ module FileTreeVisualizer
|
|
|
72
89
|
'top_option' => 'Cantidad de archivos pesados en ranking (default: %<default>s)',
|
|
73
90
|
'follow_symlinks_option' => 'Sigue enlaces simbólicos durante el escaneo',
|
|
74
91
|
'no_progress_option' => 'Desactiva la barra de progreso',
|
|
92
|
+
'exclude_option' => 'Excluye patrones (separados por coma o repetidos)',
|
|
93
|
+
'summary_option' => 'Imprime resumen en terminal',
|
|
94
|
+
'json_option' => 'Exporta resultado del escaneo como JSON',
|
|
95
|
+
'csv_option' => 'Exporta top de archivos como CSV',
|
|
75
96
|
'lang_option' => 'Idioma para CLI y reporte (en|es)',
|
|
97
|
+
'version_option' => 'Muestra version',
|
|
76
98
|
'help_option' => 'Muestra esta ayuda',
|
|
77
99
|
'messages' => {
|
|
78
100
|
'report_generated' => 'Reporte generado en: %<path>s',
|
|
101
|
+
'json_generated' => 'JSON exportado en: %<path>s',
|
|
102
|
+
'csv_generated' => 'CSV exportado en: %<path>s',
|
|
79
103
|
'scanned' => 'Escaneado: %<directories>s directorios, %<files>s archivos, %<skipped>s omitidos.',
|
|
80
104
|
'total_size' => 'Tamano total: %<size>s'
|
|
81
105
|
},
|
|
@@ -89,6 +113,16 @@ module FileTreeVisualizer
|
|
|
89
113
|
'progress' => {
|
|
90
114
|
'preparing' => 'Preparando escaneo %<spinner>s Arch:%<files>s Dir:%<dirs>s',
|
|
91
115
|
'scanning' => 'Escaneando [%<bar>s] %<percent>s%% Arch:%<pf>s/%<tf>s Dir:%<pd>s/%<td>s'
|
|
116
|
+
},
|
|
117
|
+
'summary' => {
|
|
118
|
+
'heading' => 'Resumen',
|
|
119
|
+
'source' => 'Origen: %<path>s',
|
|
120
|
+
'total_size' => 'Tamano total: %<size>s',
|
|
121
|
+
'files' => 'Archivos: %<count>s',
|
|
122
|
+
'directories' => 'Directorios: %<count>s',
|
|
123
|
+
'skipped' => 'Entradas omitidas: %<count>s',
|
|
124
|
+
'top_files' => 'Top archivos:',
|
|
125
|
+
'none' => '(ninguno)'
|
|
92
126
|
}
|
|
93
127
|
},
|
|
94
128
|
'report' => {
|
|
@@ -5,9 +5,10 @@ module FileTreeVisualizer
|
|
|
5
5
|
DEFAULT_TOP_LIMIT = 200
|
|
6
6
|
Result = Struct.new(:root, :top_files, :stats, keyword_init: true)
|
|
7
7
|
|
|
8
|
-
def initialize(top_limit: DEFAULT_TOP_LIMIT, follow_symlinks: false)
|
|
8
|
+
def initialize(top_limit: DEFAULT_TOP_LIMIT, follow_symlinks: false, excludes: [])
|
|
9
9
|
@top_limit = top_limit
|
|
10
10
|
@follow_symlinks = follow_symlinks
|
|
11
|
+
@excludes = Array(excludes).map(&:to_s).reject(&:empty?)
|
|
11
12
|
reset!
|
|
12
13
|
end
|
|
13
14
|
|
|
@@ -16,6 +17,8 @@ module FileTreeVisualizer
|
|
|
16
17
|
expanded_path = File.expand_path(path.to_s)
|
|
17
18
|
raise ArgumentError, "Path is not a directory: #{expanded_path}" unless File.directory?(expanded_path)
|
|
18
19
|
|
|
20
|
+
@root_path = expanded_path
|
|
21
|
+
|
|
19
22
|
@progress_callback = progress
|
|
20
23
|
notify_counting_progress(force: true)
|
|
21
24
|
totals = count_totals(expanded_path)
|
|
@@ -57,6 +60,7 @@ module FileTreeVisualizer
|
|
|
57
60
|
@processed_directories = 0
|
|
58
61
|
@counted_files = 0
|
|
59
62
|
@counted_directories = 0
|
|
63
|
+
@root_path = nil
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
def scan_directory(path)
|
|
@@ -78,6 +82,11 @@ module FileTreeVisualizer
|
|
|
78
82
|
entries = Dir.children(path)
|
|
79
83
|
entries.each do |entry_name|
|
|
80
84
|
child_path = File.join(path, entry_name)
|
|
85
|
+
if excluded_path?(child_path)
|
|
86
|
+
@skipped_count += 1
|
|
87
|
+
next
|
|
88
|
+
end
|
|
89
|
+
|
|
81
90
|
process_child_node(child_path, entry_name, node)
|
|
82
91
|
rescue StandardError
|
|
83
92
|
@skipped_count += 1
|
|
@@ -142,6 +151,7 @@ module FileTreeVisualizer
|
|
|
142
151
|
entries = Dir.children(path)
|
|
143
152
|
entries.each do |entry_name|
|
|
144
153
|
child_path = File.join(path, entry_name)
|
|
154
|
+
next if excluded_path?(child_path)
|
|
145
155
|
|
|
146
156
|
begin
|
|
147
157
|
if File.symlink?(child_path) && !@follow_symlinks
|
|
@@ -165,6 +175,22 @@ module FileTreeVisualizer
|
|
|
165
175
|
totals
|
|
166
176
|
end
|
|
167
177
|
|
|
178
|
+
def excluded_path?(path)
|
|
179
|
+
return false if @excludes.empty?
|
|
180
|
+
|
|
181
|
+
basename = File.basename(path)
|
|
182
|
+
relative = relative_path(path)
|
|
183
|
+
flags = File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB
|
|
184
|
+
|
|
185
|
+
@excludes.any? do |pattern|
|
|
186
|
+
File.fnmatch?(pattern, basename, flags) || File.fnmatch?(pattern, relative, flags)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def relative_path(path)
|
|
191
|
+
path.delete_prefix("#{@root_path}/")
|
|
192
|
+
end
|
|
193
|
+
|
|
168
194
|
def notify_progress
|
|
169
195
|
return unless @progress_callback
|
|
170
196
|
|
metadata
CHANGED
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: file_tree_visualizer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- John Bidwell
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
date: 2026-04-04 00:00:00.000000000 Z
|
|
12
|
-
dependencies:
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: csv
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.3'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.3'
|
|
13
27
|
description: Scans a directory recursively, computes file/directory sizes, and generates
|
|
14
28
|
an HTML report rendered with React.
|
|
15
29
|
email:
|
|
16
|
-
-
|
|
30
|
+
- johnbidwellb@gmail.com
|
|
17
31
|
executables:
|
|
18
32
|
- file-tree-visualizer
|
|
19
33
|
extensions: []
|
|
@@ -34,7 +48,8 @@ homepage: https://github.com/JohnBidwellB/file-tree-visualizer
|
|
|
34
48
|
licenses:
|
|
35
49
|
- MIT
|
|
36
50
|
metadata:
|
|
37
|
-
source_code_uri: https://github.com/JohnBidwellB/file-tree-visualizer
|
|
51
|
+
source_code_uri: https://github.com/JohnBidwellB/file-tree-visualizer/tree/main
|
|
52
|
+
bug_tracker_uri: https://github.com/JohnBidwellB/file-tree-visualizer/issues
|
|
38
53
|
changelog_uri: https://github.com/JohnBidwellB/file-tree-visualizer/blob/main/CHANGELOG.md
|
|
39
54
|
post_install_message:
|
|
40
55
|
rdoc_options: []
|