ukiryu 0.1.0 → 0.1.1
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/docs.yml +63 -0
- data/.github/workflows/links.yml +99 -0
- data/.github/workflows/rake.yml +19 -0
- data/.github/workflows/release.yml +27 -0
- data/.gitignore +18 -4
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +213 -0
- data/Gemfile +12 -8
- data/README.adoc +613 -0
- data/Rakefile +2 -2
- data/docs/assets/logo.svg +1 -0
- data/exe/ukiryu +11 -0
- data/lib/ukiryu/action/base.rb +77 -0
- data/lib/ukiryu/cache.rb +199 -0
- data/lib/ukiryu/cli.rb +133 -307
- data/lib/ukiryu/cli_commands/base_command.rb +155 -0
- data/lib/ukiryu/cli_commands/commands_command.rb +120 -0
- data/lib/ukiryu/cli_commands/commands_command.rb.fixed +40 -0
- data/lib/ukiryu/cli_commands/config_command.rb +249 -0
- data/lib/ukiryu/cli_commands/describe_command.rb +326 -0
- data/lib/ukiryu/cli_commands/describe_command.rb.fixed +254 -0
- data/lib/ukiryu/cli_commands/exec_inline_command.rb.fixed +180 -0
- data/lib/ukiryu/cli_commands/extract_command.rb +84 -0
- data/lib/ukiryu/cli_commands/info_command.rb +156 -0
- data/lib/ukiryu/cli_commands/list_command.rb +70 -0
- data/lib/ukiryu/cli_commands/opts_command.rb +106 -0
- data/lib/ukiryu/cli_commands/opts_command.rb.fixed +105 -0
- data/lib/ukiryu/cli_commands/response_formatter.rb +240 -0
- data/lib/ukiryu/cli_commands/run_command.rb +375 -0
- data/lib/ukiryu/cli_commands/run_file_command.rb +215 -0
- data/lib/ukiryu/cli_commands/system_command.rb +90 -0
- data/lib/ukiryu/cli_commands/validate_command.rb +87 -0
- data/lib/ukiryu/cli_commands/version_command.rb +16 -0
- data/lib/ukiryu/cli_commands/which_command.rb +166 -0
- data/lib/ukiryu/command_builder.rb +205 -0
- data/lib/ukiryu/config/env_provider.rb +64 -0
- data/lib/ukiryu/config/env_schema.rb +63 -0
- data/lib/ukiryu/config/override_resolver.rb +68 -0
- data/lib/ukiryu/config/type_converter.rb +59 -0
- data/lib/ukiryu/config.rb +249 -0
- data/lib/ukiryu/errors.rb +3 -0
- data/lib/ukiryu/executable_locator.rb +114 -0
- data/lib/ukiryu/execution/command_info.rb +64 -0
- data/lib/ukiryu/execution/metadata.rb +97 -0
- data/lib/ukiryu/execution/output.rb +144 -0
- data/lib/ukiryu/execution/result.rb +194 -0
- data/lib/ukiryu/execution.rb +15 -0
- data/lib/ukiryu/execution_context.rb +251 -0
- data/lib/ukiryu/executor.rb +76 -493
- data/lib/ukiryu/extractors/base_extractor.rb +63 -0
- data/lib/ukiryu/extractors/extractor.rb +150 -0
- data/lib/ukiryu/extractors/help_parser.rb +188 -0
- data/lib/ukiryu/extractors/native_extractor.rb +47 -0
- data/lib/ukiryu/io.rb +196 -0
- data/lib/ukiryu/logger.rb +544 -0
- data/lib/ukiryu/models/argument.rb +28 -0
- data/lib/ukiryu/models/argument_definition.rb +119 -0
- data/lib/ukiryu/models/arguments.rb +113 -0
- data/lib/ukiryu/models/command_definition.rb +176 -0
- data/lib/ukiryu/models/command_info.rb +37 -0
- data/lib/ukiryu/models/components.rb +107 -0
- data/lib/ukiryu/models/env_var_definition.rb +30 -0
- data/lib/ukiryu/models/error_response.rb +41 -0
- data/lib/ukiryu/models/execution_metadata.rb +31 -0
- data/lib/ukiryu/models/execution_report.rb +236 -0
- data/lib/ukiryu/models/exit_codes.rb +74 -0
- data/lib/ukiryu/models/flag_definition.rb +67 -0
- data/lib/ukiryu/models/option_definition.rb +102 -0
- data/lib/ukiryu/models/output_info.rb +25 -0
- data/lib/ukiryu/models/platform_profile.rb +153 -0
- data/lib/ukiryu/models/routing.rb +211 -0
- data/lib/ukiryu/models/search_paths.rb +39 -0
- data/lib/ukiryu/models/success_response.rb +85 -0
- data/lib/ukiryu/models/tool_definition.rb +145 -0
- data/lib/ukiryu/models/tool_metadata.rb +82 -0
- data/lib/ukiryu/models/validation_result.rb +80 -0
- data/lib/ukiryu/models/version_compatibility.rb +152 -0
- data/lib/ukiryu/models/version_detection.rb +39 -0
- data/lib/ukiryu/models.rb +23 -0
- data/lib/ukiryu/options/base.rb +95 -0
- data/lib/ukiryu/options_builder/formatter.rb +87 -0
- data/lib/ukiryu/options_builder/validator.rb +43 -0
- data/lib/ukiryu/options_builder.rb +311 -0
- data/lib/ukiryu/platform.rb +6 -6
- data/lib/ukiryu/registry.rb +143 -183
- data/lib/ukiryu/response/base.rb +217 -0
- data/lib/ukiryu/runtime.rb +179 -0
- data/lib/ukiryu/schema_validator.rb +8 -10
- data/lib/ukiryu/shell/bash.rb +3 -3
- data/lib/ukiryu/shell/cmd.rb +4 -4
- data/lib/ukiryu/shell/fish.rb +1 -1
- data/lib/ukiryu/shell/powershell.rb +3 -3
- data/lib/ukiryu/shell/sh.rb +1 -1
- data/lib/ukiryu/shell/zsh.rb +1 -1
- data/lib/ukiryu/shell.rb +146 -39
- data/lib/ukiryu/thor_ext.rb +208 -0
- data/lib/ukiryu/tool.rb +649 -258
- data/lib/ukiryu/tool_index.rb +224 -0
- data/lib/ukiryu/tools/base.rb +381 -0
- data/lib/ukiryu/tools/class_generator.rb +132 -0
- data/lib/ukiryu/tools/executable_finder.rb +29 -0
- data/lib/ukiryu/tools/generator.rb +154 -0
- data/lib/ukiryu/tools.rb +109 -0
- data/lib/ukiryu/type.rb +28 -43
- data/lib/ukiryu/validation/constraints.rb +281 -0
- data/lib/ukiryu/validation/validator.rb +188 -0
- data/lib/ukiryu/validation.rb +21 -0
- data/lib/ukiryu/version.rb +1 -1
- data/lib/ukiryu/version_detector.rb +51 -0
- data/lib/ukiryu.rb +31 -15
- data/ukiryu-proposal.md +2952 -0
- data/ukiryu.gemspec +18 -14
- metadata +137 -5
- data/.github/workflows/test.yml +0 -143
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_command'
|
|
4
|
+
require_relative '../tool'
|
|
5
|
+
|
|
6
|
+
module Ukiryu
|
|
7
|
+
module CliCommands
|
|
8
|
+
# List all commands available for a tool
|
|
9
|
+
class CommandsCommand < BaseCommand
|
|
10
|
+
# Execute the commands command
|
|
11
|
+
#
|
|
12
|
+
# @param tool_name [String] the tool name
|
|
13
|
+
def run(tool_name)
|
|
14
|
+
setup_registry
|
|
15
|
+
|
|
16
|
+
# Use find_by for interface-based discovery (ping -> ping_bsd/ping_gnu)
|
|
17
|
+
tool = Tool.find_by(tool_name.to_sym)
|
|
18
|
+
error!("Tool not found: #{tool_name}\nAvailable tools: #{Registry.tools.sort.join(', ')}") unless tool
|
|
19
|
+
|
|
20
|
+
tool_commands = tool.commands
|
|
21
|
+
error! "No commands defined for #{tool_name}" unless tool_commands
|
|
22
|
+
|
|
23
|
+
say "Commands for #{tool_name}:", :cyan
|
|
24
|
+
|
|
25
|
+
# Group commands by their parent (belongs_to) for hierarchical tools
|
|
26
|
+
grouped = group_commands_by_parent(tool_commands)
|
|
27
|
+
|
|
28
|
+
if grouped.key?(nil) && grouped.size == 1
|
|
29
|
+
# Flat structure - no routing/hierarchy
|
|
30
|
+
grouped[nil].each do |cmd|
|
|
31
|
+
display_command(cmd)
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
# Hierarchical structure - show routing groups
|
|
35
|
+
display_hierarchical_commands(tool, grouped)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
# Group commands by their parent (belongs_to)
|
|
42
|
+
#
|
|
43
|
+
# @param commands [Array] list of commands
|
|
44
|
+
# @return [Hash] grouped commands with nil key for top-level
|
|
45
|
+
#
|
|
46
|
+
def group_commands_by_parent(commands)
|
|
47
|
+
grouped = Hash.new { |h, k| h[k] = [] }
|
|
48
|
+
|
|
49
|
+
commands.each do |cmd|
|
|
50
|
+
parent = cmd.belongs_to
|
|
51
|
+
grouped[parent] << cmd
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
grouped
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Display a single command
|
|
58
|
+
#
|
|
59
|
+
# @param cmd [CommandDefinition] the command to display
|
|
60
|
+
#
|
|
61
|
+
def display_command(cmd)
|
|
62
|
+
cmd_name = cmd.name || 'unnamed'
|
|
63
|
+
description = cmd.description || 'No description'
|
|
64
|
+
say " #{cmd_name.to_s.ljust(20)} #{description}", :white
|
|
65
|
+
|
|
66
|
+
# Show usage if available
|
|
67
|
+
say " Usage: #{cmd.usage}", :dim if cmd.usage
|
|
68
|
+
|
|
69
|
+
# Show subcommand if exists
|
|
70
|
+
if cmd.subcommand
|
|
71
|
+
subcommand_info = cmd.subcommand.nil? ? '(none)' : cmd.subcommand
|
|
72
|
+
say " Subcommand: #{subcommand_info}", :dim
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Show cli_flag if this is a flag-based action
|
|
76
|
+
if cmd.flag_action?
|
|
77
|
+
say " Action flag: #{cmd.cli_flag}", :dim
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Display hierarchical commands with routing information
|
|
82
|
+
#
|
|
83
|
+
# @param tool [Tool] the tool instance
|
|
84
|
+
# @param grouped [Hash] grouped commands
|
|
85
|
+
#
|
|
86
|
+
def display_hierarchical_commands(tool, grouped)
|
|
87
|
+
# Show routing table first
|
|
88
|
+
if tool.routing?
|
|
89
|
+
say " Routing table:", :dim
|
|
90
|
+
tool.routing.keys.each do |key|
|
|
91
|
+
target = tool.routing.resolve(key)
|
|
92
|
+
say " #{key} => #{target}", :dim
|
|
93
|
+
end
|
|
94
|
+
say '', :clear
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Show top-level commands (no belongs_to)
|
|
98
|
+
if grouped.key?(nil) && !grouped[nil].empty?
|
|
99
|
+
say " Top-level commands:", :cyan
|
|
100
|
+
grouped[nil].each do |cmd|
|
|
101
|
+
display_command(cmd)
|
|
102
|
+
end
|
|
103
|
+
say '', :clear
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Show commands grouped by parent
|
|
107
|
+
grouped.each do |parent, cmds|
|
|
108
|
+
next if parent.nil?
|
|
109
|
+
|
|
110
|
+
target = tool.routing&.resolve(parent) || parent
|
|
111
|
+
say " #{parent} commands (route to: #{target}):", :cyan
|
|
112
|
+
cmds.each do |cmd|
|
|
113
|
+
display_command(cmd)
|
|
114
|
+
end
|
|
115
|
+
say '', :clear
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_command'
|
|
4
|
+
require_relative '../tool'
|
|
5
|
+
|
|
6
|
+
module Ukiryu
|
|
7
|
+
module CliCommands
|
|
8
|
+
# List all commands available for a tool
|
|
9
|
+
class CommandsCommand < BaseCommand
|
|
10
|
+
# Execute the commands command
|
|
11
|
+
#
|
|
12
|
+
# @param tool_name [String] the tool name
|
|
13
|
+
def run(tool_name)
|
|
14
|
+
setup_registry
|
|
15
|
+
|
|
16
|
+
tool = Tool.get(tool_name)
|
|
17
|
+
tool_commands = tool.commands
|
|
18
|
+
|
|
19
|
+
error! "No commands defined for #{tool_name}" unless tool_commands
|
|
20
|
+
|
|
21
|
+
say "Commands for #{tool_name}:", :cyan
|
|
22
|
+
tool_commands.each do |cmd_name, cmd|
|
|
23
|
+
cmd_name ||= 'unnamed'
|
|
24
|
+
description = cmd.description || 'No description'
|
|
25
|
+
say " #{cmd_name.to_s.ljust(20)} #{description}", :white
|
|
26
|
+
|
|
27
|
+
# Show usage if available
|
|
28
|
+
say " Usage: #{cmd.usage}", :dim if cmd.usage
|
|
29
|
+
|
|
30
|
+
# Show subcommand if exists
|
|
31
|
+
if cmd.subcommand
|
|
32
|
+
subcommand_info = cmd.subcommand.nil? ? '(none)' : cmd.subcommand
|
|
33
|
+
say " Subcommand: #{subcommand_info}", :dim
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_command'
|
|
4
|
+
require_relative '../config'
|
|
5
|
+
require 'yaml'
|
|
6
|
+
require 'fileutils'
|
|
7
|
+
|
|
8
|
+
module Ukiryu
|
|
9
|
+
module CliCommands
|
|
10
|
+
# Configuration management command
|
|
11
|
+
class ConfigCommand < BaseCommand
|
|
12
|
+
CONFIG_DIR = File.expand_path('~/.ukiryu')
|
|
13
|
+
CONFIG_FILE = File.join(CONFIG_DIR, 'config.yml')
|
|
14
|
+
|
|
15
|
+
# Execute the config command
|
|
16
|
+
#
|
|
17
|
+
# @param action [String] the action (list, get, set, unset)
|
|
18
|
+
# @param key [String, nil] the config key
|
|
19
|
+
# @param value [String, nil] the config value
|
|
20
|
+
def run(action = 'list', key = nil, value = nil)
|
|
21
|
+
setup_registry
|
|
22
|
+
|
|
23
|
+
case action
|
|
24
|
+
when 'list'
|
|
25
|
+
action_list
|
|
26
|
+
when 'get'
|
|
27
|
+
action_get(key)
|
|
28
|
+
when 'set'
|
|
29
|
+
action_set(key, value)
|
|
30
|
+
when 'unset'
|
|
31
|
+
action_unset(key)
|
|
32
|
+
else
|
|
33
|
+
error! "Unknown action: #{action}\nValid actions: list, get, set, unset"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
# List all configuration
|
|
40
|
+
def action_list
|
|
41
|
+
say 'Current configuration:', :cyan
|
|
42
|
+
say '', :clear
|
|
43
|
+
|
|
44
|
+
config_data = {
|
|
45
|
+
'Registry' => config.registry || '(not set)',
|
|
46
|
+
'Timeout' => format_config_value(config.timeout, '(no timeout)'),
|
|
47
|
+
'Debug' => format_config_value(config.debug),
|
|
48
|
+
'Dry run' => format_config_value(config.dry_run),
|
|
49
|
+
'Metrics' => format_config_value(config.metrics),
|
|
50
|
+
'Shell' => format_config_value(config.shell, '(auto-detect)'),
|
|
51
|
+
'Format' => format_config_value(config.format),
|
|
52
|
+
'Output' => format_config_value(config.output, '(stdout)'),
|
|
53
|
+
'Search paths' => format_config_value(config.search_paths, '(not set)'),
|
|
54
|
+
'Use color' => format_config_value(config.use_color, '(auto-detect)')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
config_data.each do |k, v|
|
|
58
|
+
value_str = v.is_a?(String) ? "'#{v}'" : v.to_s
|
|
59
|
+
say " #{k.ljust(20)}: #{value_str}", :white
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Show persistent config if exists
|
|
63
|
+
say '', :clear
|
|
64
|
+
if File.exist?(CONFIG_FILE)
|
|
65
|
+
say 'Persistent configuration:', :cyan
|
|
66
|
+
say " File: #{CONFIG_FILE}", :dim
|
|
67
|
+
|
|
68
|
+
persistent = load_persistent_config
|
|
69
|
+
if persistent && !persistent.empty?
|
|
70
|
+
persistent.each do |k, v|
|
|
71
|
+
say " #{k}: #{v}", :dim
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
say ' (empty)', :dim
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
say 'No persistent configuration file found.', :dim
|
|
78
|
+
say " Config would be saved to: #{CONFIG_FILE}", :dim
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Show environment variables
|
|
82
|
+
say '', :clear
|
|
83
|
+
say 'Environment variables:', :cyan
|
|
84
|
+
env_vars = {
|
|
85
|
+
'UKIRYU_REGISTRY' => ENV['UKIRYU_REGISTRY'],
|
|
86
|
+
'UKIRYU_TIMEOUT' => ENV['UKIRYU_TIMEOUT'],
|
|
87
|
+
'UKIRYU_DEBUG' => ENV['UKIRYU_DEBUG'],
|
|
88
|
+
'UKIRYU_DRY_RUN' => ENV['UKIRYU_DRY_RUN'],
|
|
89
|
+
'UKIRYU_METRICS' => ENV['UKIRYU_METRICS'],
|
|
90
|
+
'UKIRYU_SHELL' => ENV['UKIRYU_SHELL'],
|
|
91
|
+
'UKIRYU_FORMAT' => ENV['UKIRYU_FORMAT'],
|
|
92
|
+
'UKIRYU_OUTPUT' => ENV['UKIRYU_OUTPUT'],
|
|
93
|
+
'UKIRYU_SEARCH_PATHS' => ENV['UKIRYU_SEARCH_PATHS'],
|
|
94
|
+
'UKIRYU_USE_COLOR' => ENV['UKIRYU_USE_COLOR']
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
has_env = false
|
|
98
|
+
env_vars.each do |k, v|
|
|
99
|
+
if v
|
|
100
|
+
has_env = true
|
|
101
|
+
say " #{k.ljust(25)}: #{v}", :white
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
say ' (none set)', :dim unless has_env
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Get a configuration value
|
|
108
|
+
#
|
|
109
|
+
# @param key [String] the config key
|
|
110
|
+
def action_get(key)
|
|
111
|
+
normalized_key = normalize_key(key)
|
|
112
|
+
|
|
113
|
+
value = case normalized_key
|
|
114
|
+
when :registry then config.registry
|
|
115
|
+
when :timeout then config.timeout
|
|
116
|
+
when :debug then config.debug
|
|
117
|
+
when :dry_run then config.dry_run
|
|
118
|
+
when :metrics then config.metrics
|
|
119
|
+
when :shell then config.shell
|
|
120
|
+
when :format then config.format
|
|
121
|
+
when :output then config.output
|
|
122
|
+
when :search_paths then config.search_paths
|
|
123
|
+
when :use_color then config.use_color
|
|
124
|
+
else
|
|
125
|
+
error! "Unknown config key: #{key}\nValid keys: registry, timeout, debug, dry_run, metrics, shell, format, output, search_paths, use_color"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
say "#{key}: #{format_config_value(value, '(not set)')}", :white
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Set a configuration value (persisted to file)
|
|
132
|
+
#
|
|
133
|
+
# @param key [String] the config key
|
|
134
|
+
# @param value [String] the config value
|
|
135
|
+
def action_set(key, value)
|
|
136
|
+
error! 'Usage: ukiryu config set <key> <value>' unless key && value
|
|
137
|
+
|
|
138
|
+
normalized_key = normalize_key(key)
|
|
139
|
+
parsed_value = parse_value(normalized_key, value)
|
|
140
|
+
|
|
141
|
+
# Save to persistent config
|
|
142
|
+
ensure_config_dir
|
|
143
|
+
persistent = load_persistent_config || {}
|
|
144
|
+
persistent[key] = value
|
|
145
|
+
save_persistent_config(persistent)
|
|
146
|
+
|
|
147
|
+
# Also set in current config
|
|
148
|
+
set_config_value(normalized_key, parsed_value)
|
|
149
|
+
|
|
150
|
+
say "Set #{key} = #{value}", :green
|
|
151
|
+
say "Saved to: #{CONFIG_FILE}", :dim
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Unset a configuration value
|
|
155
|
+
#
|
|
156
|
+
# @param key [String] the config key
|
|
157
|
+
def action_unset(key)
|
|
158
|
+
error! 'Usage: ukiryu config unset <key>' unless key
|
|
159
|
+
|
|
160
|
+
persistent = load_persistent_config
|
|
161
|
+
error! "Key not set in persistent config: #{key}" unless persistent&.key?(key)
|
|
162
|
+
|
|
163
|
+
persistent.delete(key)
|
|
164
|
+
save_persistent_config(persistent)
|
|
165
|
+
|
|
166
|
+
say "Unset #{key}", :green
|
|
167
|
+
say "Updated: #{CONFIG_FILE}", :dim
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Normalize key to symbol
|
|
171
|
+
#
|
|
172
|
+
# @param key [String] the key
|
|
173
|
+
# @return [Symbol] normalized key
|
|
174
|
+
def normalize_key(key)
|
|
175
|
+
key.to_s.downcase.to_sym
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Parse value based on key type
|
|
179
|
+
#
|
|
180
|
+
# @param key [Symbol] the config key
|
|
181
|
+
# @param value [String] the string value
|
|
182
|
+
# @return [Object] parsed value
|
|
183
|
+
def parse_value(key, value)
|
|
184
|
+
case key
|
|
185
|
+
when :timeout
|
|
186
|
+
value.to_i
|
|
187
|
+
when :debug, :dry_run, :metrics, :use_color
|
|
188
|
+
%w[true yes 1].include?(value.downcase)
|
|
189
|
+
when :format
|
|
190
|
+
value.to_sym
|
|
191
|
+
else
|
|
192
|
+
value
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Set config value
|
|
197
|
+
#
|
|
198
|
+
# @param key [Symbol] the config key
|
|
199
|
+
# @param value [Object] the value
|
|
200
|
+
def set_config_value(key, value)
|
|
201
|
+
case key
|
|
202
|
+
when :timeout then config.timeout = value
|
|
203
|
+
when :debug then config.debug = value
|
|
204
|
+
when :dry_run then config.dry_run = value
|
|
205
|
+
when :metrics then config.metrics = value
|
|
206
|
+
when :shell then config.shell = value
|
|
207
|
+
when :format then config.format = value
|
|
208
|
+
when :output then config.output = value
|
|
209
|
+
when :registry then config.registry = value
|
|
210
|
+
when :search_paths then config.search_paths = value
|
|
211
|
+
when :use_color then config.use_color = value
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Format config value for display
|
|
216
|
+
#
|
|
217
|
+
# @param value [Object] the value
|
|
218
|
+
# @param default [String] default string for nil
|
|
219
|
+
# @return [String] formatted value
|
|
220
|
+
def format_config_value(value, default = '(nil)')
|
|
221
|
+
value.nil? ? default : value
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Ensure config directory exists
|
|
225
|
+
def ensure_config_dir
|
|
226
|
+
FileUtils.mkdir_p(CONFIG_DIR) unless Dir.exist?(CONFIG_DIR)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Load persistent config from file
|
|
230
|
+
#
|
|
231
|
+
# @return [Hash, nil] the persistent config or nil
|
|
232
|
+
def load_persistent_config
|
|
233
|
+
return nil unless File.exist?(CONFIG_FILE)
|
|
234
|
+
|
|
235
|
+
YAML.load_file(CONFIG_FILE, permitted_classes: [Symbol])
|
|
236
|
+
rescue StandardError => e
|
|
237
|
+
say "Warning: Failed to load config file: #{e.message}", :red
|
|
238
|
+
nil
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Save persistent config to file
|
|
242
|
+
#
|
|
243
|
+
# @param data [Hash] the config data
|
|
244
|
+
def save_persistent_config(data)
|
|
245
|
+
File.write(CONFIG_FILE, data.to_yaml)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|