file_tree_visualizer 0.1.0 → 0.2.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/README.md +62 -5
- data/file_tree_visualizer.gemspec +5 -3
- data/lib/file_tree_visualizer/cli.rb +115 -12
- data/lib/file_tree_visualizer/i18n.rb +32 -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: b43d301f84619b7a620a0cbcef1d135d4906073efaecf03b737b43572ebd6d89
|
|
4
|
+
data.tar.gz: 65de782e8d5094d981f0bedd23e6307d1b6cd4eedebd6b8bbb412a9b303e330e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f6a58da21e94d26fd62fa5a05bc5d0946a16525c187f021e7184b010515051f346b2c8786067879c278c34ca3abfbe61dc416f1a2bd170201654c71d477bffd0
|
|
7
|
+
data.tar.gz: ba3cb73876856ee460c66f1b34a61f1965cb6deda2021f52dba5904a8500b995e8cd4c28fd91bb1f388462a88c2d62e381024e94d1430dfaf591555344c674a8
|
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.
|
|
36
|
+
gem install file_tree_visualizer -v 0.2.0
|
|
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.
|
|
44
|
+
gem install ./file_tree_visualizer-0.2.0.gem
|
|
42
45
|
file-tree-visualizer /path/to/scan -o report.html
|
|
43
46
|
```
|
|
44
47
|
|
|
@@ -55,6 +58,10 @@ 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)
|
|
59
66
|
-h, --help Show help
|
|
60
67
|
|
|
@@ -64,12 +71,62 @@ Language resolution priority:
|
|
|
64
71
|
- fallback to English (`en`)
|
|
65
72
|
```
|
|
66
73
|
|
|
74
|
+
## Common workflows
|
|
75
|
+
|
|
76
|
+
Summary only (no HTML file generated unless `--output` is explicitly provided):
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
file-tree-visualizer --summary
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Summary + HTML report:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
file-tree-visualizer . --summary --output report.html
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Exclude directories and files by pattern:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
file-tree-visualizer . --exclude "node_modules,.git,*.log" --exclude "tmp/**"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Export JSON and CSV in one run:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
file-tree-visualizer . --summary --json scan.json --csv top-files.csv
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Contributing
|
|
101
|
+
|
|
102
|
+
1. Create a feature branch from `main`.
|
|
103
|
+
2. Implement your change and run tests locally.
|
|
104
|
+
3. Push your branch and open a Pull Request.
|
|
105
|
+
4. Wait for CI to pass and at least one approval.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
git checkout -b feat/short-description
|
|
109
|
+
bundle exec rake test
|
|
110
|
+
git push origin feat/short-description
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Branch policy:
|
|
114
|
+
- For collaborators, `main` is protected and requires PR + CI + approval.
|
|
115
|
+
- Repository admins can bypass these rules when needed.
|
|
116
|
+
|
|
67
117
|
## Automatic release to RubyGems
|
|
68
118
|
|
|
69
|
-
- This repository publishes the gem automatically when pushing a tag with format `v*` (for example `v0.0
|
|
119
|
+
- This repository publishes the gem automatically when pushing a tag with format `v*` (for example `v0.2.0`).
|
|
70
120
|
- Before using it, configure the `RUBYGEMS_API_KEY` secret in GitHub Actions.
|
|
121
|
+
- You can also trigger the workflow manually from GitHub Actions (`workflow_dispatch`).
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
git tag v0.2.0
|
|
125
|
+
git push origin v0.2.0
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Reusable release notes template:
|
|
71
129
|
|
|
72
130
|
```bash
|
|
73
|
-
|
|
74
|
-
git push origin v0.0.4
|
|
131
|
+
gh release create v0.2.0 --title "v0.2.0" --notes-file .github/release-template.md
|
|
75
132
|
```
|
|
@@ -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
|
|
@@ -24,22 +26,30 @@ module FileTreeVisualizer
|
|
|
24
26
|
t(locale, 'cli.errors.invalid_directory', path: expanded_path)
|
|
25
27
|
end
|
|
26
28
|
|
|
27
|
-
scanner = Scanner.new(
|
|
29
|
+
scanner = Scanner.new(
|
|
30
|
+
top_limit: options[:top],
|
|
31
|
+
follow_symlinks: options[:follow_symlinks],
|
|
32
|
+
excludes: options[:exclude_patterns]
|
|
33
|
+
)
|
|
28
34
|
progress = ProgressRenderer.new(enabled: options[:progress], locale: locale)
|
|
29
35
|
callback = options[:progress] ? progress.method(:render) : nil
|
|
30
36
|
result = scanner.scan(expanded_path, progress: callback)
|
|
31
37
|
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
|
-
|
|
38
|
+
generated_at = Time.now.utc
|
|
39
|
+
output_path = maybe_write_report(options, expanded_path, result, locale, generated_at)
|
|
40
|
+
json_path = write_json_export(options[:json_output], expanded_path, result, locale, generated_at)
|
|
41
|
+
csv_path = write_csv_export(options[:csv_output], result)
|
|
42
|
+
print_summary(expanded_path, result, locale) if options[:summary]
|
|
43
|
+
puts t(locale, 'cli.messages.report_generated', path: output_path) if output_path
|
|
44
|
+
puts t(locale, 'cli.messages.json_generated', path: json_path) if json_path
|
|
45
|
+
puts t(locale, 'cli.messages.csv_generated', path: csv_path) if csv_path
|
|
46
|
+
unless options[:summary]
|
|
47
|
+
puts t(locale, 'cli.messages.scanned',
|
|
48
|
+
directories: result.stats[:directories],
|
|
49
|
+
files: result.stats[:files],
|
|
50
|
+
skipped: result.stats[:skipped])
|
|
51
|
+
end
|
|
52
|
+
puts t(locale, 'cli.messages.total_size', size: format_bytes(result.stats[:bytes])) unless options[:summary]
|
|
43
53
|
0
|
|
44
54
|
rescue OptionParser::ParseError, ArgumentError => e
|
|
45
55
|
locale = error_locale
|
|
@@ -133,6 +143,11 @@ module FileTreeVisualizer
|
|
|
133
143
|
top: Scanner::DEFAULT_TOP_LIMIT,
|
|
134
144
|
follow_symlinks: false,
|
|
135
145
|
progress: true,
|
|
146
|
+
summary: false,
|
|
147
|
+
output_given: false,
|
|
148
|
+
json_output: nil,
|
|
149
|
+
csv_output: nil,
|
|
150
|
+
exclude_patterns: [],
|
|
136
151
|
lang: nil,
|
|
137
152
|
help: false
|
|
138
153
|
}
|
|
@@ -164,6 +179,7 @@ module FileTreeVisualizer
|
|
|
164
179
|
|
|
165
180
|
opts.on('-o', '--output FILE', t(locale, 'cli.output_option', default: DEFAULT_OUTPUT)) do |value|
|
|
166
181
|
options[:output] = value
|
|
182
|
+
options[:output_given] = true
|
|
167
183
|
end
|
|
168
184
|
|
|
169
185
|
opts.on('-t', '--top N', Integer, t(locale, 'cli.top_option', default: Scanner::DEFAULT_TOP_LIMIT)) do |value|
|
|
@@ -178,6 +194,22 @@ module FileTreeVisualizer
|
|
|
178
194
|
options[:progress] = false
|
|
179
195
|
end
|
|
180
196
|
|
|
197
|
+
opts.on('--exclude PATTERNS', t(locale, 'cli.exclude_option')) do |value|
|
|
198
|
+
options[:exclude_patterns].concat(split_patterns(value))
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
opts.on('--summary', t(locale, 'cli.summary_option')) do
|
|
202
|
+
options[:summary] = true
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
opts.on('--json FILE', t(locale, 'cli.json_option')) do |value|
|
|
206
|
+
options[:json_output] = value
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
opts.on('--csv FILE', t(locale, 'cli.csv_option')) do |value|
|
|
210
|
+
options[:csv_output] = value
|
|
211
|
+
end
|
|
212
|
+
|
|
181
213
|
opts.on('--lang LANG', t(locale, 'cli.lang_option')) do |value|
|
|
182
214
|
options[:lang] = value
|
|
183
215
|
end
|
|
@@ -198,6 +230,10 @@ module FileTreeVisualizer
|
|
|
198
230
|
nil
|
|
199
231
|
end
|
|
200
232
|
|
|
233
|
+
def split_patterns(value)
|
|
234
|
+
value.to_s.split(',').map(&:strip).reject(&:empty?)
|
|
235
|
+
end
|
|
236
|
+
|
|
201
237
|
def t(locale, key, **vars)
|
|
202
238
|
I18n.t(locale, key, **vars)
|
|
203
239
|
end
|
|
@@ -221,5 +257,72 @@ module FileTreeVisualizer
|
|
|
221
257
|
precision = value < 10 ? 2 : 1
|
|
222
258
|
format("%.#{precision}f %s", value, units[unit_index])
|
|
223
259
|
end
|
|
260
|
+
|
|
261
|
+
def maybe_write_report(options, source_path, result, locale, generated_at)
|
|
262
|
+
should_write = !options[:summary] || options[:output_given]
|
|
263
|
+
return nil unless should_write
|
|
264
|
+
|
|
265
|
+
report = ReportBuilder.new(
|
|
266
|
+
result: result,
|
|
267
|
+
source_path: source_path,
|
|
268
|
+
locale: locale,
|
|
269
|
+
generated_at: generated_at
|
|
270
|
+
).build
|
|
271
|
+
output_path = File.expand_path(options[:output])
|
|
272
|
+
File.write(output_path, report)
|
|
273
|
+
output_path
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def write_json_export(target_path, source_path, result, locale, generated_at)
|
|
277
|
+
return nil unless target_path
|
|
278
|
+
|
|
279
|
+
output_path = File.expand_path(target_path)
|
|
280
|
+
payload = {
|
|
281
|
+
source_path: source_path,
|
|
282
|
+
generated_at: generated_at.iso8601,
|
|
283
|
+
locale: locale,
|
|
284
|
+
version: FileTreeVisualizer::VERSION,
|
|
285
|
+
stats: result.stats,
|
|
286
|
+
root: result.root,
|
|
287
|
+
top_files: result.top_files
|
|
288
|
+
}
|
|
289
|
+
File.write(output_path, JSON.pretty_generate(payload))
|
|
290
|
+
output_path
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def write_csv_export(target_path, result)
|
|
294
|
+
return nil unless target_path
|
|
295
|
+
|
|
296
|
+
output_path = File.expand_path(target_path)
|
|
297
|
+
CSV.open(output_path, 'w') do |csv|
|
|
298
|
+
csv << %w[rank path name size_bytes size_human]
|
|
299
|
+
result.top_files.each_with_index do |item, index|
|
|
300
|
+
csv << [index + 1, item[:path], item[:name], item[:size], format_bytes(item[:size])]
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
output_path
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def print_summary(source_path, result, locale)
|
|
307
|
+
puts t(locale, 'cli.summary.heading')
|
|
308
|
+
puts t(locale, 'cli.summary.source', path: source_path)
|
|
309
|
+
puts t(locale, 'cli.summary.total_size', size: format_bytes(result.stats[:bytes]))
|
|
310
|
+
puts t(locale, 'cli.summary.files', count: result.stats[:files])
|
|
311
|
+
puts t(locale, 'cli.summary.directories', count: result.stats[:directories])
|
|
312
|
+
puts t(locale, 'cli.summary.skipped', count: result.stats[:skipped])
|
|
313
|
+
puts t(locale, 'cli.summary.top_files')
|
|
314
|
+
|
|
315
|
+
if result.top_files.empty?
|
|
316
|
+
puts " #{t(locale, 'cli.summary.none')}"
|
|
317
|
+
return
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
result.top_files.each_with_index do |item, index|
|
|
321
|
+
puts format(' %<rank>d. %<size>s %<path>s',
|
|
322
|
+
rank: index + 1,
|
|
323
|
+
size: format_bytes(item[:size]),
|
|
324
|
+
path: item[:path])
|
|
325
|
+
end
|
|
326
|
+
end
|
|
224
327
|
end
|
|
225
328
|
end
|
|
@@ -13,10 +13,16 @@ 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)',
|
|
17
21
|
'help_option' => 'Show this help',
|
|
18
22
|
'messages' => {
|
|
19
23
|
'report_generated' => 'Report generated at: %<path>s',
|
|
24
|
+
'json_generated' => 'JSON exported at: %<path>s',
|
|
25
|
+
'csv_generated' => 'CSV exported at: %<path>s',
|
|
20
26
|
'scanned' => 'Scanned: %<directories>s directories, %<files>s files, %<skipped>s skipped.',
|
|
21
27
|
'total_size' => 'Total size: %<size>s'
|
|
22
28
|
},
|
|
@@ -30,6 +36,16 @@ module FileTreeVisualizer
|
|
|
30
36
|
'progress' => {
|
|
31
37
|
'preparing' => 'Preparing scan %<spinner>s Files:%<files>s Dirs:%<dirs>s',
|
|
32
38
|
'scanning' => 'Scanning [%<bar>s] %<percent>s%% Files:%<pf>s/%<tf>s Dirs:%<pd>s/%<td>s'
|
|
39
|
+
},
|
|
40
|
+
'summary' => {
|
|
41
|
+
'heading' => 'Summary',
|
|
42
|
+
'source' => 'Source: %<path>s',
|
|
43
|
+
'total_size' => 'Total size: %<size>s',
|
|
44
|
+
'files' => 'Files: %<count>s',
|
|
45
|
+
'directories' => 'Directories: %<count>s',
|
|
46
|
+
'skipped' => 'Skipped entries: %<count>s',
|
|
47
|
+
'top_files' => 'Top files:',
|
|
48
|
+
'none' => '(none)'
|
|
33
49
|
}
|
|
34
50
|
},
|
|
35
51
|
'report' => {
|
|
@@ -72,10 +88,16 @@ module FileTreeVisualizer
|
|
|
72
88
|
'top_option' => 'Cantidad de archivos pesados en ranking (default: %<default>s)',
|
|
73
89
|
'follow_symlinks_option' => 'Sigue enlaces simbólicos durante el escaneo',
|
|
74
90
|
'no_progress_option' => 'Desactiva la barra de progreso',
|
|
91
|
+
'exclude_option' => 'Excluye patrones (separados por coma o repetidos)',
|
|
92
|
+
'summary_option' => 'Imprime resumen en terminal',
|
|
93
|
+
'json_option' => 'Exporta resultado del escaneo como JSON',
|
|
94
|
+
'csv_option' => 'Exporta top de archivos como CSV',
|
|
75
95
|
'lang_option' => 'Idioma para CLI y reporte (en|es)',
|
|
76
96
|
'help_option' => 'Muestra esta ayuda',
|
|
77
97
|
'messages' => {
|
|
78
98
|
'report_generated' => 'Reporte generado en: %<path>s',
|
|
99
|
+
'json_generated' => 'JSON exportado en: %<path>s',
|
|
100
|
+
'csv_generated' => 'CSV exportado en: %<path>s',
|
|
79
101
|
'scanned' => 'Escaneado: %<directories>s directorios, %<files>s archivos, %<skipped>s omitidos.',
|
|
80
102
|
'total_size' => 'Tamano total: %<size>s'
|
|
81
103
|
},
|
|
@@ -89,6 +111,16 @@ module FileTreeVisualizer
|
|
|
89
111
|
'progress' => {
|
|
90
112
|
'preparing' => 'Preparando escaneo %<spinner>s Arch:%<files>s Dir:%<dirs>s',
|
|
91
113
|
'scanning' => 'Escaneando [%<bar>s] %<percent>s%% Arch:%<pf>s/%<tf>s Dir:%<pd>s/%<td>s'
|
|
114
|
+
},
|
|
115
|
+
'summary' => {
|
|
116
|
+
'heading' => 'Resumen',
|
|
117
|
+
'source' => 'Origen: %<path>s',
|
|
118
|
+
'total_size' => 'Tamano total: %<size>s',
|
|
119
|
+
'files' => 'Archivos: %<count>s',
|
|
120
|
+
'directories' => 'Directorios: %<count>s',
|
|
121
|
+
'skipped' => 'Entradas omitidas: %<count>s',
|
|
122
|
+
'top_files' => 'Top archivos:',
|
|
123
|
+
'none' => '(ninguno)'
|
|
92
124
|
}
|
|
93
125
|
},
|
|
94
126
|
'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.
|
|
4
|
+
version: 0.2.0
|
|
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: []
|