serialbench 0.1.2 → 0.1.3
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/.github/workflows/benchmark.yml +273 -228
- data/.github/workflows/rake.yml +11 -0
- data/.github/workflows/windows-debug.yml +171 -0
- data/.gitignore +32 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +274 -0
- data/Gemfile +13 -1
- data/README.adoc +36 -0
- data/data/schemas/result.yml +29 -0
- data/docs/PLATFORM_VALIDATION_FIX.md +79 -0
- data/docs/SYCK_YAML_FIX.md +91 -0
- data/docs/WEBSITE_COMPLETION_PLAN.md +440 -0
- data/docs/WINDOWS_LIBXML_FIX.md +136 -0
- data/docs/WINDOWS_SETUP.md +122 -0
- data/lib/serialbench/benchmark_runner.rb +3 -3
- data/lib/serialbench/cli/benchmark_cli.rb +74 -1
- data/lib/serialbench/cli/environment_cli.rb +3 -3
- data/lib/serialbench/cli/resultset_cli.rb +72 -26
- data/lib/serialbench/cli/ruby_build_cli.rb +75 -88
- data/lib/serialbench/cli/validate_cli.rb +88 -0
- data/lib/serialbench/cli.rb +6 -2
- data/lib/serialbench/config_manager.rb +15 -26
- data/lib/serialbench/models/benchmark_config.rb +12 -0
- data/lib/serialbench/models/benchmark_result.rb +39 -3
- data/lib/serialbench/models/environment_config.rb +3 -2
- data/lib/serialbench/models/platform.rb +56 -4
- data/lib/serialbench/models/result.rb +28 -1
- data/lib/serialbench/models/result_set.rb +8 -0
- data/lib/serialbench/ruby_build_manager.rb +19 -23
- data/lib/serialbench/runners/asdf_runner.rb +1 -1
- data/lib/serialbench/runners/docker_runner.rb +2 -4
- data/lib/serialbench/runners/local_runner.rb +71 -0
- data/lib/serialbench/serializers/base_serializer.rb +1 -1
- data/lib/serialbench/serializers/json/rapidjson_serializer.rb +1 -1
- data/lib/serialbench/serializers/toml/base_toml_serializer.rb +0 -2
- data/lib/serialbench/serializers/toml/toml_rb_serializer.rb +1 -1
- data/lib/serialbench/serializers/toml/tomlib_serializer.rb +1 -1
- data/lib/serialbench/serializers/xml/libxml_serializer.rb +4 -8
- data/lib/serialbench/serializers/xml/nokogiri_serializer.rb +2 -2
- data/lib/serialbench/serializers/xml/oga_serializer.rb +4 -8
- data/lib/serialbench/serializers/xml/ox_serializer.rb +2 -2
- data/lib/serialbench/serializers/xml/rexml_serializer.rb +3 -3
- data/lib/serialbench/serializers/yaml/psych_serializer.rb +1 -1
- data/lib/serialbench/serializers/yaml/syck_serializer.rb +1 -1
- data/lib/serialbench/serializers.rb +2 -2
- data/lib/serialbench/site_generator.rb +180 -2
- data/lib/serialbench/templates/assets/css/format_based.css +1 -53
- data/lib/serialbench/templates/assets/css/themes.css +5 -4
- data/lib/serialbench/templates/assets/js/chart_helpers.js +44 -14
- data/lib/serialbench/templates/assets/js/dashboard.js +14 -15
- data/lib/serialbench/templates/format_based.liquid +480 -252
- data/lib/serialbench/version.rb +1 -1
- data/lib/serialbench/yaml_validator.rb +36 -0
- data/serialbench.gemspec +11 -2
- metadata +34 -23
- data/.github/workflows/ci.yml +0 -74
- data/.github/workflows/docker.yml +0 -272
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Windows Setup Guide for Serialbench
|
|
2
|
+
|
|
3
|
+
This guide explains how to set up serialbench on Windows, particularly for installing the `libxml-ruby` gem which requires native libxml2 libraries.
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
The `libxml-ruby` gem requires native C libraries (libxml2) that need to be installed separately on Windows. Without these libraries, bundler will fail when trying to install the gem.
|
|
8
|
+
|
|
9
|
+
## Solution
|
|
10
|
+
|
|
11
|
+
### Option 1: Using Chocolatey (Recommended)
|
|
12
|
+
|
|
13
|
+
1. Install [Chocolatey](https://chocolatey.org/install) if you haven't already:
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
Set-ExecutionPolicy Bypass -Scope Process -Force
|
|
17
|
+
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
|
|
18
|
+
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
2. Install libxml2 and required tools:
|
|
22
|
+
|
|
23
|
+
```powershell
|
|
24
|
+
choco install -y libxml2
|
|
25
|
+
choco install -y pkgconfiglite
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
3. Set environment variables (you may need to adjust paths based on your installation):
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
# Find the actual libxml2 installation path
|
|
32
|
+
$libxmlPath = (Get-ChildItem "C:\ProgramData\chocolatey\lib\libxml2" -Recurse -Filter "libxml2.dll" | Select-Object -First 1).Directory.Parent.FullName
|
|
33
|
+
|
|
34
|
+
# Set PKG_CONFIG_PATH
|
|
35
|
+
$env:PKG_CONFIG_PATH = "$libxmlPath\lib\pkgconfig"
|
|
36
|
+
[System.Environment]::SetEnvironmentVariable('PKG_CONFIG_PATH', $env:PKG_CONFIG_PATH, 'User')
|
|
37
|
+
|
|
38
|
+
# Add to PATH
|
|
39
|
+
$env:PATH = "$libxmlPath\bin;$env:PATH"
|
|
40
|
+
$currentPath = [System.Environment]::GetEnvironmentVariable('PATH', 'User')
|
|
41
|
+
[System.Environment]::SetEnvironmentVariable('PATH', "$libxmlPath\bin;$currentPath", 'User')
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
4. Install Ruby dependencies:
|
|
45
|
+
|
|
46
|
+
```powershell
|
|
47
|
+
bundle install
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Option 2: Using vcpkg
|
|
51
|
+
|
|
52
|
+
1. Install vcpkg:
|
|
53
|
+
|
|
54
|
+
```powershell
|
|
55
|
+
git clone https://github.com/Microsoft/vcpkg.git
|
|
56
|
+
cd vcpkg
|
|
57
|
+
.\bootstrap-vcpkg.bat
|
|
58
|
+
.\vcpkg integrate install
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
2. Install libxml2:
|
|
62
|
+
|
|
63
|
+
```powershell
|
|
64
|
+
.\vcpkg install libxml2:x64-windows
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
3. Set environment variables:
|
|
68
|
+
|
|
69
|
+
```powershell
|
|
70
|
+
$vcpkgPath = "C:\path\to\vcpkg\installed\x64-windows"
|
|
71
|
+
$env:PKG_CONFIG_PATH = "$vcpkgPath\lib\pkgconfig"
|
|
72
|
+
$env:PATH = "$vcpkgPath\bin;$env:PATH"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Option 3: Skip libxml-ruby (Testing Only)
|
|
76
|
+
|
|
77
|
+
If you don't need to test the libxml serializer, you can temporarily exclude it:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
# In Gemfile or when installing
|
|
81
|
+
bundle install --without libxml
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or remove it from the gemspec temporarily (not recommended for CI).
|
|
85
|
+
|
|
86
|
+
## Troubleshooting
|
|
87
|
+
|
|
88
|
+
### Error: "Cannot find libxml2"
|
|
89
|
+
|
|
90
|
+
This means the libxml2 libraries are not in the expected locations. Try:
|
|
91
|
+
|
|
92
|
+
1. Verify libxml2 is installed:
|
|
93
|
+
```powershell
|
|
94
|
+
where libxml2.dll
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
2. Check pkg-config can find it:
|
|
98
|
+
```powershell
|
|
99
|
+
pkg-config --libs libxml-2.0
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
3. Manually specify the path when installing the gem:
|
|
103
|
+
```powershell
|
|
104
|
+
gem install libxml-ruby -- --with-xml2-dir="C:\path\to\libxml2"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Error: "mkmf.log shows missing headers"
|
|
108
|
+
|
|
109
|
+
The development headers aren't found. Make sure you installed the complete libxml2 package including headers.
|
|
110
|
+
|
|
111
|
+
## GitHub Actions CI
|
|
112
|
+
|
|
113
|
+
For CI/CD on GitHub Actions, see `.github/workflows/windows-setup.yml` for the complete setup that:
|
|
114
|
+
|
|
115
|
+
1. Installs libxml2 via Chocolatey
|
|
116
|
+
2. Configures environment paths
|
|
117
|
+
3. Runs bundle install
|
|
118
|
+
4. Executes tests
|
|
119
|
+
|
|
120
|
+
## Local Development
|
|
121
|
+
|
|
122
|
+
For local development on Windows, follow the Chocolatey or vcpkg installation steps above. There is no automated Rake task - you must manually install libxml2 before running `bundle install`.
|
|
@@ -36,7 +36,7 @@ module Serialbench
|
|
|
36
36
|
serializers: Serializers.information,
|
|
37
37
|
parsing: run_parsing_benchmarks,
|
|
38
38
|
generation: run_generation_benchmarks,
|
|
39
|
-
|
|
39
|
+
memory: run_memory_benchmarks,
|
|
40
40
|
streaming: run_streaming_benchmarks
|
|
41
41
|
)
|
|
42
42
|
end
|
|
@@ -221,7 +221,7 @@ module Serialbench
|
|
|
221
221
|
city: "City #{i % 100}",
|
|
222
222
|
preferences: {
|
|
223
223
|
theme: i.even? ? 'dark' : 'light',
|
|
224
|
-
notifications: i % 3
|
|
224
|
+
notifications: (i % 3).zero?
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
}
|
|
@@ -244,7 +244,7 @@ module Serialbench
|
|
|
244
244
|
data: {
|
|
245
245
|
field1: "Value #{i}",
|
|
246
246
|
field2: i * 2,
|
|
247
|
-
field3: i % 100
|
|
247
|
+
field3: (i % 100).zero? ? 'special' : 'normal',
|
|
248
248
|
nested: [
|
|
249
249
|
"Item #{i}-1",
|
|
250
250
|
"Item #{i}-2",
|
|
@@ -242,6 +242,79 @@ module Serialbench
|
|
|
242
242
|
|
|
243
243
|
private
|
|
244
244
|
|
|
245
|
+
def execute_local_benchmark(environment, config, benchmark_config_path)
|
|
246
|
+
say '🏠 Executing local benchmark', :green
|
|
247
|
+
|
|
248
|
+
runner = Serialbench::BenchmarkRunner.new(
|
|
249
|
+
environment_config: environment,
|
|
250
|
+
benchmark_config: config
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
# Run benchmarks
|
|
254
|
+
results = runner.run_all_benchmarks
|
|
255
|
+
|
|
256
|
+
platform = Serialbench::Models::Platform.current_local
|
|
257
|
+
|
|
258
|
+
metadata = Models::RunMetadata.new(
|
|
259
|
+
benchmark_config_path: benchmark_config_path,
|
|
260
|
+
environment_config_path: "config/environments/#{environment.name}.yml",
|
|
261
|
+
tags: [
|
|
262
|
+
'local',
|
|
263
|
+
platform.os,
|
|
264
|
+
platform.arch,
|
|
265
|
+
"ruby-#{environment.ruby_build_tag}"
|
|
266
|
+
]
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Create results directory
|
|
270
|
+
result_dir = "results/runs/#{environment.name}-results"
|
|
271
|
+
FileUtils.mkdir_p(result_dir)
|
|
272
|
+
|
|
273
|
+
# Save results to single YAML file with platform and metadata merged in
|
|
274
|
+
results_model = Models::Result.new(
|
|
275
|
+
platform: platform,
|
|
276
|
+
metadata: metadata,
|
|
277
|
+
environment_config: environment,
|
|
278
|
+
benchmark_config: config,
|
|
279
|
+
benchmark_result: results
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
results_file = File.join(result_dir, 'results.yaml')
|
|
283
|
+
results_model.to_file(results_file)
|
|
284
|
+
|
|
285
|
+
say '✅ Local benchmark completed successfully!', :green
|
|
286
|
+
say "Results saved to: #{result_dir}", :cyan
|
|
287
|
+
say "Generate site: serialbench benchmark build-site #{result_dir}", :white
|
|
288
|
+
rescue StandardError => e
|
|
289
|
+
say "❌ Local benchmark failed: #{e.message}", :red
|
|
290
|
+
say "Details: #{e.backtrace.first(3).join("\n")}", :white if options[:verbose]
|
|
291
|
+
raise e
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def execute_docker_benchmark(environment, config, benchmark_config_path)
|
|
295
|
+
say '🐳 Executing Docker benchmark', :green
|
|
296
|
+
|
|
297
|
+
require_relative '../runners/docker_runner'
|
|
298
|
+
|
|
299
|
+
environment_config_path = "config/environments/#{environment.name}.yml"
|
|
300
|
+
runner = Runners::DockerRunner.new(environment, environment_config_path)
|
|
301
|
+
|
|
302
|
+
# Create results directory
|
|
303
|
+
result_dir = "results/runs/#{environment.name}-results"
|
|
304
|
+
FileUtils.mkdir_p(result_dir)
|
|
305
|
+
|
|
306
|
+
# Run benchmark
|
|
307
|
+
runner.run_benchmark(config, benchmark_config_path, result_dir)
|
|
308
|
+
|
|
309
|
+
say '✅ Docker benchmark completed successfully!', :green
|
|
310
|
+
say "Results saved to: #{result_dir}", :cyan
|
|
311
|
+
say "Generate site: serialbench benchmark build-site #{result_dir}", :white
|
|
312
|
+
rescue StandardError => e
|
|
313
|
+
say "❌ Docker benchmark failed: #{e.message}", :red
|
|
314
|
+
say "Details: #{e.backtrace.first(3).join("\n")}", :white if options[:verbose]
|
|
315
|
+
raise e
|
|
316
|
+
end
|
|
317
|
+
|
|
245
318
|
def show_execute_usage_and_exit
|
|
246
319
|
say '❌ Error: Environment and config file arguments are required.', :red
|
|
247
320
|
say ''
|
|
@@ -350,7 +423,7 @@ module Serialbench
|
|
|
350
423
|
# raise e
|
|
351
424
|
# end
|
|
352
425
|
|
|
353
|
-
def execute_asdf_benchmark(environment,
|
|
426
|
+
def execute_asdf_benchmark(environment, _config, benchmark_config_path)
|
|
354
427
|
say '🔧 Executing ASDF benchmark', :green
|
|
355
428
|
|
|
356
429
|
# Use the ASDF runner to execute the benchmark
|
|
@@ -169,9 +169,9 @@ module Serialbench
|
|
|
169
169
|
when 'asdf'
|
|
170
170
|
require_relative '../runners/asdf_runner'
|
|
171
171
|
Runners::AsdfRunner.new(environment_config, environment_config_path)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
when 'local'
|
|
173
|
+
require_relative '../runners/local_runner'
|
|
174
|
+
Runners::LocalRunner.new(environment_config, environment_config_path)
|
|
175
175
|
else
|
|
176
176
|
raise "Unknown environment type: #{environment_config.kind}"
|
|
177
177
|
end
|
|
@@ -20,7 +20,7 @@ module Serialbench
|
|
|
20
20
|
serialbench resultset create cross-platform-test results/sets/cross-platform-test
|
|
21
21
|
DESC
|
|
22
22
|
def create(resultset_name, resultset_path)
|
|
23
|
-
|
|
23
|
+
Serialbench::Models::ResultStore.default
|
|
24
24
|
|
|
25
25
|
# Check if resultset already exists
|
|
26
26
|
definition_path = File.join(resultset_path, 'resultset.yaml')
|
|
@@ -49,36 +49,83 @@ module Serialbench
|
|
|
49
49
|
exit 1
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
desc 'add-result RESULT_PATH
|
|
52
|
+
desc 'add-result RESULTSET_PATH RESULT_PATH...', 'Add one or more runs to a resultset'
|
|
53
53
|
long_desc <<~DESC
|
|
54
|
-
Add
|
|
54
|
+
Add one or more benchmark runs to a resultset.
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
RESULTSET_PATH is the path to the resultset directory
|
|
57
|
+
RESULT_PATH... accepts multiple result paths (supports shell expansion)
|
|
58
58
|
|
|
59
59
|
Examples:
|
|
60
|
-
|
|
61
|
-
serialbench resultset add-result results/sets/
|
|
60
|
+
# Add single result
|
|
61
|
+
serialbench resultset add-result results/sets/weekly results/runs/my-run
|
|
62
|
+
|
|
63
|
+
# Add multiple results explicitly
|
|
64
|
+
serialbench resultset add-result results/sets/weekly results/runs/run1 results/runs/run2
|
|
65
|
+
|
|
66
|
+
# Add multiple results with shell expansion
|
|
67
|
+
serialbench resultset add-result results/sets/weekly artifacts/benchmark-results-*/
|
|
68
|
+
serialbench resultset add-result results/sets/weekly results/runs/*
|
|
62
69
|
DESC
|
|
63
|
-
def add_result(resultset_path,
|
|
70
|
+
def add_result(resultset_path, *result_paths)
|
|
71
|
+
if result_paths.empty?
|
|
72
|
+
say '❌ Error: At least one result path must be provided', :red
|
|
73
|
+
exit 1
|
|
74
|
+
end
|
|
75
|
+
|
|
64
76
|
resultset = Serialbench::Models::ResultSet.load(resultset_path)
|
|
65
77
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
78
|
+
say "📦 Adding #{result_paths.size} result(s) to resultset", :cyan
|
|
79
|
+
say "ResultSet: #{resultset_path}", :white
|
|
80
|
+
say ''
|
|
81
|
+
|
|
82
|
+
added_count = 0
|
|
83
|
+
failed_count = 0
|
|
84
|
+
skipped_count = 0
|
|
85
|
+
|
|
86
|
+
result_paths.each_with_index do |result_path, index|
|
|
87
|
+
say "#{index + 1}/#{result_paths.size} Processing: #{result_path}", :cyan
|
|
88
|
+
|
|
89
|
+
# Find results.yaml in the path or subdirectories
|
|
90
|
+
results_file = if File.exist?(File.join(result_path, 'results.yaml'))
|
|
91
|
+
File.join(result_path, 'results.yaml')
|
|
92
|
+
else
|
|
93
|
+
Dir.glob(File.join(result_path, '**/results.yaml')).first
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
unless results_file
|
|
97
|
+
say ' ⚠️ No results.yaml found - skipping', :yellow
|
|
98
|
+
skipped_count += 1
|
|
99
|
+
next
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
result_dir = File.dirname(results_file)
|
|
103
|
+
|
|
104
|
+
begin
|
|
105
|
+
resultset.add_result(result_dir)
|
|
106
|
+
say ' ✅ Added successfully', :green
|
|
107
|
+
added_count += 1
|
|
108
|
+
rescue StandardError => e
|
|
109
|
+
say " ❌ Failed: #{e.message}", :red
|
|
110
|
+
failed_count += 1
|
|
111
|
+
end
|
|
112
|
+
say ''
|
|
70
113
|
end
|
|
71
114
|
|
|
72
|
-
# Add run to resultset
|
|
73
|
-
resultset.add_result(result_path)
|
|
74
115
|
resultset.save(resultset_path)
|
|
75
116
|
|
|
76
|
-
say '
|
|
77
|
-
say
|
|
78
|
-
say "
|
|
79
|
-
say "
|
|
117
|
+
say '=' * 60, :cyan
|
|
118
|
+
say 'Summary:', :green
|
|
119
|
+
say " Total processed: #{result_paths.size}", :white
|
|
120
|
+
say " ✅ Successfully added: #{added_count}", :green
|
|
121
|
+
say " ❌ Failed: #{failed_count}", :red if failed_count > 0
|
|
122
|
+
say " ⚠️ Skipped: #{skipped_count}", :yellow if skipped_count > 0
|
|
123
|
+
say " 📊 Total results in set: #{resultset.results.count}", :cyan
|
|
124
|
+
say '=' * 60, :cyan
|
|
125
|
+
|
|
126
|
+
exit 1 if failed_count > 0 && added_count == 0
|
|
80
127
|
rescue StandardError => e
|
|
81
|
-
say "Error
|
|
128
|
+
say "❌ Error: #{e.message}", :red
|
|
82
129
|
exit 1
|
|
83
130
|
end
|
|
84
131
|
|
|
@@ -93,8 +140,8 @@ module Serialbench
|
|
|
93
140
|
serialbench resultset remove-result results/sets/performance-comparison results/runs/my-run-local-macos-arm64-ruby-3.3.8
|
|
94
141
|
serialbench resultset remove-result results/sets/cross-platform-test results/runs/my-docker-run
|
|
95
142
|
DESC
|
|
96
|
-
def remove_result(resultset_path,
|
|
97
|
-
|
|
143
|
+
def remove_result(resultset_path, _result_path)
|
|
144
|
+
Serialbench::Models::ResultStore.default
|
|
98
145
|
|
|
99
146
|
# Find the resultset
|
|
100
147
|
resultset = Serialbench::Models::ResultSet.load(resultset_path)
|
|
@@ -136,8 +183,7 @@ module Serialbench
|
|
|
136
183
|
serialbench resultset build-site results/sets/performance-comparison
|
|
137
184
|
serialbench resultset build-site results/sets/cross-platform-test output/
|
|
138
185
|
DESC
|
|
139
|
-
|
|
140
|
-
def build_site(resultset_path)
|
|
186
|
+
def build_site(resultset_path, output_dir = '_site')
|
|
141
187
|
unless Dir.exist?(resultset_path)
|
|
142
188
|
say "ResultSet directory not found: #{resultset_path}", :red
|
|
143
189
|
say "Please create a resultset first using 'serialbench resultset create'", :white
|
|
@@ -156,11 +202,11 @@ module Serialbench
|
|
|
156
202
|
say "Runs in set: #{resultset.results.size}", :cyan
|
|
157
203
|
|
|
158
204
|
# Use the unified site generator for resultsets
|
|
159
|
-
Serialbench::SiteGenerator.generate_for_resultset(resultset,
|
|
205
|
+
Serialbench::SiteGenerator.generate_for_resultset(resultset, output_dir)
|
|
160
206
|
|
|
161
207
|
say '✅ HTML site generated successfully!', :green
|
|
162
|
-
say "Site location: #{
|
|
163
|
-
say "Open: #{File.join(
|
|
208
|
+
say "Site location: #{output_dir}", :cyan
|
|
209
|
+
say "Open: #{File.join(output_dir, 'index.html')}", :white
|
|
164
210
|
rescue StandardError => e
|
|
165
211
|
say "Error generating site: #{e.message}", :red
|
|
166
212
|
say "Details: #{e.backtrace.first(3).join("\n")}", :red if options[:verbose]
|
|
@@ -32,7 +32,6 @@ module Serialbench
|
|
|
32
32
|
say "\n📋 Recent Ruby versions available:", :white
|
|
33
33
|
recent_versions.each { |version| say " #{version}", :cyan }
|
|
34
34
|
end
|
|
35
|
-
|
|
36
35
|
rescue StandardError => e
|
|
37
36
|
say "❌ Failed to update Ruby-Build definitions: #{e.message}", :red
|
|
38
37
|
exit 1
|
|
@@ -52,42 +51,39 @@ module Serialbench
|
|
|
52
51
|
DESC
|
|
53
52
|
option :limit, type: :numeric, default: 50, desc: 'Maximum number of definitions to show'
|
|
54
53
|
def list(filter = nil)
|
|
55
|
-
|
|
56
|
-
definitions = RubyBuildManager.list_definitions(filter: filter)
|
|
57
|
-
|
|
58
|
-
if definitions.empty?
|
|
59
|
-
if filter
|
|
60
|
-
say "No Ruby-Build definitions found matching '#{filter}'", :yellow
|
|
61
|
-
else
|
|
62
|
-
say 'No Ruby-Build definitions found in cache', :yellow
|
|
63
|
-
say 'Update the cache first: serialbench ruby-build update', :white
|
|
64
|
-
end
|
|
65
|
-
return
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Limit results if there are many
|
|
69
|
-
limited_definitions = definitions.first(options[:limit])
|
|
54
|
+
definitions = RubyBuildManager.list_definitions(filter: filter)
|
|
70
55
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
say
|
|
56
|
+
if definitions.empty?
|
|
57
|
+
if filter
|
|
58
|
+
say "No Ruby-Build definitions found matching '#{filter}'", :yellow
|
|
59
|
+
else
|
|
60
|
+
say 'No Ruby-Build definitions found in cache', :yellow
|
|
61
|
+
say 'Update the cache first: serialbench ruby-build update', :white
|
|
76
62
|
end
|
|
63
|
+
return
|
|
64
|
+
end
|
|
77
65
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
say "\n... and #{remaining} more definitions", :yellow
|
|
81
|
-
say "Use --limit to show more results", :white
|
|
82
|
-
end
|
|
66
|
+
# Limit results if there are many
|
|
67
|
+
limited_definitions = definitions.first(options[:limit])
|
|
83
68
|
|
|
84
|
-
|
|
69
|
+
say "Ruby-Build Definitions#{filter ? " (filtered by '#{filter}')" : ''}:", :green
|
|
70
|
+
say '=' * 60, :green
|
|
85
71
|
|
|
86
|
-
|
|
87
|
-
say "
|
|
88
|
-
|
|
89
|
-
|
|
72
|
+
limited_definitions.each do |definition|
|
|
73
|
+
say " #{definition}", :cyan
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if definitions.length > options[:limit]
|
|
77
|
+
remaining = definitions.length - options[:limit]
|
|
78
|
+
say "\n... and #{remaining} more definitions", :yellow
|
|
79
|
+
say 'Use --limit to show more results', :white
|
|
90
80
|
end
|
|
81
|
+
|
|
82
|
+
say "\nTotal: #{definitions.length} definitions", :white
|
|
83
|
+
rescue StandardError => e
|
|
84
|
+
say "❌ Failed to list Ruby-Build definitions: #{e.message}", :red
|
|
85
|
+
say 'Try updating the cache: serialbench ruby-build update', :white
|
|
86
|
+
exit 1
|
|
91
87
|
end
|
|
92
88
|
|
|
93
89
|
desc 'show TAG', 'Show details for a specific Ruby-Build definition'
|
|
@@ -99,21 +95,18 @@ module Serialbench
|
|
|
99
95
|
serialbench ruby-build show 3.2.4
|
|
100
96
|
DESC
|
|
101
97
|
def show(tag)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
say 'Available definitions: serialbench ruby-build list', :white
|
|
115
|
-
exit 1
|
|
116
|
-
end
|
|
98
|
+
definition = RubyBuildManager.show_definition(tag)
|
|
99
|
+
|
|
100
|
+
say "Ruby-Build Definition: #{tag}", :green
|
|
101
|
+
say '=' * 40, :green
|
|
102
|
+
say "Tag: #{definition[:tag]}", :cyan
|
|
103
|
+
say "Available: #{definition[:available] ? '✅ Yes' : '❌ No'}", :cyan
|
|
104
|
+
say "Source: #{definition[:source]}", :cyan
|
|
105
|
+
say "Cache file: #{definition[:cache_file]}", :white
|
|
106
|
+
rescue StandardError => e
|
|
107
|
+
say "❌ #{e.message}", :red
|
|
108
|
+
say 'Available definitions: serialbench ruby-build list', :white
|
|
109
|
+
exit 1
|
|
117
110
|
end
|
|
118
111
|
|
|
119
112
|
desc 'validate TAG', 'Validate a Ruby-Build tag'
|
|
@@ -125,31 +118,28 @@ module Serialbench
|
|
|
125
118
|
serialbench ruby-build validate 3.2.4
|
|
126
119
|
DESC
|
|
127
120
|
def validate(tag)
|
|
128
|
-
|
|
129
|
-
valid = RubyBuildManager.validate_tag(tag)
|
|
130
|
-
|
|
131
|
-
if valid
|
|
132
|
-
say "✅ Ruby-Build tag '#{tag}' is valid", :green
|
|
133
|
-
else
|
|
134
|
-
say "❌ Ruby-Build tag '#{tag}' is not valid", :red
|
|
121
|
+
valid = RubyBuildManager.validate_tag(tag)
|
|
135
122
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
123
|
+
if valid
|
|
124
|
+
say "✅ Ruby-Build tag '#{tag}' is valid", :green
|
|
125
|
+
else
|
|
126
|
+
say "❌ Ruby-Build tag '#{tag}' is not valid", :red
|
|
139
127
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
end
|
|
128
|
+
# Suggest similar tags
|
|
129
|
+
definitions = RubyBuildManager.list_definitions
|
|
130
|
+
similar = definitions.select { |d| d.include?(tag.split('.').first(2).join('.')) }.first(5)
|
|
144
131
|
|
|
145
|
-
|
|
132
|
+
if similar.any?
|
|
133
|
+
say "\n💡 Similar available tags:", :yellow
|
|
134
|
+
similar.each { |s| say " #{s}", :cyan }
|
|
146
135
|
end
|
|
147
136
|
|
|
148
|
-
rescue StandardError => e
|
|
149
|
-
say "❌ Failed to validate tag: #{e.message}", :red
|
|
150
|
-
say 'Try updating the cache: serialbench ruby-build update', :white
|
|
151
137
|
exit 1
|
|
152
138
|
end
|
|
139
|
+
rescue StandardError => e
|
|
140
|
+
say "❌ Failed to validate tag: #{e.message}", :red
|
|
141
|
+
say 'Try updating the cache: serialbench ruby-build update', :white
|
|
142
|
+
exit 1
|
|
153
143
|
end
|
|
154
144
|
|
|
155
145
|
desc 'suggest', 'Suggest Ruby-Build tag for current Ruby version'
|
|
@@ -163,26 +153,23 @@ module Serialbench
|
|
|
163
153
|
serialbench ruby-build suggest
|
|
164
154
|
DESC
|
|
165
155
|
def suggest
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
suggested_tag = RubyBuildManager.suggest_current_ruby_tag
|
|
156
|
+
current_ruby = RUBY_VERSION
|
|
157
|
+
suggested_tag = RubyBuildManager.suggest_current_ruby_tag
|
|
169
158
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
# Validate the suggestion
|
|
174
|
-
if RubyBuildManager.validate_tag(suggested_tag)
|
|
175
|
-
say "✅ Suggested tag is valid", :green
|
|
176
|
-
else
|
|
177
|
-
say "⚠️ Suggested tag not found in ruby-build definitions", :yellow
|
|
178
|
-
say "You may need to update the cache or use a different tag", :white
|
|
179
|
-
end
|
|
159
|
+
say "Current Ruby version: #{current_ruby}", :cyan
|
|
160
|
+
say "Suggested ruby_build_tag: #{suggested_tag}", :green
|
|
180
161
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
say '
|
|
184
|
-
|
|
162
|
+
# Validate the suggestion
|
|
163
|
+
if RubyBuildManager.validate_tag(suggested_tag)
|
|
164
|
+
say '✅ Suggested tag is valid', :green
|
|
165
|
+
else
|
|
166
|
+
say '⚠️ Suggested tag not found in ruby-build definitions', :yellow
|
|
167
|
+
say 'You may need to update the cache or use a different tag', :white
|
|
185
168
|
end
|
|
169
|
+
rescue StandardError => e
|
|
170
|
+
say "❌ Failed to suggest tag: #{e.message}", :red
|
|
171
|
+
say 'Try updating the cache: serialbench ruby-build update', :white
|
|
172
|
+
exit 1
|
|
186
173
|
end
|
|
187
174
|
|
|
188
175
|
desc 'cache-info', 'Show information about the Ruby-Build definitions cache'
|
|
@@ -203,19 +190,19 @@ module Serialbench
|
|
|
203
190
|
say "Location: #{RubyBuildManager::CACHE_FILE}", :cyan
|
|
204
191
|
say "Definitions: #{definitions_count}", :cyan
|
|
205
192
|
say "Age: #{format_cache_age(cache_age)}", :cyan
|
|
206
|
-
say
|
|
193
|
+
say 'Status: ✅ Available', :green
|
|
207
194
|
|
|
208
195
|
if cache_age > 7 * 24 * 60 * 60 # 7 days
|
|
209
196
|
say "\n💡 Cache is older than 7 days, consider updating:", :yellow
|
|
210
|
-
say
|
|
197
|
+
say ' serialbench ruby-build update', :white
|
|
211
198
|
end
|
|
212
199
|
else
|
|
213
200
|
say 'Ruby-Build Cache Information:', :green
|
|
214
201
|
say '=' * 40, :green
|
|
215
202
|
say "Location: #{RubyBuildManager::CACHE_FILE}", :cyan
|
|
216
|
-
say
|
|
203
|
+
say 'Status: ❌ Not found', :red
|
|
217
204
|
say "\n📥 Update the cache first:", :yellow
|
|
218
|
-
say
|
|
205
|
+
say ' serialbench ruby-build update', :white
|
|
219
206
|
end
|
|
220
207
|
end
|
|
221
208
|
|
|
@@ -225,12 +212,12 @@ module Serialbench
|
|
|
225
212
|
days = (seconds / (24 * 60 * 60)).to_i
|
|
226
213
|
hours = ((seconds % (24 * 60 * 60)) / (60 * 60)).to_i
|
|
227
214
|
|
|
228
|
-
if days
|
|
215
|
+
if days.positive?
|
|
229
216
|
"#{days} day#{'s' if days != 1}, #{hours} hour#{'s' if hours != 1}"
|
|
230
|
-
elsif hours
|
|
217
|
+
elsif hours.positive?
|
|
231
218
|
"#{hours} hour#{'s' if hours != 1}"
|
|
232
219
|
else
|
|
233
|
-
|
|
220
|
+
'less than 1 hour'
|
|
234
221
|
end
|
|
235
222
|
end
|
|
236
223
|
end
|