ukiryu 0.1.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: 9a829b8c3437032c87c7dc360fec0aacd18a2ce7fe627b82defbb972e00047c2
4
+ data.tar.gz: 811407bd87c8e7665e78a970506d1591584a8a51ff95d6426333dd57b0749339
5
+ SHA512:
6
+ metadata.gz: 03a7575c15d808461881baebe51ffaca79f868f93ef4e073e026ab2385f88a0540e20168bcfe2299edcec0a68a7e0a5074cd01f60aaee786267665eb56a568cd
7
+ data.tar.gz: 15d32df885540d695c0a439acc03e4c1d144056ca5f7fa481c12934237b61350bab4b2e83c2ee4f184c3bb1f9dd905a3085d283b81f625cf4073cbc4d520f488
@@ -0,0 +1,143 @@
1
+ name: Test Tool Profiles
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, master, develop ]
6
+ pull_request:
7
+ branches: [ main, master, develop ]
8
+
9
+ jobs:
10
+ test:
11
+ name: Test on ${{ matrix.os }}
12
+ runs-on: ${{ matrix.os }}
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: [ubuntu-latest, macos-latest]
17
+ ruby: ['3.3']
18
+
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Set up Ruby
24
+ uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: ${{ matrix.ruby }}
27
+ bundler-cache: true
28
+ working-directory: ./ukiryu
29
+
30
+ - name: Install system dependencies (Ubuntu)
31
+ if: matrix.os == 'ubuntu-latest'
32
+ run: |
33
+ sudo apt-get update
34
+ sudo apt-get install -y imagemagick ffmpeg ghostscript
35
+
36
+ - name: Install system dependencies (macOS)
37
+ if: matrix.os == 'macos-latest'
38
+ run: |
39
+ brew install imagemagick ffmpeg ghostscript
40
+
41
+ - name: Show installed tool versions
42
+ run: |
43
+ echo "=== Installed Tool Versions ==="
44
+ echo -n "ImageMagick: " && magick -version | head -1 || echo "Not installed"
45
+ echo -n "FFmpeg: " && ffmpeg -version | head -1 || echo "Not installed"
46
+ echo -n "Ghostscript: " && gs --version || echo "Not installed"
47
+ echo -n "Pandoc: " && pandoc --version | head -1 || echo "Not installed"
48
+ echo -n "jpegoptim: " && jpegoptim --version 2>&1 | head -1 || echo "Not installed"
49
+ echo -n "optipng: " && optipng -v 2>&1 | head -1 || echo "Not installed"
50
+
51
+ - name: Run tests
52
+ working-directory: ./ukiryu
53
+ run: bundle exec rspec --format documentation
54
+
55
+ - name: Run all tests with coverage
56
+ working-directory: ./ukiryu
57
+ run: bundle exec rspec
58
+
59
+ schema-validation:
60
+ name: Validate Tool Profiles Schema
61
+ runs-on: ubuntu-latest
62
+
63
+ steps:
64
+ - name: Checkout code
65
+ uses: actions/checkout@v4
66
+
67
+ - name: Set up Ruby
68
+ uses: ruby/setup-ruby@v1
69
+ with:
70
+ ruby-version: '3.3'
71
+ bundler-cache: true
72
+ working-directory: ./ukiryu
73
+
74
+ - name: Validate all tool profiles
75
+ working-directory: ./ukiryu
76
+ run: |
77
+ ruby -r ./lib/ukiryu.rb -r ./lib/ukiryu/schema_validator.rb <<-'RUBY'
78
+ require 'yaml'
79
+ require 'json-schema'
80
+
81
+ schema_path = File.expand_path('../../schema/tool-profile.schema.yaml', __dir__)
82
+ schema = JSON::Schema.parse(File.read(schema_path))
83
+
84
+ # Find all tool profiles
85
+ profiles = Dir.glob('../../register/tools/**/*.yaml').sort
86
+
87
+ puts "Validating #{profiles.count} tool profiles..."
88
+ errors = []
89
+
90
+ profiles.each do |profile_path|
91
+ profile_name = profile_path.sub('../../register/tools/', '')
92
+ begin
93
+ profile = YAML.safe_load(File.read(profile_path))
94
+ schema.validate(profile)
95
+ puts " ✓ #{profile_name}"
96
+ rescue => e
97
+ errors << "#{profile_name}: #{e.message}"
98
+ puts " ✗ #{profile_name}: #{e.message}"
99
+ end
100
+ end
101
+
102
+ if errors.any?
103
+ puts "\n#{errors.count} validation errors:"
104
+ errors.each { |err| puts " - #{err}" }
105
+ exit 1
106
+ end
107
+
108
+ puts "\n✓ All #{profiles.count} tool profiles are valid!"
109
+ RUBY
110
+
111
+ # Optional: Test on Windows with native Windows tools
112
+ test-windows:
113
+ name: Test on Windows
114
+ runs-on: windows-latest
115
+ if: github.event_name == 'push' || (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'test-windows'))
116
+
117
+ steps:
118
+ - name: Checkout code
119
+ uses: actions/checkout@v4
120
+
121
+ - name: Set up Ruby
122
+ uses: ruby/setup-ruby@v1
123
+ with:
124
+ ruby-version: '3.3'
125
+ bundler-cache: true
126
+ working-directory: ./ukiryu
127
+
128
+ - name: Install Chocolatey packages
129
+ run: |
130
+ choco install imagemagick ffmpeg ghostscript -y
131
+
132
+ - name: Show installed tool versions
133
+ shell: pwsh
134
+ run: |
135
+ Write-Host "=== Installed Tool Versions ==="
136
+ Write-Host "ImageMagick: $(magick -version | Select-Object -First 1)"
137
+ Write-Host "FFmpeg: $(ffmpeg -version | Select-Object -First 1)"
138
+ Write-Host "Ghostscript: $(gs --version)"
139
+
140
+ - name: Run tests (skip unavailable tools)
141
+ working-directory: ./ukiryu
142
+ run: bundle exec rspec --format documentation
143
+ continue-on-error: true
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ Gemfile.lock
3
+ .rspec_status
4
+ .rubocop-*
5
+
6
+ .sass-cache
7
+ _site
8
+ *.gem
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "schema"]
2
+ path = schema
3
+ url = git@github.com:ukiryu/schema.git
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in ukiryu.gemspec
6
+ gemspec
7
+
8
+ # Development dependencies
9
+ gem "rake"
10
+ gem "rspec"
11
+ gem "rubocop"
12
+ gem "rubocop-performance"
13
+ gem "rubocop-rake"
14
+ gem "rubocop-rspec"
15
+
16
+ # For optional YAML schema validation in registry
17
+ gem "json-schema", "~> 3.0"
data/README.adoc ADDED
@@ -0,0 +1,295 @@
1
+ = Ukiryu
2
+
3
+ Platform-adaptive command execution framework using declarative YAML tool
4
+ profiles.
5
+
6
+ image:https://img.shields.io/gem/v/ukiryu.svg[RubyGems Version]
7
+ image:https://img.shields.io/github/license/ukiryu/ukiryu.svg[License]
8
+ image:https://github.com/ukiryu/ukiryu/actions/workflows/test.yml/badge.svg["Build", link="https://github.com/ukiryu/ukiryu/actions/workflows/test.yml"]
9
+
10
+ == Purpose
11
+
12
+ Ukiryu provides a Ruby framework for executing external commands with:
13
+
14
+ * Declarative YAML tool profiles
15
+ * Platform-specific command formatting (macOS, Linux, Windows)
16
+ * Shell-specific syntax (bash, zsh, fish, PowerShell, cmd)
17
+ * Version-aware tool detection
18
+ * Fully object-oriented result handling
19
+
20
+ == Features
21
+
22
+ === Tool Registry
23
+
24
+ Load tool definitions from YAML profiles:
25
+
26
+ [source,ruby]
27
+ ----
28
+ Ukiryu::Registry.default_registry_path = 'path/to/register'
29
+ tool = Ukiryu::Tool.get(:imagemagick)
30
+ ----
31
+
32
+ === Platform Detection
33
+
34
+ Automatic platform and shell detection:
35
+
36
+ [source,ruby]
37
+ ----
38
+ Ukiryu::Platform.detect # => :macos, :linux, or :windows
39
+ Ukiryu::Shell.detect # => :bash, :zsh, :powershell, etc.
40
+ ----
41
+
42
+ === Version Awareness
43
+
44
+ Handle different tool versions with specific profiles:
45
+
46
+ [source,ruby]
47
+ ----
48
+ tool = Ukiryu::Tool.get(:inkscape)
49
+ # Automatically selects 1.0.yaml or 0.92.yaml based on detected version
50
+ ----
51
+
52
+ === OOP Result Handling
53
+
54
+ Rich, object-oriented execution results:
55
+
56
+ [source,ruby]
57
+ ----
58
+ result = tool.execute(:convert, { inputs: ['input.png'], output: 'output.jpg' })
59
+
60
+ result.command_info.executable # => "/opt/homebrew/bin/magick"
61
+ result.output.stdout # => ""
62
+ result.output.success? # => true
63
+ result.metadata.duration # => 0.5
64
+ result.metadata.formatted_duration # => "500ms"
65
+ ----
66
+
67
+ == Architecture
68
+
69
+ === Class Hierarchy
70
+
71
+ [source]
72
+ ----
73
+ Ukiryu
74
+ ├── Executor
75
+ │ ├── CommandInfo (command details)
76
+ │ ├── Output (stdout/stderr with utilities)
77
+ │ ├── ExecutionMetadata(timing information)
78
+ │ └── Result (composes above three)
79
+ ├── Tool (YAML profile loader and executor)
80
+ ├── Registry (profile discovery and loading)
81
+ ├── Platform (platform detection and utilities)
82
+ ├── Shell
83
+ │ ├── Base (abstract shell interface)
84
+ │ ├── Bash
85
+ │ ├── Zsh
86
+ │ ├── Fish
87
+ │ ├── Sh
88
+ │ ├── PowerShell
89
+ │ └── Cmd
90
+ └── Errors (custom exception hierarchy)
91
+ ----
92
+
93
+ === Data Flow
94
+
95
+ [source]
96
+ ----
97
+ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐
98
+ │ YAML Profile │─────►│ Tool Class │─────►│ Executor │
99
+ │ (declarative) │ │ (loader & │ │ (platform & │
100
+ │ │ │ executor) │ │ shell aware) │
101
+ └─────────────────┘ └─────────────────┘ └────────┬─────────┘
102
+
103
+
104
+ ┌─────────────┐
105
+ │ Result │
106
+ │ (OOP with │
107
+ │ CommandInfo│
108
+ │ + Output │
109
+ │ + Metadata)│
110
+ └─────────────┘
111
+ ----
112
+
113
+ == Installation
114
+
115
+ Add this line to your application's Gemfile:
116
+
117
+ [source,ruby]
118
+ ----
119
+ gem 'ukiryu'
120
+ ----
121
+
122
+ And then execute:
123
+
124
+ [source,shell]
125
+ ----
126
+ bundle install
127
+ ----
128
+
129
+ Or install it yourself as:
130
+
131
+ [source,shell]
132
+ ----
133
+ gem install ukiryu
134
+ ----
135
+
136
+ == Usage
137
+
138
+ === Basic Command Execution
139
+
140
+ [source,ruby]
141
+ ----
142
+ require 'ukiryu'
143
+
144
+ # Set registry path to tool profiles
145
+ Ukiryu::Registry.default_registry_path = 'path/to/register'
146
+
147
+ # Get a tool
148
+ tool = Ukiryu::Tool.get(:imagemagick)
149
+
150
+ # Execute a command
151
+ result = tool.execute(:convert, {
152
+ inputs: ['input.png'],
153
+ output: 'output.jpg',
154
+ resize: '50x50',
155
+ quality: 85
156
+ })
157
+
158
+ # Check result
159
+ if result.success?
160
+ puts "Converted in #{result.metadata.formatted_duration}"
161
+ else
162
+ puts "Error: #{result.output.stderr}"
163
+ end
164
+ ----
165
+
166
+ === Accessing Result Details
167
+
168
+ [source,ruby]
169
+ ----
170
+ result = tool.execute(:identify, { input: ['test.png'] })
171
+
172
+ # Command information
173
+ result.command_info.executable # Full path to executable
174
+ result.command_info.arguments # Array of arguments
175
+ result.command_info.full_command # Complete command string
176
+ result.command_info.shell # Shell type used
177
+
178
+ # Output
179
+ result.output.stdout # Stripped stdout
180
+ result.output.stderr # Stripped stderr
181
+ result.output.stdout_lines # Array of lines
182
+ result.output.stdout_contains?(/PNG/)
183
+
184
+ # Metadata
185
+ result.metadata.started_at # Time object
186
+ result.metadata.finished_at # Time object
187
+ result.metadata.duration # Float (seconds)
188
+ result.metadata.timed_out? # Boolean
189
+ ----
190
+
191
+ === Error Handling
192
+
193
+ [source,ruby]
194
+ ----
195
+ begin
196
+ result = tool.execute(:convert, { inputs: ['nonexistent.png'], output: 'out.jpg' })
197
+ rescue Ukiryu::ExecutionError => e
198
+ puts "Command failed: #{e.message}"
199
+ rescue Ukiryu::TimeoutError => e
200
+ puts "Command timed out: #{e.message}"
201
+ end
202
+ ----
203
+
204
+ === Tool Availability
205
+
206
+ [source,ruby]
207
+ ----
208
+ tool = Ukiryu::Tool.get(:ffmpeg)
209
+
210
+ if tool.available?
211
+ puts "FFmpeg #{tool.version} found at #{tool.executable}"
212
+ else
213
+ puts "FFmpeg not installed"
214
+ end
215
+ ----
216
+
217
+ == Tool Profiles
218
+
219
+ Tool profiles are defined in separate https://github.com/ukiryu/register[Ukiryu Register] repository.
220
+
221
+ Example profile structure:
222
+
223
+ [source,yaml]
224
+ ----
225
+ name: imagemagick
226
+ version: "7.1"
227
+
228
+ version_detection:
229
+ command: "--version"
230
+ pattern: "(\\d+\\.\\d+)"
231
+
232
+ profiles:
233
+ - name: unix
234
+ platforms: [macos, linux]
235
+ shells: [bash, zsh, fish, sh]
236
+ commands:
237
+ convert:
238
+ arguments:
239
+ - name: inputs
240
+ type: file
241
+ variadic: true
242
+ position: last
243
+ options:
244
+ - name: resize
245
+ cli: "-resize"
246
+ flags:
247
+ - name: strip
248
+ cli: "-strip"
249
+ ----
250
+
251
+ == Development
252
+
253
+ === Running Tests
254
+
255
+ [source,shell]
256
+ ----
257
+ bundle exec rspec
258
+ ----
259
+
260
+ === Schema Validation
261
+
262
+ [source,shell]
263
+ ----
264
+ bundle exec rspec spec/ukiryu/schema_validator_spec.rb
265
+ ----
266
+
267
+ === GitHub Actions
268
+
269
+ Tests run on:
270
+ * Ubuntu latest
271
+ * macOS latest
272
+
273
+ == Contributing
274
+
275
+ 1. Fork the repository
276
+ 2. Create your feature branch
277
+ 3. Write tests for your changes
278
+ 4. Ensure all tests pass
279
+ 5. Submit a pull request
280
+
281
+
282
+ == License
283
+
284
+ The content is available as open source under the terms of the Ribose BSD
285
+ 2-Clause License.
286
+
287
+ == Copyright
288
+
289
+ Copyright Ribose.
290
+
291
+
292
+ == Related Repositories
293
+
294
+ * https://github.com/ukiryu/register[ukiryu/register] - Tool profile registry
295
+ * https://github.com/ukiryu/schema[ukiryu/schema] - Profile validation schema
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec