dcat 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 21aa70d4fd2961f0000538bb28d339c50379aee433f35ff4663a26217a8c58e1
4
+ data.tar.gz: 9f66cab093be3f67b938d4bc6ea3102449c50a390ef6672a8553866baaaf8e51
5
+ SHA512:
6
+ metadata.gz: c8af4dd1942c96e0945cca7630e9f0d2e9193a8ceb9e241ec6fa0ae282d8a27b67651567983b2949580391d1d2e838b0f257fba3c929151bf9d7e9dc4c46dc6e
7
+ data.tar.gz: cb88673b172b06d4ee42b4c59774e5a358ef7a8b3ec4423e4f4d86c60974125c4970005067bd1437adf7c384e4e2b883161aaa91772cbced32ce463e220eab30
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 src
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.ja.md ADDED
@@ -0,0 +1,132 @@
1
+ # Dcat
2
+
3
+ [English](README.md) | **日本語**
4
+
5
+ ディスクカタログを作成・検索するためのRuby gemです。ファイルリストとメタデータ(サイズ、更新日時)を含む検索可能なカタログを作成し、効率的な保存のためにgzipで圧縮できます。
6
+
7
+ ## 機能
8
+
9
+ - **カタログ作成** - ディレクトリ構造からファイルメタデータ付きのカタログを作成
10
+ - **カタログ検索** - ripgrepを使用した効率的な検索
11
+ - **カタログ圧縮** - gzip圧縮による省スペース保存
12
+ - **クロスプラットフォーム対応** - Windows互換性
13
+ - **人間が読みやすいファイルサイズ** - 出力での可読性
14
+
15
+ ## インストール
16
+
17
+ gemをインストールするには:
18
+
19
+ ```bash
20
+ $ gem install dcat
21
+ ```
22
+
23
+ または、Gemfileに追加:
24
+
25
+ ```ruby
26
+ gem 'dcat'
27
+ ```
28
+
29
+ ## 使用方法
30
+
31
+ ### 設定
32
+
33
+ `~/.catalogrc`に設定ファイルを作成:
34
+
35
+ ```yaml
36
+ general:
37
+ catalogdir: ./data
38
+ ```
39
+
40
+ ### コマンド
41
+
42
+ #### カタログの作成
43
+
44
+ ```bash
45
+ $ dcatc [ディレクトリパス]
46
+ ```
47
+
48
+ 指定されたディレクトリ(未指定の場合は現在のディレクトリ)からカタログファイルを作成します。
49
+
50
+ #### カタログの検索
51
+
52
+ ```bash
53
+ $ dcats [検索パターン]
54
+ ```
55
+
56
+ パターンに一致するファイルをカタログファイルから検索します。
57
+
58
+ #### 圧縮カタログの読み込み
59
+
60
+ ```bash
61
+ $ dcatz [カタログファイル.gz]
62
+ ```
63
+
64
+ 圧縮されたカタログファイルを読み込むための`zcat`の代替コマンド。特にWindowsで有用です。
65
+
66
+ ### カタログファイル形式
67
+
68
+ カタログファイルはタブ区切り値として保存されます:
69
+ - 列1: フルファイルパス
70
+ - 列2: 更新日時(YYYY-MM-DD形式)
71
+ - 列3: ファイルサイズ(バイト)
72
+ - 列4: KB単位に切り上げたファイルサイズ(例: `1 KB`、`120,564 KB`)
73
+
74
+ ファイルは効率的な保存のためにgzip(`.gz`拡張子)で圧縮できます。
75
+
76
+ ### 使用例
77
+
78
+ ```bash
79
+ # 現在のディレクトリのカタログを作成
80
+ $ dcatc
81
+
82
+ # 特定のディレクトリのカタログを作成
83
+ $ dcatc /path/to/directory
84
+
85
+ # "document"を含むファイルを検索
86
+ $ dcats document
87
+
88
+ # 特定の拡張子のファイルを検索
89
+ $ dcats "*.pdf"
90
+
91
+ # 圧縮されたカタログを読み込み
92
+ $ dcatz catalog.gz
93
+ ```
94
+
95
+ ## 開発
96
+
97
+ リポジトリをチェックアウト後、`bin/setup`を実行して依存関係をインストールします。その後、`rake test`でテストを実行できます。
98
+
99
+ ```bash
100
+ # 依存関係のインストール
101
+ $ bundle install
102
+
103
+ # テストの実行
104
+ $ rake test
105
+
106
+ # gemのビルド
107
+ $ bundle exec rake build
108
+
109
+ # ローカルインストール
110
+ $ bundle exec rake install
111
+
112
+ # 対話型コンソール
113
+ $ bin/console
114
+ ```
115
+
116
+ ## 要件
117
+
118
+ - Ruby >= 2.6.0
119
+ - 検索機能用の`ripgrep`(rg)コマンド
120
+
121
+ ## 依存関係
122
+
123
+ - `sys-filesystem` - ディスク容量情報の取得
124
+ - `zlib` - gzip圧縮/展開
125
+
126
+ ## 貢献
127
+
128
+ バグレポートとプルリクエストは、GitHub https://github.com/src256/dcat で歓迎します。
129
+
130
+ ## ライセンス
131
+
132
+ このgemは[MIT License](https://opensource.org/licenses/MIT)の条件の下でオープンソースとして利用できます。
data/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # Dcat
2
+
3
+ **English** | [日本語](README.ja.md)
4
+
5
+ A Ruby gem for creating and searching disk catalogs. Generate searchable catalogs containing file lists and metadata (size, modification date) with efficient gzip compression for storage.
6
+
7
+ ## Features
8
+
9
+ - **Create catalogs** from directory structures with file metadata
10
+ - **Search catalogs** efficiently using ripgrep
11
+ - **Compress catalogs** with gzip for space-efficient storage
12
+ - **Cross-platform support** with Windows compatibility
13
+ - **Human-readable file sizes** in output
14
+
15
+ ## Installation
16
+
17
+ Install the gem by executing:
18
+
19
+ ```bash
20
+ $ gem install dcat
21
+ ```
22
+
23
+ Or add to your Gemfile:
24
+
25
+ ```ruby
26
+ gem 'dcat'
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Configuration
32
+
33
+ Create a configuration file at `~/.catalogrc`:
34
+
35
+ ```yaml
36
+ general:
37
+ catalogdir: ./data
38
+ ```
39
+
40
+ ### Commands
41
+
42
+ #### Create a catalog
43
+
44
+ ```bash
45
+ $ dcatc [directory_path]
46
+ ```
47
+
48
+ Creates a catalog file from the specified directory (or current directory if not specified).
49
+
50
+ #### Search catalogs
51
+
52
+ ```bash
53
+ $ dcats [search_pattern]
54
+ ```
55
+
56
+ Searches through catalog files for files matching the pattern.
57
+
58
+ #### Read compressed catalogs
59
+
60
+ ```bash
61
+ $ dcatz [catalog_file.gz]
62
+ ```
63
+
64
+ Alternative to `zcat` for reading compressed catalog files, especially useful on Windows.
65
+
66
+ ### Catalog File Format
67
+
68
+ Catalog files are stored as tab-separated values:
69
+ - Column 1: Full file path
70
+ - Column 2: Modification date (YYYY-MM-DD format)
71
+ - Column 3: File size (bytes)
72
+ - Column 4: File size rounded up to KB (e.g. `1 KB`, `120,564 KB`)
73
+
74
+ Files can be compressed with gzip (`.gz` extension) for efficient storage.
75
+
76
+ ### Examples
77
+
78
+ ```bash
79
+ # Create a catalog of the current directory
80
+ $ dcatc
81
+
82
+ # Create a catalog of a specific directory
83
+ $ dcatc /path/to/directory
84
+
85
+ # Search for files containing "document"
86
+ $ dcats document
87
+
88
+ # Search for files with specific extension
89
+ $ dcats "*.pdf"
90
+
91
+ # Read a compressed catalog
92
+ $ dcatz catalog.gz
93
+ ```
94
+
95
+ ## Development
96
+
97
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests.
98
+
99
+ ```bash
100
+ # Install dependencies
101
+ $ bundle install
102
+
103
+ # Run tests
104
+ $ rake test
105
+
106
+ # Build the gem
107
+ $ bundle exec rake build
108
+
109
+ # Install locally
110
+ $ bundle exec rake install
111
+
112
+ # Interactive console
113
+ $ bin/console
114
+ ```
115
+
116
+ ## Requirements
117
+
118
+ - Ruby >= 2.6.0
119
+ - `ripgrep` (rg) command for searching functionality
120
+
121
+ ## Dependencies
122
+
123
+ - `sys-filesystem` - For disk space information
124
+ - `zlib` - For gzip compression/decompression
125
+
126
+ ## Contributing
127
+
128
+ Bug reports and pull requests are welcome on GitHub at https://github.com/src256/dcat.
129
+
130
+ ## License
131
+
132
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/exe/dcatc ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "dcat"
4
+
5
+ Dcat::CreateCommand.run(ARGV)
data/exe/dcats ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "dcat"
4
+
5
+ Dcat::SearchCommand.run(ARGV)
data/exe/dcatz ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'zlib'
4
+
5
+
6
+ def zcat(filename)
7
+ return unless filename
8
+ return unless FileTest.file?(filename)
9
+ if filename =~ /\.gz$/
10
+ Zlib::GzipReader.open(filename) do |gz|
11
+ print gz.read
12
+ end
13
+ return
14
+ end
15
+ File.open(filename, 'rb') do |f|
16
+ while (line = f.gets)
17
+ print line
18
+ end
19
+ end
20
+ end
21
+
22
+ filename = ARGV[0]
23
+ zcat(filename)
24
+
25
+
@@ -0,0 +1,61 @@
1
+ module MyFind
2
+
3
+ #
4
+ # Calls the associated block with the name of every file and directory listed
5
+ # as arguments, then recursively on their subdirectories, and so on.
6
+ #
7
+ # Returns an enumerator if no block is given.
8
+ #
9
+ # See the +Find+ module documentation for an example.
10
+ #
11
+ def find(*paths, ignore_error: true) # :yield: path
12
+ block_given? or return enum_for(__method__, *paths, ignore_error: ignore_error)
13
+
14
+ fs_encoding = Encoding.find("filesystem")
15
+
16
+ paths.collect!{|d| raise Errno::ENOENT, d unless File.exist?(d); d.dup}.each do |path|
17
+ path = path.to_path if path.respond_to? :to_path
18
+ enc = path.encoding == Encoding::US_ASCII ? fs_encoding : path.encoding
19
+ ps = [path]
20
+ while file = ps.shift
21
+ catch(:prune) do
22
+ yield file.dup
23
+ begin
24
+ s = File.lstat(file)
25
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EPERM
26
+ raise unless ignore_error
27
+ next
28
+ end
29
+ if s.directory? then
30
+ begin
31
+ fs = Dir.children(file, encoding: enc)
32
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EPERM
33
+ raise unless ignore_error
34
+ next
35
+ end
36
+ fs.sort!
37
+ fs.reverse_each {|f|
38
+ f = File.join(file, f)
39
+ ps.unshift f
40
+ }
41
+ end
42
+ end
43
+ end
44
+ end
45
+ nil
46
+ end
47
+
48
+ #
49
+ # Skips the current file or directory, restarting the loop with the next
50
+ # entry. If the current file is a directory, that directory will not be
51
+ # recursively entered. Meaningful only within the block associated with
52
+ # Find::find.
53
+ #
54
+ # See the +Find+ module documentation for an example.
55
+ #
56
+ def prune
57
+ throw :prune
58
+ end
59
+
60
+ module_function :find, :prune
61
+ end
data/lib/dcat/utils.rb ADDED
@@ -0,0 +1,32 @@
1
+ module Dcat
2
+ class Utils
3
+ def self.number_to_human_size(size)
4
+ kb = 1024
5
+ mb = 1024**2
6
+ gb = 1024**3
7
+ tb = 1024**4
8
+ case
9
+ when size < kb
10
+ '%d Bytes' % size
11
+ when size < mb
12
+ '%.1f KB' % (size.to_f / kb)
13
+ when size < gb
14
+ '%.1f MB' % (size.to_f / mb)
15
+ when size < tb
16
+ '%.1f GB' % (size.to_f / gb)
17
+ else
18
+ '%.1f TB' % (size.to_f / tb)
19
+ end.sub('.0', '')
20
+ end
21
+
22
+ def self.windows?
23
+ RUBY_PLATFORM =~ /mswin|mingw|bccwin|cygwin/
24
+ end
25
+
26
+ def self.number_to_kb(bytes)
27
+ kb = (bytes.to_f / 1024).ceil
28
+ kb.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse + " KB"
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dcat
4
+ VERSION = "1.0.0"
5
+ end
data/lib/dcat.rb ADDED
@@ -0,0 +1,308 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dcat/version"
4
+ require "dcat/my_find"
5
+ require "dcat/utils"
6
+
7
+
8
+ require 'optparse'
9
+ require 'fileutils'
10
+ require 'yaml'
11
+ require 'sys/filesystem'
12
+ require 'zlib'
13
+
14
+ module Dcat
15
+ DEF_CONFIG = File.expand_path("~/.catalogrc")
16
+ SEARCH_CMD = "rg"
17
+
18
+ class Error < StandardError; end
19
+
20
+ class Config
21
+ CATALOGDIR = File.expand_path("~/.catalog")
22
+
23
+ def self.create_from_yaml(yaml)
24
+ config = Config.new
25
+ catalogdir = config_value(yaml, "general", "catalogdir", true)
26
+ if catalogdir
27
+ catalogdir = File.expand_path(catalogdir)
28
+ end
29
+ config.catalogdir = catalogdir
30
+
31
+ ## puts config.catalogdir
32
+ config.init_default
33
+ if config.catalogdir.nil? || !FileTest.directory?(config.catalogdir)
34
+ raise RuntimeError, "catalogdir is not exist: #{config.catalogdir}"
35
+ end
36
+ config
37
+ end
38
+
39
+ def self.config_value(yaml, section, key, require)
40
+ return nil unless yaml
41
+ return nil unless yaml[section]
42
+ value = yaml[section][key]
43
+ if require && (value.nil? || value.empty?)
44
+ raise RuntimeError, "#{section}:#{key}: is empty"
45
+ end
46
+ value
47
+ end
48
+
49
+ def init_default
50
+ @catalogdir ||= CATALOGDIR
51
+ end
52
+
53
+ attr_accessor :catalogdir
54
+ end
55
+
56
+ class Option
57
+ def initialize(opts, argv, config)
58
+ @opts = opts
59
+ @argv = argv
60
+ @config = config
61
+ @debug = @opts[:d]
62
+ @list = false
63
+ if @opts[:l]
64
+ @list = true
65
+ end
66
+ end
67
+ attr_reader :debug, :list
68
+ def catalogdir
69
+ @config.catalogdir
70
+ end
71
+ end
72
+
73
+ class CreateOption < Option
74
+ def initialize(opts, argv, config)
75
+ super
76
+ @dir = nil
77
+ if argv.size > 0 && FileTest.directory?(argv[0])
78
+ @dir = argv[0]
79
+ end
80
+
81
+ @debug = @opts[:d]
82
+ @compress = @opts[:z]
83
+ @output = @opts[:o]
84
+ if @output
85
+ @output_files = File.join(catalogdir, @output + '.files')
86
+ @output_info = File.join(catalogdir, @output + '.info')
87
+ end
88
+ end
89
+ attr_reader :dir, :search, :debug, :output, :output_files, :output_info, :compress, :debug
90
+
91
+ # def output_files
92
+ # if compress
93
+ # @output_files + '.gz'
94
+ # else
95
+ # @output_files
96
+ # end
97
+ # end
98
+
99
+ def compress_output_files
100
+ @output_files + '.gz'
101
+ end
102
+
103
+ def real_output_files
104
+ if compress
105
+ compress_output_files
106
+ else
107
+ @output_files
108
+ end
109
+ end
110
+ end
111
+
112
+ class SearchOption < Option
113
+ def initialize(opts, argv, config)
114
+ super
115
+ @search = nil
116
+ if argv.size > 0
117
+ @search = argv[0]
118
+ end
119
+ raise "SEARCH is not specified" unless @search
120
+ end
121
+ attr_reader :search
122
+ end
123
+
124
+ class Command
125
+ def self.load_yaml(config_file)
126
+ config_file ||= DEF_CONFIG
127
+ config_file = File.expand_path(config_file)
128
+ puts "Config: #{config_file}"
129
+ yaml = nil
130
+ if FileTest.file?(config_file)
131
+ yaml = YAML.load_file(config_file)
132
+ end
133
+ Config.create_from_yaml(yaml)
134
+ end
135
+
136
+ def list
137
+ puts "List catalog in #{@option.catalogdir}"
138
+ Dir.glob(File.join(@option.catalogdir, "*.info")).each do |path|
139
+ puts File.basename(path)
140
+ end
141
+ end
142
+ end
143
+
144
+ class CreateCommand < Command
145
+ def self.run(argv)
146
+ STDOUT.sync = true
147
+ opts = {}
148
+ opt = OptionParser.new(argv)
149
+ opt.version = VERSION
150
+ opt.banner = "Usage: #{opt.program_name} [options] <directory>"
151
+ opt.separator('Options')
152
+ opt.on_head('-h', '--help', 'show this message') do |v|
153
+ puts opt.help
154
+ exit
155
+ end
156
+ opt.on('-v', '--verbose', 'verbose message') {|v| opts[:v] = v}
157
+ opt.on('-o FILENAME', '--output=FILENAME') {|v| opts[:o] = v}
158
+ opt.on('--config=CONFIGFILE', 'Config file') {|v| opts[:c] = v }
159
+ opt.on('-d', '--debug', 'debug message') {|v| opts[:d] = v}
160
+ opt.on('-z', '--gzip', 'compress with gzip') {|v| opts[:z] = v}
161
+ opt.on('-l', '--list') {|v| opts[:l] = v}
162
+ opt.parse!(argv)
163
+ # if opts[:o].nil?
164
+ # puts opt.help
165
+ # exit
166
+ # end
167
+ config = load_yaml(opts[:c])
168
+ option = CreateOption.new(opts, argv, config)
169
+ begin
170
+ command = CreateCommand.new(option)
171
+ command.run
172
+ rescue => e
173
+ puts e.message
174
+ if option.debug
175
+ puts e.backtrace
176
+ end
177
+ puts opt.help
178
+ end
179
+ end
180
+
181
+ def initialize(option)
182
+ @option = option
183
+ end
184
+
185
+ def run
186
+ if @option.list
187
+ list
188
+ else
189
+ unless @option.dir
190
+ raise "directory is not specified"
191
+ end
192
+ make_files
193
+ make_info
194
+ end
195
+ end
196
+
197
+ private
198
+ def make_files
199
+ puts "Create catalog file for #{@option.dir}: #{@option.real_output_files}"
200
+ unless FileTest.directory?(@option.dir)
201
+ raise RuntimeError
202
+ end
203
+
204
+ File.unlink(@option.output_files) if FileTest.file?(@option.output_files)
205
+ File.unlink(@option.compress_output_files) if FileTest.file?(@option.compress_output_files)
206
+
207
+ if @option.compress
208
+ out = File.open(@option.compress_output_files, "w:utf-8")
209
+ out = Zlib::GzipWriter.open(out)
210
+ else
211
+ out = File.open(@option.output_files, "w:utf-8")
212
+ end
213
+
214
+ begin
215
+ MyFind.find(@option.dir, ignore_error: true) do |f|
216
+ if FileTest.file?(f)
217
+ size = File.size(f)
218
+ mtime = File.mtime(f).strftime("%Y-%m-%d")
219
+ human_readable_size = Utils.number_to_kb(size)
220
+ out.puts "#{f}\t#{mtime}\t#{size}\t#{human_readable_size}"
221
+ elsif FileTest.directory?(f)
222
+ STDERR.puts f
223
+ end
224
+ end
225
+ rescue => e
226
+ puts e.message
227
+ if option.debug
228
+ p e.backtrace
229
+ p e.class
230
+ end
231
+ end
232
+ out.close if out
233
+ end
234
+
235
+ def make_info
236
+ puts "Create info for #{@option.dir}: #{@option.output_info}"
237
+ unless FileTest.directory?(@option.dir)
238
+ raise RuntimeError
239
+ end
240
+
241
+ stat = Sys::Filesystem.stat(@option.dir)
242
+ free_bytes = Utils::number_to_human_size(stat.blocks_available * stat.block_size)
243
+ # puts number_to_human_size(free_bytes)
244
+ puts "total=#{stat.blocks * stat.block_size}"
245
+ total_bytes = Utils::number_to_human_size(stat.blocks * stat.block_size)
246
+ puts "total_bytes=#{total_bytes}"
247
+ #puts number_to_human_size(total_bytes)
248
+
249
+ out = File.open(@option.output_info, "w:utf-8")
250
+ created = Time.now.strftime("%Y-%m-%dT%H:%M:%S")
251
+ out.puts "Created: #{created}"
252
+ out.puts "Volume: #{@option.dir}"
253
+ out.puts "Total: #{total_bytes}"
254
+ out.puts "Free: #{free_bytes}"
255
+ out.close if out
256
+ end
257
+ end
258
+
259
+ class SearchCommand < Command
260
+ def self.run(argv)
261
+ STDOUT.sync = true
262
+ opts = {}
263
+ opt = OptionParser.new(argv)
264
+ opt.version = VERSION
265
+ opt.banner = "Usage: #{opt.program_name} [options] SEARCH <directory>"
266
+ opt.separator('Options')
267
+ opt.on_head('-h', '--help', 'show this message') do |v|
268
+ puts opt.help
269
+ exit
270
+ end
271
+ opt.on('-v', '--verbose', 'verbose message') {|v| opts[:v] = v}
272
+ opt.on('--config=CONFIGFILE', 'Config file') {|v| opts[:c] = v }
273
+ opt.on('-d', '--debug', 'debug message') {|v| opts[:d] = v}
274
+ opt.parse!(argv)
275
+ config = load_yaml(opts[:c])
276
+ begin
277
+ option = SearchOption.new(opts, argv, config)
278
+ command = SearchCommand.new(option)
279
+ command.run
280
+ rescue => e
281
+ puts e.message
282
+ if opts[:d]
283
+ puts e.backtrace
284
+ end
285
+ puts opt.help
286
+ end
287
+ end
288
+
289
+ def initialize(option)
290
+ @option = option
291
+ end
292
+
293
+ def run
294
+ if @option.list
295
+ list
296
+ else
297
+ search
298
+ end
299
+ end
300
+
301
+ def search
302
+ # rg の -z オプションが gzip 圧縮されたカタログを展開しながら検索する
303
+ cmd = "#{SEARCH_CMD} -z #{@option.search} #{@option.catalogdir}"
304
+ puts cmd if @option.debug
305
+ system(cmd)
306
+ end
307
+ end
308
+ end
data/sig/dcat.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Dcat
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dcat
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - src
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2026-09-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sys-filesystem
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: zlib
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: |
42
+ Dcat builds searchable catalogs of directory trees, recording each file's
43
+ full path, modification date and size as tab-separated text. Catalogs can be
44
+ gzip-compressed for compact storage and searched with ripgrep. It ships three
45
+ commands: dcatc to create a catalog, dcats to search catalogs, and dcatz to
46
+ read compressed catalogs as an alternative to zcat.
47
+ email:
48
+ - src@srcw.net
49
+ executables:
50
+ - dcatc
51
+ - dcats
52
+ - dcatz
53
+ extensions: []
54
+ extra_rdoc_files: []
55
+ files:
56
+ - LICENSE.txt
57
+ - README.ja.md
58
+ - README.md
59
+ - exe/dcatc
60
+ - exe/dcats
61
+ - exe/dcatz
62
+ - lib/dcat.rb
63
+ - lib/dcat/my_find.rb
64
+ - lib/dcat/utils.rb
65
+ - lib/dcat/version.rb
66
+ - sig/dcat.rbs
67
+ homepage: https://github.com/src256/dcat
68
+ licenses:
69
+ - MIT
70
+ metadata:
71
+ homepage_uri: https://github.com/src256/dcat
72
+ source_code_uri: https://github.com/src256/dcat
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 2.6.0
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 3.5.22
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Create and search disk catalogs of files and their metadata.
92
+ test_files: []