patcmd 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/.rubocop.yml +2 -0
- data/.vscode/launch.json +32 -0
- data/lib/patcmd/cli/command_runner.rb +49 -0
- data/lib/patcmd/cli/commands/add_command.rb +24 -30
- data/lib/patcmd/cli/commands/base_command.rb +13 -13
- data/lib/patcmd/cli/commands/core.rb +17 -15
- data/lib/patcmd/cli/commands/exec_command.rb +13 -11
- data/lib/patcmd/cli/commands/init_command.rb +8 -6
- data/lib/patcmd/cli/commands/list_command.rb +15 -9
- data/lib/patcmd/cli/{commands/commands.rb → commands.rb} +2 -3
- data/lib/patcmd/cli/environment_preparer.rb +24 -0
- data/lib/patcmd/cli/logger.rb +44 -0
- data/lib/patcmd/cli/path_resolver.rb +20 -0
- data/lib/patcmd/cli/presenters/task_presenter.rb +28 -0
- data/lib/patcmd/cli/presenters.rb +11 -0
- data/lib/patcmd/cli/services/task_builder.rb +24 -0
- data/lib/patcmd/cli/services/task_validator.rb +33 -0
- data/lib/patcmd/cli/services.rb +11 -0
- data/lib/patcmd/cli/task.rb +17 -0
- data/lib/patcmd/cli/task_executor.rb +8 -57
- data/lib/patcmd/cli.rb +7 -1
- data/lib/patcmd/version.rb +1 -1
- data/lib/patcmd.rb +2 -2
- metadata +21 -11
- data/lib/patcmd/cli/cli.rb +0 -11
- data/lib/patcmd/cli/helpers/helpers.rb +0 -11
- data/lib/patcmd/cli/helpers/logger.rb +0 -25
- data/lib/patcmd/cli/helpers/task_helper.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e08b470213e3e2014f9dbb67081a5bedc21eb0a6914039ebfa5d95cfbc8aa21c
|
4
|
+
data.tar.gz: 968f2c23d043c84887920498c2075ee0e327de83a6f4c43c53ab24b421cec8f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13b6bd069fa64889bb29aff3f5a6c46ea6a4eb7a0fd6e60eda28d1863391748911a840e9a376269d873424b7ba080dd69814b7f98c08368741444a5638546b0a
|
7
|
+
data.tar.gz: 26c39484a084cd4908c0a56dc0d5eff01af124b5f029d0c7ad0b818369e2ea684480e29e9885819434c270bfc299e7d43474de4dd05b448b8207f2c0290b2bf8
|
data/.rubocop.yml
CHANGED
data/.vscode/launch.json
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
{
|
2
|
+
"version": "0.2.0",
|
3
|
+
"configurations": [
|
4
|
+
{
|
5
|
+
"type": "ruby_lsp",
|
6
|
+
"name": "RSpec: Run Current Spec File",
|
7
|
+
"request": "launch",
|
8
|
+
"program": "${workspaceFolder}/bin/rspec ${file}",
|
9
|
+
"env": {
|
10
|
+
"RAILS_ENV": "test"
|
11
|
+
}
|
12
|
+
},
|
13
|
+
{
|
14
|
+
"type": "ruby_lsp",
|
15
|
+
"name": "RSpec: Run All Specs",
|
16
|
+
"request": "launch",
|
17
|
+
"program": "${workspaceFolder}/bin/rspec",
|
18
|
+
"env": {
|
19
|
+
"RAILS_ENV": "test"
|
20
|
+
}
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"type": "ruby_lsp",
|
24
|
+
"name": "RSpec: Run Test at Cursor",
|
25
|
+
"request": "launch",
|
26
|
+
"program": "${workspaceFolder}/bin/rspec ${file}:${lineNumber}",
|
27
|
+
"env": {
|
28
|
+
"RAILS_ENV": "test"
|
29
|
+
}
|
30
|
+
}
|
31
|
+
]
|
32
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Patcmd
|
4
|
+
module CLI
|
5
|
+
class CommandRunner
|
6
|
+
def initialize(task, options, env_vars)
|
7
|
+
@task = task
|
8
|
+
@options = options
|
9
|
+
@env_vars = env_vars
|
10
|
+
@logger = Logger.new(verbose: options[:verbose])
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
command = prepare_command
|
15
|
+
path = PathResolver.expand(@task.path)
|
16
|
+
|
17
|
+
unless Dir.exist?(path)
|
18
|
+
@logger.error("Path not found: #{path}")
|
19
|
+
exit(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
@logger.info("Executing '#{@task.description}' in #{path}")
|
23
|
+
@logger.info("Command: #{command}") if @options[:verbose]
|
24
|
+
@logger.info("Environment Variables: #{@env_vars}") if @options[:verbose] && @env_vars.any?
|
25
|
+
|
26
|
+
Dir.chdir(path) do
|
27
|
+
result = system(@env_vars, command)
|
28
|
+
unless result
|
29
|
+
@logger.error("Command execution failed.")
|
30
|
+
exit(1)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
@logger.success("Command executed successfully.")
|
34
|
+
rescue KeyError => e
|
35
|
+
@logger.error("Missing option for command substitution: #{e.message}")
|
36
|
+
exit(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def prepare_command
|
42
|
+
substitution_vars = @options[:options] ? @options[:options].transform_keys(&:to_sym) : {}
|
43
|
+
cmd = @task.command % substitution_vars
|
44
|
+
args = @task.args.map { |arg| arg % substitution_vars }
|
45
|
+
([cmd] + args).join(" ")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -2,38 +2,32 @@
|
|
2
2
|
|
3
3
|
module Patcmd
|
4
4
|
module CLI
|
5
|
-
|
6
|
-
|
5
|
+
module Commands
|
6
|
+
class AddCommand < BaseCommand
|
7
|
+
default_task :add
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
def add
|
18
|
-
task = build_task_from_options
|
19
|
-
validate_task(task)
|
20
|
-
config_manager.add_task(task)
|
21
|
-
puts "Added task '#{task["name"]}' under category '#{task["category"]}' with action '#{task["action"]}'."
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
9
|
+
desc "add", "Add a new task to the config"
|
10
|
+
method_option :name, aliases: "-n", required: true, desc: "Task name"
|
11
|
+
method_option :description, aliases: "-d", required: true, desc: "Task description"
|
12
|
+
method_option :category, aliases: "-c", required: true, desc: "Category name"
|
13
|
+
method_option :path, aliases: "-p", required: true, desc: "Execution path"
|
14
|
+
method_option :action, aliases: "-a", required: true, desc: "Action name"
|
15
|
+
method_option :command, aliases: "-m", required: true, desc: "Command to execute"
|
16
|
+
method_option :args, aliases: "-g", type: :array, default: [], desc: "Arguments for the command"
|
17
|
+
method_option :environments, aliases: "-e", type: :hash, default: {}, desc: "Environment variables"
|
25
18
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
"
|
36
|
-
|
19
|
+
def add
|
20
|
+
task = Services::TaskBuilder.build_from_options(options)
|
21
|
+
Services::TaskValidator.validate(task)
|
22
|
+
config_manager.add_task(task)
|
23
|
+
Presenters::TaskPresenter.new($stdout).display(task)
|
24
|
+
logger.success(
|
25
|
+
"Added task '#{task["name"]}' under category '#{task["category"]}' with action '#{task["action"]}'.",
|
26
|
+
)
|
27
|
+
rescue Services::TaskValidator::ValidationError => e
|
28
|
+
logger.error("Error: #{e.message}")
|
29
|
+
exit(1)
|
30
|
+
end
|
37
31
|
end
|
38
32
|
end
|
39
33
|
end
|
@@ -2,23 +2,23 @@
|
|
2
2
|
|
3
3
|
module Patcmd
|
4
4
|
module CLI
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
module Commands
|
6
|
+
class BaseCommand < Thor
|
7
|
+
CONFIG_PATH = File.expand_path("~/.patcmd/config.yml")
|
8
8
|
|
9
|
-
|
9
|
+
# Define global options
|
10
|
+
class_option :config, type: :string, default: CONFIG_PATH, desc: "Path to configuration file"
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
def initialize(*args)
|
13
|
+
super
|
14
|
+
@config_manager = ConfigurationManager.new(options[:config])
|
15
|
+
@logger = Logger.new(verbose: options[:verbose])
|
16
|
+
end
|
13
17
|
|
14
|
-
|
15
|
-
super
|
16
|
-
@config_manager = ConfigurationManager.new(options[:config])
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
18
|
+
private
|
20
19
|
|
21
|
-
|
20
|
+
attr_reader :config_manager, :logger
|
21
|
+
end
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -1,25 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
require "patcmd/cli/commands/base_command"
|
4
|
+
require "patcmd/cli/commands/init_command"
|
5
|
+
require "patcmd/cli/commands/add_command"
|
6
|
+
require "patcmd/cli/commands/list_command"
|
7
|
+
require "patcmd/cli/commands/exec_command"
|
8
8
|
|
9
9
|
module Patcmd
|
10
10
|
module CLI
|
11
|
-
|
12
|
-
class
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
module Commands
|
12
|
+
class Core < Thor
|
13
|
+
class << self
|
14
|
+
# Ensure the CLI exits with a non-zero status code on failure
|
15
|
+
def exit_on_failure?
|
16
|
+
true
|
17
|
+
end
|
16
18
|
end
|
17
|
-
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
register InitCommand, "init", "init", "Initialize the PatCmd configuration"
|
21
|
+
register AddCommand, "add", "add", "Add a new task to the config"
|
22
|
+
register ListCommand, "list", "list", "List all configured tasks"
|
23
|
+
register ExecCommand, "exec", "exec CATEGORY NAME ACTION", "Execute a defined task"
|
24
|
+
end
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
@@ -2,18 +2,20 @@
|
|
2
2
|
|
3
3
|
module Patcmd
|
4
4
|
module CLI
|
5
|
-
|
6
|
-
|
5
|
+
module Commands
|
6
|
+
class ExecCommand < BaseCommand
|
7
|
+
default_task :exec
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
desc "exec CATEGORY NAME ACTION", "Execute a defined task"
|
10
|
+
def exec(category, name, action)
|
11
|
+
task = config_manager.find_task(category, name, action)
|
12
|
+
if task
|
13
|
+
executor = TaskExecutor.new(task, options)
|
14
|
+
executor.execute
|
15
|
+
else
|
16
|
+
puts "Task not found for category '#{category}', name '#{name}', and action '#{action}'."
|
17
|
+
exit(1)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -2,13 +2,15 @@
|
|
2
2
|
|
3
3
|
module Patcmd
|
4
4
|
module CLI
|
5
|
-
|
6
|
-
|
5
|
+
module Commands
|
6
|
+
class InitCommand < BaseCommand
|
7
|
+
default_task :init
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
desc "init", "Initialize the PatCmd configuration"
|
10
|
+
def init
|
11
|
+
config_manager.init_config
|
12
|
+
puts "Configuration initialized at #{config_manager.config_path}"
|
13
|
+
end
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -2,16 +2,22 @@
|
|
2
2
|
|
3
3
|
module Patcmd
|
4
4
|
module CLI
|
5
|
-
|
6
|
-
|
5
|
+
module Commands
|
6
|
+
class ListCommand < BaseCommand
|
7
|
+
default_task :list
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
desc "list", "List all configured tasks"
|
10
|
+
def list
|
11
|
+
tasks = config_manager.all_tasks
|
12
|
+
if tasks.empty?
|
13
|
+
logger.info("No tasks configured.")
|
14
|
+
else
|
15
|
+
presenter = Presenters::TaskPresenter.new($stdout)
|
16
|
+
tasks.each { |task| presenter.display(task) }
|
17
|
+
end
|
18
|
+
rescue StandardError => e
|
19
|
+
logger.error("An error occurred while listing tasks: #{e.message}")
|
20
|
+
exit(1)
|
15
21
|
end
|
16
22
|
end
|
17
23
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "thor"
|
4
|
-
|
5
|
-
require_relative "core"
|
4
|
+
require "patcmd/cli/commands/core"
|
6
5
|
|
7
6
|
module Patcmd
|
8
7
|
module CLI
|
9
8
|
class << self
|
10
9
|
def start(argv)
|
11
|
-
Core.start(argv)
|
10
|
+
Commands::Core.start(argv)
|
12
11
|
end
|
13
12
|
end
|
14
13
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Patcmd
|
4
|
+
module CLI
|
5
|
+
class EnvironmentPreparer
|
6
|
+
def initialize(options = {})
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def prepare(env_vars)
|
11
|
+
substitution_vars = prepare_substitution_vars
|
12
|
+
env_vars.transform_values { |v| v % substitution_vars }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def prepare_substitution_vars
|
18
|
+
return {} unless @options[:options]
|
19
|
+
|
20
|
+
@options[:options].transform_keys(&:to_sym)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Patcmd
|
4
|
+
module CLI
|
5
|
+
class Logger
|
6
|
+
COLORS = {
|
7
|
+
info: "\e[34m", # Blue
|
8
|
+
success: "\e[32m", # Green
|
9
|
+
error: "\e[31m", # Red
|
10
|
+
warn: "\e[33m", # Yellow
|
11
|
+
reset: "\e[0m", # Reset
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
def initialize(verbose: false)
|
15
|
+
@verbose = verbose
|
16
|
+
end
|
17
|
+
|
18
|
+
def info(message)
|
19
|
+
log(:info, message)
|
20
|
+
end
|
21
|
+
|
22
|
+
def success(message)
|
23
|
+
log(:success, message)
|
24
|
+
end
|
25
|
+
|
26
|
+
def error(message)
|
27
|
+
log(:error, message)
|
28
|
+
end
|
29
|
+
|
30
|
+
def warn(message)
|
31
|
+
log(:warn, message)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def log(level, message)
|
37
|
+
return unless @verbose || level == :error
|
38
|
+
|
39
|
+
color = COLORS[level] || COLORS[:info]
|
40
|
+
puts "#{color}[#{level.to_s.upcase}]#{COLORS[:reset]} #{message}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Patcmd
|
4
|
+
module CLI
|
5
|
+
class PathResolver
|
6
|
+
class << self
|
7
|
+
def expand(path)
|
8
|
+
return if path.nil? || path.strip.empty?
|
9
|
+
|
10
|
+
# Expand tilde (~) and substitute environment variables
|
11
|
+
expanded_path = path.gsub("~", Dir.home)
|
12
|
+
expanded_path.gsub!(/\$\{([^\}]+)\}/) { ENV[::Regexp.last_match(1)] || "" }
|
13
|
+
|
14
|
+
# Ensure the path does not double-resolve
|
15
|
+
File.expand_path(expanded_path)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Patcmd
|
4
|
+
module CLI
|
5
|
+
module Presenters
|
6
|
+
class TaskPresenter
|
7
|
+
def initialize(output = $stdout)
|
8
|
+
@output = output
|
9
|
+
end
|
10
|
+
|
11
|
+
def display(task)
|
12
|
+
@output.puts "Category: #{task["category"]}"
|
13
|
+
@output.puts " Name: #{task["name"]}"
|
14
|
+
@output.puts " Action: #{task["action"]}"
|
15
|
+
@output.puts " Description: #{task["description"]}"
|
16
|
+
@output.puts " Path: #{task["path"]}"
|
17
|
+
@output.puts " Command: #{task["command"]}"
|
18
|
+
@output.puts " Args: #{task["args"].join(" ")}" if task["args"]&.any?
|
19
|
+
if task["environments"]&.any?
|
20
|
+
envs = task["environments"].map { |k, v| "#{k}=#{v}" }.join(", ")
|
21
|
+
@output.puts " Environments: #{envs}"
|
22
|
+
end
|
23
|
+
@output.puts "-" * 40
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Patcmd
|
4
|
+
module CLI
|
5
|
+
module Services
|
6
|
+
class TaskBuilder
|
7
|
+
class << self
|
8
|
+
def build_from_options(options)
|
9
|
+
{
|
10
|
+
"name" => options[:name],
|
11
|
+
"description" => options[:description],
|
12
|
+
"category" => options[:category],
|
13
|
+
"path" => options[:path],
|
14
|
+
"action" => options[:action],
|
15
|
+
"command" => options[:command],
|
16
|
+
"args" => options[:args],
|
17
|
+
"environments" => options[:environments],
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Patcmd
|
4
|
+
module CLI
|
5
|
+
module Services
|
6
|
+
class TaskValidator
|
7
|
+
class ValidationError < StandardError; end
|
8
|
+
|
9
|
+
REQUIRED_FIELDS = ["name", "description", "category", "path", "action", "command"].freeze
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def validate(task)
|
13
|
+
missing_fields = REQUIRED_FIELDS.select { |field| task[field].nil? || task[field].strip.empty? }
|
14
|
+
|
15
|
+
unless missing_fields.empty?
|
16
|
+
raise ValidationError, "Missing required fields: #{missing_fields.join(", ")}"
|
17
|
+
end
|
18
|
+
|
19
|
+
unless task["args"].is_a?(Array)
|
20
|
+
raise ValidationError, "The 'args' field must be an array."
|
21
|
+
end
|
22
|
+
|
23
|
+
unless task["environments"].is_a?(Hash)
|
24
|
+
raise ValidationError, "The 'environments' field must be a hash."
|
25
|
+
end
|
26
|
+
|
27
|
+
true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Patcmd
|
4
|
+
module CLI
|
5
|
+
class Task
|
6
|
+
attr_reader :description, :command, :args, :environments, :path
|
7
|
+
|
8
|
+
def initialize(task)
|
9
|
+
@description = task["description"]
|
10
|
+
@command = task["command"]
|
11
|
+
@args = task["args"] || []
|
12
|
+
@environments = task["environments"] || {}
|
13
|
+
@path = task["path"]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,70 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "patcmd/cli/task"
|
4
|
+
require "patcmd/cli/environment_preparer"
|
5
|
+
require "patcmd/cli/command_runner"
|
6
|
+
require "patcmd/cli/path_resolver"
|
7
|
+
|
3
8
|
module Patcmd
|
4
9
|
module CLI
|
5
10
|
class TaskExecutor
|
6
|
-
require "shellwords"
|
7
|
-
|
8
11
|
def initialize(task, options)
|
9
|
-
@task = task
|
12
|
+
@task = Task.new(task)
|
10
13
|
@options = options
|
11
14
|
end
|
12
15
|
|
13
16
|
def execute
|
14
|
-
|
15
|
-
|
16
|
-
path = expand_path(@task["path"])
|
17
|
-
|
18
|
-
unless Dir.exist?(path)
|
19
|
-
puts "Path not found: #{path}"
|
20
|
-
exit(1)
|
21
|
-
end
|
22
|
-
|
23
|
-
puts "Executing '#{@task["description"]}' in #{path}"
|
24
|
-
puts "Command: #{command}" if @options[:verbose]
|
25
|
-
puts "Environment Variables: #{env_vars}" if @options[:verbose] && env_vars.any?
|
26
|
-
|
27
|
-
Dir.chdir(path) do
|
28
|
-
result = system(env_vars, command)
|
29
|
-
unless result
|
30
|
-
puts "Command execution failed."
|
31
|
-
exit(1)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
rescue KeyError => e
|
35
|
-
puts "Missing option for command substitution: #{e.message}"
|
36
|
-
exit(1)
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def prepare_command
|
42
|
-
cmd = @task["command"]
|
43
|
-
args = @task["args"] || []
|
44
|
-
|
45
|
-
# Handle command substitution
|
46
|
-
if @options[:options] && !@options[:options].empty?
|
47
|
-
substitution_vars = @options[:options].transform_keys(&:to_sym)
|
48
|
-
cmd %= substitution_vars
|
49
|
-
args = args.map { |arg| arg % substitution_vars }
|
50
|
-
end
|
51
|
-
|
52
|
-
([cmd] + args).join(" ")
|
53
|
-
end
|
54
|
-
|
55
|
-
def prepare_environment_variables
|
56
|
-
env_vars = @task["environments"] || {}
|
57
|
-
|
58
|
-
if @options[:options] && !@options[:options].empty?
|
59
|
-
substitution_vars = @options[:options].transform_keys(&:to_sym)
|
60
|
-
env_vars = env_vars.transform_values { |v| v % substitution_vars }
|
61
|
-
end
|
62
|
-
|
63
|
-
env_vars
|
64
|
-
end
|
65
|
-
|
66
|
-
def expand_path(path)
|
67
|
-
File.expand_path(path.gsub("~", Dir.home))
|
17
|
+
env_vars = EnvironmentPreparer.new(@options).prepare(@task.environments)
|
18
|
+
CommandRunner.new(@task, @options, env_vars).execute
|
68
19
|
end
|
69
20
|
end
|
70
21
|
end
|
data/lib/patcmd/cli.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "patcmd/cli/logger"
|
4
|
+
require "patcmd/cli/configuration_manager"
|
5
|
+
require "patcmd/cli/task_executor"
|
6
|
+
require "patcmd/cli/presenters"
|
7
|
+
require "patcmd/cli/services"
|
8
|
+
require "patcmd/cli/commands"
|
9
|
+
|
4
10
|
module Patcmd
|
5
11
|
module CLI
|
6
12
|
end
|
data/lib/patcmd/version.rb
CHANGED
data/lib/patcmd.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: patcmd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Huy Nguyen
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -36,6 +36,7 @@ files:
|
|
36
36
|
- ".rspec"
|
37
37
|
- ".rubocop.yml"
|
38
38
|
- ".tool-versions"
|
39
|
+
- ".vscode/launch.json"
|
39
40
|
- ".vscode/settings.json"
|
40
41
|
- CODE_OF_CONDUCT.md
|
41
42
|
- LICENSE.txt
|
@@ -44,26 +45,35 @@ files:
|
|
44
45
|
- bin/patcmd
|
45
46
|
- lib/patcmd.rb
|
46
47
|
- lib/patcmd/cli.rb
|
47
|
-
- lib/patcmd/cli/
|
48
|
+
- lib/patcmd/cli/command_runner.rb
|
49
|
+
- lib/patcmd/cli/commands.rb
|
48
50
|
- lib/patcmd/cli/commands/add_command.rb
|
49
51
|
- lib/patcmd/cli/commands/base_command.rb
|
50
|
-
- lib/patcmd/cli/commands/commands.rb
|
51
52
|
- lib/patcmd/cli/commands/core.rb
|
52
53
|
- lib/patcmd/cli/commands/exec_command.rb
|
53
54
|
- lib/patcmd/cli/commands/init_command.rb
|
54
55
|
- lib/patcmd/cli/commands/list_command.rb
|
55
56
|
- lib/patcmd/cli/configuration_manager.rb
|
56
|
-
- lib/patcmd/cli/
|
57
|
-
- lib/patcmd/cli/
|
58
|
-
- lib/patcmd/cli/
|
57
|
+
- lib/patcmd/cli/environment_preparer.rb
|
58
|
+
- lib/patcmd/cli/logger.rb
|
59
|
+
- lib/patcmd/cli/path_resolver.rb
|
60
|
+
- lib/patcmd/cli/presenters.rb
|
61
|
+
- lib/patcmd/cli/presenters/task_presenter.rb
|
62
|
+
- lib/patcmd/cli/services.rb
|
63
|
+
- lib/patcmd/cli/services/task_builder.rb
|
64
|
+
- lib/patcmd/cli/services/task_validator.rb
|
65
|
+
- lib/patcmd/cli/task.rb
|
59
66
|
- lib/patcmd/cli/task_executor.rb
|
60
67
|
- lib/patcmd/version.rb
|
61
68
|
- sig/patcmd.rbs
|
62
69
|
homepage: https://github.com/patrick204nqh/patcmd
|
63
70
|
licenses:
|
64
71
|
- MIT
|
65
|
-
metadata:
|
66
|
-
|
72
|
+
metadata:
|
73
|
+
homepage_uri: https://github.com/patrick204nqh/patcmd
|
74
|
+
source_code_uri: https://github.com/patrick204nqh/patcmd
|
75
|
+
changelog_uri: https://github.com/patrick204nqh/patcmd/blob/main/CHANGELOG.md
|
76
|
+
post_install_message:
|
67
77
|
rdoc_options: []
|
68
78
|
require_paths:
|
69
79
|
- lib
|
@@ -79,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
89
|
version: '0'
|
80
90
|
requirements: []
|
81
91
|
rubygems_version: 3.5.3
|
82
|
-
signing_key:
|
92
|
+
signing_key:
|
83
93
|
specification_version: 4
|
84
94
|
summary: A CLI tool for running tasks quickly.
|
85
95
|
test_files: []
|
data/lib/patcmd/cli/cli.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Patcmd
|
4
|
-
module CLI
|
5
|
-
module Helpers
|
6
|
-
module Logger
|
7
|
-
# Logs an informational message with a timestamp.
|
8
|
-
#
|
9
|
-
# @param message [String] The message to log.
|
10
|
-
# @return [void]
|
11
|
-
def log_info(message)
|
12
|
-
puts "[INFO] #{Time.now.strftime("%Y-%m-%d %H:%M:%S")} - #{message}"
|
13
|
-
end
|
14
|
-
|
15
|
-
# Logs an error message with a timestamp.
|
16
|
-
#
|
17
|
-
# @param message [String] The message to log.
|
18
|
-
# @return [void]
|
19
|
-
def log_error(message)
|
20
|
-
puts "[ERROR] #{Time.now.strftime("%Y-%m-%d %H:%M:%S")} - #{message}"
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Patcmd
|
4
|
-
module CLI
|
5
|
-
module Helpers
|
6
|
-
module TaskHelper
|
7
|
-
class ValidationError < StandardError; end
|
8
|
-
|
9
|
-
def validate_task(task)
|
10
|
-
required_fields = ["name", "description", "category", "path", "action", "command"]
|
11
|
-
missing_fields = required_fields.select { |field| task[field].nil? || task[field].strip.empty? }
|
12
|
-
|
13
|
-
unless missing_fields.empty?
|
14
|
-
raise ValidationError, "Missing required fields: #{missing_fields.join(", ")}"
|
15
|
-
exit(1)
|
16
|
-
end
|
17
|
-
|
18
|
-
unless task["args"].is_a?(Array)
|
19
|
-
rails(ValidationError, "The 'args' field must be an array.")
|
20
|
-
exit(1)
|
21
|
-
end
|
22
|
-
|
23
|
-
unless task["environments"].is_a?(Hash)
|
24
|
-
rails(ValidationError, "The 'environments' field must be a hash.")
|
25
|
-
exit(1)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def display_task(task)
|
30
|
-
puts "Category: #{task["category"]}"
|
31
|
-
puts " Name: #{task["name"]}"
|
32
|
-
puts " Action: #{task["action"]}"
|
33
|
-
puts " Description: #{task["description"]}"
|
34
|
-
puts " Path: #{task["path"]}"
|
35
|
-
puts " Command: #{task["command"]}"
|
36
|
-
puts " Args: #{task["args"].join(" ")}" if task["args"].any?
|
37
|
-
if task["environments"].any?
|
38
|
-
envs = task["environments"].map { |k, v| "#{k}=#{v}" }.join(", ")
|
39
|
-
puts " Environments: #{envs}"
|
40
|
-
end
|
41
|
-
puts "-" * 40
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|