ukiryu 0.1.7 → 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/lib/ukiryu/cache.rb +6 -0
- data/lib/ukiryu/cache_registry.rb +64 -0
- data/lib/ukiryu/cli_commands/base_command.rb +6 -5
- data/lib/ukiryu/cli_commands/config_command.rb +7 -10
- data/lib/ukiryu/cli_commands/register_command.rb +27 -18
- data/lib/ukiryu/cli_commands/validate_command.rb +2 -2
- data/lib/ukiryu/command_builder.rb +83 -50
- data/lib/ukiryu/config.rb +13 -2
- data/lib/ukiryu/debug.rb +20 -9
- data/lib/ukiryu/definition/loader.rb +3 -3
- data/lib/ukiryu/errors.rb +37 -37
- data/lib/ukiryu/executable_locator.rb +40 -16
- data/lib/ukiryu/extractors/base_extractor.rb +2 -1
- data/lib/ukiryu/extractors/help_parser.rb +3 -0
- data/lib/ukiryu/logger.rb +51 -0
- data/lib/ukiryu/models/implementation_index.rb +2 -1
- data/lib/ukiryu/models/implementation_version.rb +18 -1
- data/lib/ukiryu/models/interface.rb +2 -1
- data/lib/ukiryu/models/run_environment.rb +0 -2
- data/lib/ukiryu/models/semantic_version.rb +174 -0
- data/lib/ukiryu/models/stage_metrics.rb +0 -1
- data/lib/ukiryu/register.rb +473 -232
- data/lib/ukiryu/shell/powershell.rb +188 -99
- data/lib/ukiryu/shell/sh.rb +4 -1
- data/lib/ukiryu/shell.rb +60 -2
- data/lib/ukiryu/tool/command_resolution.rb +2 -1
- data/lib/ukiryu/tool/executable_discovery.rb +14 -15
- data/lib/ukiryu/tool/loader.rb +543 -0
- data/lib/ukiryu/tool/version_detection.rb +1 -3
- data/lib/ukiryu/tool.rb +79 -87
- data/lib/ukiryu/tool_index.rb +127 -62
- data/lib/ukiryu/tools/base.rb +4 -2
- data/lib/ukiryu/type.rb +26 -15
- data/lib/ukiryu/version.rb +1 -1
- data/lib/ukiryu.rb +1 -1
- data/spec/fixtures/profiles/ghostscript_10.0.yaml +50 -0
- data/spec/fixtures/register/tools/ghostscript/default/10.0.yaml +6 -0
- data/spec/spec_helper.rb +10 -6
- data/spec/support/tool_helper.rb +2 -0
- data/spec/ukiryu/definition/loader_spec.rb +2 -2
- data/spec/ukiryu/executor_spec.rb +6 -3
- data/spec/ukiryu/models/execution_report_spec.rb +3 -2
- data/spec/ukiryu/models/semantic_version_spec.rb +284 -0
- data/spec/ukiryu/shell/powershell_integration_spec.rb +165 -0
- data/spec/ukiryu/shell/powershell_real_command_spec.rb +143 -0
- data/spec/ukiryu/shell/powershell_spec.rb +228 -60
- data/spec/ukiryu/tool/loader_spec.rb +148 -0
- data/spec/ukiryu/tool_index_spec.rb +110 -18
- data/spec/ukiryu/tools/ghostscript_spec.rb +242 -0
- data/spec/ukiryu/tools/imagemagick_spec.rb +2 -1
- data/spec/ukiryu/tools/inkscape_spec.rb +4 -2
- metadata +14 -2
- data/lib/ukiryu/register_auto_manager.rb +0 -342
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '09496e921523ef4d99248688fee0293e542ff1cbfc7759403e062822d843f9ba'
|
|
4
|
+
data.tar.gz: 3e094dc9c7af3313d3d3e5d6179a491b037ce643ecf79d00715c5c6099f7b3e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d357286b89e3edaa8a495f965146effd6ffe06250f8f378c1e38ca6eef8d349abbe1698648e986c6bde2be52ff57637433ef6360175172e171d9db6155856fc4
|
|
7
|
+
data.tar.gz: b3cd0be008011acc0f659b77b651163b61af823e63af3e68486acdc82beb82d074b6a0cb84a21ea299c813e1c201d3089123dc83e687a3366f12ce3cd10318b6
|
data/lib/ukiryu/cache.rb
CHANGED
|
@@ -50,6 +50,12 @@ module Ukiryu
|
|
|
50
50
|
@mutex = Mutex.new if thread_safe
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
# @return [Integer] maximum cache size
|
|
54
|
+
attr_reader :max_size
|
|
55
|
+
|
|
56
|
+
# @return [Integer, nil] time-to-live in seconds
|
|
57
|
+
attr_reader :ttl
|
|
58
|
+
|
|
53
59
|
# Get a value from the cache
|
|
54
60
|
#
|
|
55
61
|
# @param key [Object] the cache key
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ukiryu
|
|
4
|
+
# Centralized cache registry for managing all Ukiryu caches.
|
|
5
|
+
#
|
|
6
|
+
# Provides a single point of control for:
|
|
7
|
+
# - Clearing all caches (useful for testing)
|
|
8
|
+
# - Getting cache statistics (useful for debugging)
|
|
9
|
+
# - Accessing individual caches by name
|
|
10
|
+
#
|
|
11
|
+
# @example Clear all caches
|
|
12
|
+
# Ukiryu::CacheRegistry.clear_all
|
|
13
|
+
#
|
|
14
|
+
# @example Get cache statistics
|
|
15
|
+
# Ukiryu::CacheRegistry.stats
|
|
16
|
+
# # => { tool_cache: { size: 10, hits: 100, misses: 5 }, ... }
|
|
17
|
+
#
|
|
18
|
+
module CacheRegistry
|
|
19
|
+
class << self
|
|
20
|
+
# Get all registered caches
|
|
21
|
+
#
|
|
22
|
+
# @return [Array<Cache>] list of cache instances
|
|
23
|
+
def caches
|
|
24
|
+
[
|
|
25
|
+
ToolCache.cache,
|
|
26
|
+
Definition::Loader.profile_cache
|
|
27
|
+
].compact
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Clear all registered caches
|
|
31
|
+
#
|
|
32
|
+
# @return [void]
|
|
33
|
+
def clear_all
|
|
34
|
+
caches.each(&:clear)
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Get statistics for all caches
|
|
39
|
+
#
|
|
40
|
+
# @return [Hash] cache name => stats hash
|
|
41
|
+
def stats
|
|
42
|
+
{
|
|
43
|
+
tool_cache: cache_stats(ToolCache.cache),
|
|
44
|
+
definition_cache: cache_stats(Definition::Loader.profile_cache)
|
|
45
|
+
}.compact
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# Get stats for a single cache
|
|
51
|
+
#
|
|
52
|
+
# @param cache [Cache, nil] the cache instance
|
|
53
|
+
# @return [Hash, nil] stats hash or nil if cache is nil
|
|
54
|
+
def cache_stats(cache)
|
|
55
|
+
return nil unless cache
|
|
56
|
+
|
|
57
|
+
{
|
|
58
|
+
size: cache.size,
|
|
59
|
+
max_size: cache.max_size
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -36,7 +36,9 @@ module Ukiryu
|
|
|
36
36
|
register_path = custom_path || config.register || default_register_path
|
|
37
37
|
return unless register_path && Dir.exist?(register_path)
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
# Set UKIRYU_REGISTER env and reset the default register
|
|
40
|
+
ENV['UKIRYU_REGISTER'] = register_path
|
|
41
|
+
Ukiryu::Register.reset_default
|
|
40
42
|
end
|
|
41
43
|
|
|
42
44
|
# Apply CLI options to the Config instance
|
|
@@ -80,11 +82,10 @@ module Ukiryu
|
|
|
80
82
|
|
|
81
83
|
# Get the default register path
|
|
82
84
|
#
|
|
83
|
-
# @return [String, nil] the default register path
|
|
85
|
+
# @return [String, nil] the default register path
|
|
84
86
|
def default_register_path
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
rescue StandardError
|
|
87
|
+
Ukiryu::Register.default.path
|
|
88
|
+
rescue Ukiryu::Register::Error
|
|
88
89
|
nil
|
|
89
90
|
end
|
|
90
91
|
|
|
@@ -222,23 +222,20 @@ module Ukiryu
|
|
|
222
222
|
#
|
|
223
223
|
# @return [String] formatted register display
|
|
224
224
|
def format_register_display
|
|
225
|
-
|
|
225
|
+
register = Ukiryu::Register.default
|
|
226
|
+
info = register.info
|
|
226
227
|
|
|
227
|
-
|
|
228
|
-
when :ok
|
|
229
|
-
# Register exists and is valid
|
|
228
|
+
if info[:valid]
|
|
230
229
|
source_label = format_source_label(info[:source])
|
|
231
230
|
tools_count = info[:tools_count] ? " (#{info[:tools_count]} tools)" : ''
|
|
232
231
|
"#{info[:path]} [#{source_label}]#{tools_count}"
|
|
233
|
-
|
|
234
|
-
# Register not cloned yet
|
|
235
|
-
'~/.ukiryu/register (not found - run: ukiryu register update)'
|
|
236
|
-
when :invalid
|
|
237
|
-
# Register exists but is invalid
|
|
232
|
+
elsif info[:exists]
|
|
238
233
|
"#{info[:path]} (invalid - run: ukiryu register update --force)"
|
|
239
234
|
else
|
|
240
|
-
'(
|
|
235
|
+
'~/.ukiryu/register (not found - run: ukiryu register update)'
|
|
241
236
|
end
|
|
237
|
+
rescue Ukiryu::Register::Error
|
|
238
|
+
'~/.ukiryu/register (not found - run: ukiryu register update)'
|
|
242
239
|
end
|
|
243
240
|
|
|
244
241
|
# Format source label for display
|
|
@@ -21,7 +21,7 @@ module Ukiryu
|
|
|
21
21
|
else
|
|
22
22
|
error!("Unknown subcommand: #{subcommand}. Valid subcommands: info, update, path")
|
|
23
23
|
end
|
|
24
|
-
rescue Ukiryu::
|
|
24
|
+
rescue Ukiryu::Register::Error => e
|
|
25
25
|
error!("Register error: #{e.message}")
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -31,21 +31,16 @@ module Ukiryu
|
|
|
31
31
|
#
|
|
32
32
|
# @param options [Hash] command options
|
|
33
33
|
def show_info(_options = {})
|
|
34
|
-
info = Ukiryu::
|
|
34
|
+
info = Ukiryu::Register.default.info
|
|
35
35
|
|
|
36
36
|
say 'Register Information', :cyan
|
|
37
37
|
say ''
|
|
38
38
|
|
|
39
|
-
case info
|
|
39
|
+
case determine_status(info)
|
|
40
40
|
when :not_found
|
|
41
41
|
say ' Status: Not configured', :red
|
|
42
42
|
say ''
|
|
43
43
|
say ' No register found. Run: ukiryu register update', :yellow
|
|
44
|
-
when :not_cloned
|
|
45
|
-
say ' Status: Not cloned', :yellow
|
|
46
|
-
say " Expected path: #{info[:path]}", :dim
|
|
47
|
-
say ''
|
|
48
|
-
say ' Run: ukiryu register update', :yellow
|
|
49
44
|
when :invalid
|
|
50
45
|
say ' Status: Invalid', :red
|
|
51
46
|
say " Path: #{info[:path]}", :dim
|
|
@@ -58,11 +53,14 @@ module Ukiryu
|
|
|
58
53
|
|
|
59
54
|
say " Tools available: #{info[:tools_count]}", :dim if info[:tools_count]
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
if info[:git_info]
|
|
57
|
+
say " Branch: #{info[:git_info][:branch]}", :dim if info[:git_info][:branch]
|
|
58
|
+
say " Commit: #{info[:git_info][:commit]}", :dim if info[:git_info][:commit]
|
|
59
|
+
if info[:git_info][:last_update]
|
|
60
|
+
say " Last updated: #{info[:git_info][:last_update].strftime('%Y-%m-%d %H:%M:%S')}",
|
|
61
|
+
:dim
|
|
62
|
+
end
|
|
63
|
+
end
|
|
66
64
|
end
|
|
67
65
|
|
|
68
66
|
say ''
|
|
@@ -74,7 +72,15 @@ module Ukiryu
|
|
|
74
72
|
say ' UKIRYU_REGISTER (not set)', :dim
|
|
75
73
|
end
|
|
76
74
|
|
|
77
|
-
show_manual_setup_help
|
|
75
|
+
show_manual_setup_help unless info[:valid]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Determine register status from info hash
|
|
79
|
+
def determine_status(info)
|
|
80
|
+
return :not_found unless info[:exists]
|
|
81
|
+
return :invalid unless info[:valid]
|
|
82
|
+
|
|
83
|
+
:ok
|
|
78
84
|
end
|
|
79
85
|
|
|
80
86
|
# Update the register
|
|
@@ -85,11 +91,14 @@ module Ukiryu
|
|
|
85
91
|
|
|
86
92
|
if force
|
|
87
93
|
say 'Force re-cloning register...', :yellow
|
|
94
|
+
FileUtils.rm_rf(Ukiryu::Register.default.path) if Dir.exist?(Ukiryu::Register.default.path)
|
|
95
|
+
Ukiryu::Register.reset_default
|
|
88
96
|
else
|
|
89
97
|
say 'Updating register...', :cyan
|
|
90
98
|
end
|
|
91
99
|
|
|
92
|
-
Ukiryu::
|
|
100
|
+
register = Ukiryu::Register.default
|
|
101
|
+
register.update!
|
|
93
102
|
|
|
94
103
|
say 'Register updated successfully!', :green
|
|
95
104
|
show_info(options)
|
|
@@ -97,9 +106,9 @@ module Ukiryu
|
|
|
97
106
|
|
|
98
107
|
# Show the register path
|
|
99
108
|
def show_path
|
|
100
|
-
path = Ukiryu::
|
|
109
|
+
path = Ukiryu::Register.default.path
|
|
101
110
|
|
|
102
|
-
if path
|
|
111
|
+
if path && Dir.exist?(path)
|
|
103
112
|
say path
|
|
104
113
|
else
|
|
105
114
|
error!('Register not available. Run: ukiryu register update')
|
|
@@ -129,7 +138,7 @@ module Ukiryu
|
|
|
129
138
|
say 'Manual setup:', :cyan
|
|
130
139
|
say ''
|
|
131
140
|
say ' 1. Clone the register:'
|
|
132
|
-
say
|
|
141
|
+
say ' git clone https://github.com/ukiryu/register ~/.ukiryu/register'
|
|
133
142
|
say ''
|
|
134
143
|
say ' 2. Or set environment variable:'
|
|
135
144
|
say ' export UKIRYU_REGISTER=/path/to/register'
|
|
@@ -163,7 +163,7 @@ module Ukiryu
|
|
|
163
163
|
#
|
|
164
164
|
# This method runs executable validation against all tool definitions
|
|
165
165
|
def test_all_executables
|
|
166
|
-
register_path = Ukiryu::
|
|
166
|
+
register_path = Ukiryu::Register.default.path
|
|
167
167
|
return say_error("Register not found: #{register_path}") unless Dir.exist?(register_path)
|
|
168
168
|
|
|
169
169
|
tools_dir = File.join(register_path, 'tools')
|
|
@@ -453,7 +453,7 @@ module Ukiryu
|
|
|
453
453
|
|
|
454
454
|
# Validate all definitions in register
|
|
455
455
|
def validate_all
|
|
456
|
-
register_path = Ukiryu::
|
|
456
|
+
register_path = Ukiryu::Register.default.path
|
|
457
457
|
return say_error("Register not found: #{register_path}") unless Dir.exist?(register_path)
|
|
458
458
|
|
|
459
459
|
tools_dir = File.join(register_path, 'tools')
|
|
@@ -17,11 +17,10 @@ module Ukiryu
|
|
|
17
17
|
def build_args(command, params)
|
|
18
18
|
args = []
|
|
19
19
|
|
|
20
|
-
# Debug logging for
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
end
|
|
20
|
+
# Debug logging for CI - log all params
|
|
21
|
+
Logger.debug("command: #{command.name}", category: :executable)
|
|
22
|
+
Logger.debug("params: #{params.inspect}", category: :executable)
|
|
23
|
+
Logger.debug("params.class: #{params.class}", category: :executable)
|
|
25
24
|
|
|
26
25
|
# Add subcommand prefix if present (e.g., for ImageMagick "magick convert")
|
|
27
26
|
args << command.subcommand if command.subcommand
|
|
@@ -45,6 +44,11 @@ module Ukiryu
|
|
|
45
44
|
next if params[param_key].nil?
|
|
46
45
|
|
|
47
46
|
formatted_opt = format_option(opt_def, params[param_key])
|
|
47
|
+
|
|
48
|
+
# Debug logging
|
|
49
|
+
Logger.debug("formatted_opt for #{param_key}: #{formatted_opt.inspect}",
|
|
50
|
+
category: :executable)
|
|
51
|
+
|
|
48
52
|
Array(formatted_opt).each { |opt| args << opt unless opt.nil? || opt.empty? }
|
|
49
53
|
end
|
|
50
54
|
|
|
@@ -65,12 +69,11 @@ module Ukiryu
|
|
|
65
69
|
last_arg = arguments.find(&:last?)
|
|
66
70
|
regular_args = arguments.reject(&:last?)
|
|
67
71
|
|
|
68
|
-
# Debug logging for
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
end
|
|
72
|
+
# Debug logging for arguments
|
|
73
|
+
Logger.debug("arguments: #{arguments.inspect}", category: :executable)
|
|
74
|
+
Logger.debug("regular_args: #{regular_args.map(&:name_sym).inspect}",
|
|
75
|
+
category: :executable)
|
|
76
|
+
Logger.debug("last_arg: #{last_arg&.name_sym.inspect}", category: :executable)
|
|
74
77
|
|
|
75
78
|
# Add regular positional arguments (in order, excluding "last")
|
|
76
79
|
regular_args.sort_by(&:numeric_position).each do |arg_def|
|
|
@@ -80,21 +83,17 @@ module Ukiryu
|
|
|
80
83
|
value = params[param_key]
|
|
81
84
|
next if value.nil?
|
|
82
85
|
|
|
83
|
-
# Debug logging
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
warn "[UKIRYU DEBUG CommandBuilder#build_args] arg_def.variadic: #{arg_def.variadic}"
|
|
89
|
-
end
|
|
86
|
+
# Debug logging
|
|
87
|
+
Logger.debug("param_key: #{param_key.inspect}", category: :executable)
|
|
88
|
+
Logger.debug("value.class: #{value.class}", category: :executable)
|
|
89
|
+
Logger.debug("value.inspect: #{value.inspect}", category: :executable)
|
|
90
|
+
Logger.debug("arg_def.variadic: #{arg_def.variadic}", category: :executable)
|
|
90
91
|
|
|
91
92
|
if arg_def.variadic
|
|
92
93
|
# Variadic argument - expand array
|
|
93
94
|
array = Ukiryu::Type.validate(value, :array, arg_def)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
warn "[UKIRYU DEBUG CommandBuilder#build_args] array.inspect: #{array.inspect}"
|
|
97
|
-
end
|
|
95
|
+
Logger.debug("array.class: #{array.class}", category: :executable)
|
|
96
|
+
Logger.debug("array.inspect: #{array.inspect}", category: :executable)
|
|
98
97
|
array.each { |v| args << format_arg(v, arg_def) }
|
|
99
98
|
else
|
|
100
99
|
args << format_arg(value, arg_def)
|
|
@@ -124,11 +123,12 @@ module Ukiryu
|
|
|
124
123
|
end
|
|
125
124
|
end
|
|
126
125
|
|
|
127
|
-
# Debug logging for
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
# Debug logging for final args
|
|
127
|
+
Logger.debug("Final args: #{args.inspect}", category: :executable)
|
|
128
|
+
Logger.debug("Args class: #{args.class}", category: :executable)
|
|
129
|
+
Logger.debug("Args size: #{args.size}", category: :executable)
|
|
130
|
+
args.each_with_index do |arg, i|
|
|
131
|
+
Logger.debug("args[#{i}]: #{arg.inspect} (#{arg.class})", category: :executable)
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
args
|
|
@@ -144,7 +144,7 @@ module Ukiryu
|
|
|
144
144
|
Ukiryu::Type.validate(value, arg_def.type || :string, arg_def)
|
|
145
145
|
|
|
146
146
|
# Apply platform-specific path formatting
|
|
147
|
-
if arg_def.type ==
|
|
147
|
+
if arg_def.type.to_s == 'file'
|
|
148
148
|
shell = Ukiryu::Shell::InstanceCache.instance_for(@shell)
|
|
149
149
|
shell.format_path(value.to_s)
|
|
150
150
|
else
|
|
@@ -161,6 +161,13 @@ module Ukiryu
|
|
|
161
161
|
# Validate type
|
|
162
162
|
Ukiryu::Type.validate(value, opt_def.type || :string, opt_def)
|
|
163
163
|
|
|
164
|
+
# Debug logging - trace the full option formatting
|
|
165
|
+
Logger.debug("opt_def.name: #{opt_def.name.inspect}", category: :executable)
|
|
166
|
+
Logger.debug("opt_def.cli: #{opt_def.cli.inspect}", category: :executable)
|
|
167
|
+
Logger.debug("opt_def.assignment_delimiter: #{opt_def.assignment_delimiter.inspect}",
|
|
168
|
+
category: :executable)
|
|
169
|
+
Logger.debug("value: #{value.inspect} (#{value.class})", category: :executable)
|
|
170
|
+
|
|
164
171
|
# Handle boolean types - just return the CLI flag (no value)
|
|
165
172
|
type_val = opt_def.type
|
|
166
173
|
if [:boolean, TrueClass, 'boolean'].include?(type_val)
|
|
@@ -173,27 +180,55 @@ module Ukiryu
|
|
|
173
180
|
delimiter_sym = opt_def.assignment_delimiter_sym
|
|
174
181
|
separator = opt_def.separator || '='
|
|
175
182
|
|
|
183
|
+
Logger.debug("cli variable: #{cli.inspect}", category: :executable)
|
|
184
|
+
Logger.debug("delimiter_sym: #{delimiter_sym.inspect}", category: :executable)
|
|
185
|
+
|
|
176
186
|
# Auto-detect delimiter based on CLI prefix
|
|
177
187
|
delimiter_sym = detect_delimiter(cli) if delimiter_sym == :auto
|
|
178
188
|
|
|
179
|
-
|
|
180
|
-
|
|
189
|
+
Logger.debug("delimiter_sym after detect: #{delimiter_sym.inspect}",
|
|
190
|
+
category: :executable)
|
|
191
|
+
|
|
192
|
+
# Convert value to string (handle symbols and file paths)
|
|
193
|
+
if value.is_a?(Symbol)
|
|
194
|
+
value_str = value.to_s
|
|
195
|
+
elsif opt_def.type.to_s == 'file'
|
|
196
|
+
# Apply platform-specific path formatting for file types
|
|
197
|
+
shell_instance = Ukiryu::Shell::InstanceCache.instance_for(@shell)
|
|
198
|
+
Logger.debug("FILE type detected: opt_def.name=#{opt_def.name}, value=#{value.inspect}",
|
|
199
|
+
category: :executable)
|
|
200
|
+
Logger.debug("@shell=#{@shell.inspect}, shell_instance=#{shell_instance.class}",
|
|
201
|
+
category: :executable)
|
|
202
|
+
Logger.debug("Platform.windows?=#{Ukiryu::Platform.windows? if defined?(Ukiryu::Platform)}",
|
|
203
|
+
category: :executable)
|
|
204
|
+
value_str = shell_instance.format_path(value.to_s)
|
|
205
|
+
Logger.debug("format_path result: #{value_str.inspect}", category: :executable)
|
|
206
|
+
else
|
|
207
|
+
value_str = value.to_s
|
|
208
|
+
end
|
|
181
209
|
|
|
182
210
|
# Handle array values with separator
|
|
183
211
|
if value.is_a?(Array) && separator
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
212
|
+
# Apply path formatting to each element if type is file
|
|
213
|
+
formatted_values = if opt_def.type.to_s == 'file'
|
|
214
|
+
shell_instance ||= Ukiryu::Shell::InstanceCache.instance_for(@shell)
|
|
215
|
+
value.map { |v| shell_instance.format_path(v.to_s) }
|
|
216
|
+
else
|
|
217
|
+
value.map(&:to_s)
|
|
218
|
+
end
|
|
219
|
+
joined = formatted_values.join(separator)
|
|
220
|
+
result = case delimiter_sym
|
|
221
|
+
when :equals
|
|
222
|
+
"#{cli}=#{joined}"
|
|
223
|
+
when :space
|
|
224
|
+
[cli, joined] # Return array for space-separated
|
|
225
|
+
when :colon
|
|
226
|
+
"#{cli}:#{joined}"
|
|
227
|
+
when :none
|
|
228
|
+
cli
|
|
229
|
+
else
|
|
230
|
+
"#{cli}=#{joined}"
|
|
231
|
+
end
|
|
197
232
|
else
|
|
198
233
|
result = case delimiter_sym
|
|
199
234
|
when :equals
|
|
@@ -207,15 +242,13 @@ module Ukiryu
|
|
|
207
242
|
else
|
|
208
243
|
"#{cli}=#{value_str}"
|
|
209
244
|
end
|
|
245
|
+
end
|
|
210
246
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
warn "[UKIRYU DEBUG format_option] result.class: #{result.class}"
|
|
215
|
-
end
|
|
247
|
+
# Debug logging for result
|
|
248
|
+
Logger.debug("FINAL result: #{result.inspect}", category: :executable)
|
|
249
|
+
Logger.debug("result.class: #{result.class}", category: :executable)
|
|
216
250
|
|
|
217
|
-
|
|
218
|
-
end
|
|
251
|
+
result
|
|
219
252
|
end
|
|
220
253
|
|
|
221
254
|
# Detect assignment delimiter based on CLI prefix
|
data/lib/ukiryu/config.rb
CHANGED
|
@@ -33,7 +33,9 @@ module Ukiryu
|
|
|
33
33
|
|
|
34
34
|
class << self
|
|
35
35
|
def instance
|
|
36
|
-
|
|
36
|
+
mutex.synchronize do
|
|
37
|
+
@instance ||= new
|
|
38
|
+
end
|
|
37
39
|
end
|
|
38
40
|
|
|
39
41
|
# Configure Ukiryu with a block
|
|
@@ -46,7 +48,9 @@ module Ukiryu
|
|
|
46
48
|
|
|
47
49
|
# Reset configuration to defaults
|
|
48
50
|
def reset!
|
|
49
|
-
|
|
51
|
+
mutex.synchronize do
|
|
52
|
+
@instance = new
|
|
53
|
+
end
|
|
50
54
|
end
|
|
51
55
|
|
|
52
56
|
# Delegate to instance
|
|
@@ -57,6 +61,13 @@ module Ukiryu
|
|
|
57
61
|
def respond_to_missing?(method, include_private = false)
|
|
58
62
|
instance.respond_to?(method) || super
|
|
59
63
|
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
# Mutex for thread-safe singleton access
|
|
68
|
+
def mutex
|
|
69
|
+
@mutex ||= Mutex.new
|
|
70
|
+
end
|
|
60
71
|
end
|
|
61
72
|
|
|
62
73
|
# @!attribute [r] resolver
|
data/lib/ukiryu/debug.rb
CHANGED
|
@@ -12,24 +12,35 @@ module Ukiryu
|
|
|
12
12
|
#
|
|
13
13
|
# @example Disable debug logging (default)
|
|
14
14
|
# Ukiryu.debug_enabled? # => false
|
|
15
|
+
#
|
|
16
|
+
# @example Log with category
|
|
17
|
+
# Ukiryu::Debug.log("Found executable", category: :executable)
|
|
15
18
|
module Debug
|
|
16
19
|
class << self
|
|
17
|
-
# Check if debug logging is enabled
|
|
18
|
-
#
|
|
19
|
-
# Debug is enabled ONLY when UKIRYU_DEBUG environment variable is set.
|
|
20
|
-
# The ENV['CI'] check was removed to prevent debug output from polluting
|
|
21
|
-
# JSON/YAML output in automated tests.
|
|
20
|
+
# Check if debug logging is enabled for a category
|
|
22
21
|
#
|
|
22
|
+
# @param category [Symbol, nil] the category (:executable for UKIRYU_DEBUG_EXECUTABLE)
|
|
23
23
|
# @return [Boolean] true if debug mode is enabled
|
|
24
|
-
def enabled?
|
|
25
|
-
|
|
24
|
+
def enabled?(category = nil)
|
|
25
|
+
case category
|
|
26
|
+
when :executable
|
|
27
|
+
ENV['UKIRYU_DEBUG_EXECUTABLE'] || (defined?(Platform) && Platform.windows? && ENV['CI'])
|
|
28
|
+
else
|
|
29
|
+
ENV['UKIRYU_DEBUG'] || ENV['UKIRYU_DEBUG_EXECUTABLE']
|
|
30
|
+
end
|
|
26
31
|
end
|
|
27
32
|
|
|
28
33
|
# Log a debug message to stderr
|
|
29
34
|
#
|
|
30
35
|
# @param message [String] the debug message
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
# @param category [Symbol, nil] optional category (:executable for executable discovery)
|
|
37
|
+
# @param context [Hash] optional context data
|
|
38
|
+
def log(message, category: nil, context: {})
|
|
39
|
+
return unless enabled?(category)
|
|
40
|
+
|
|
41
|
+
prefix = "[UKIRYU DEBUG#{category ? " #{category.to_s.upcase}" : ''}]"
|
|
42
|
+
details = context.empty? ? '' : " (#{context.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')})"
|
|
43
|
+
warn "#{prefix} #{message}#{details}"
|
|
33
44
|
end
|
|
34
45
|
end
|
|
35
46
|
end
|
|
@@ -60,11 +60,11 @@ module Ukiryu
|
|
|
60
60
|
load_from_source(source, options)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
# Get the profile cache
|
|
63
|
+
# Get the profile cache (bounded LRU cache)
|
|
64
64
|
#
|
|
65
|
-
# @return [
|
|
65
|
+
# @return [Cache] the profile cache
|
|
66
66
|
def profile_cache
|
|
67
|
-
@profile_cache ||=
|
|
67
|
+
@profile_cache ||= Cache.new(max_size: 100, ttl: 3600)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
# Clear the profile cache
|