patcmd 0.1.1 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e08b470213e3e2014f9dbb67081a5bedc21eb0a6914039ebfa5d95cfbc8aa21c
4
- data.tar.gz: 968f2c23d043c84887920498c2075ee0e327de83a6f4c43c53ab24b421cec8f6
3
+ metadata.gz: ca00a46642b861edd38385a45ef93e6d6cae49f2dd0fec6a4a2237d19a90be14
4
+ data.tar.gz: c3bdbadaf8ab1fc83f712e4a41d64da0b5f3eb1b9e05f12d99fb0914172150db
5
5
  SHA512:
6
- metadata.gz: 13b6bd069fa64889bb29aff3f5a6c46ea6a4eb7a0fd6e60eda28d1863391748911a840e9a376269d873424b7ba080dd69814b7f98c08368741444a5638546b0a
7
- data.tar.gz: 26c39484a084cd4908c0a56dc0d5eff01af124b5f029d0c7ad0b818369e2ea684480e29e9885819434c270bfc299e7d43474de4dd05b448b8207f2c0290b2bf8
6
+ metadata.gz: 50203822923ae061412d63b46dc351d9550ded803316372582f2d16b45b49b007fb38ae8e925ef6c91f178c55660352a806ccae2cb771862173a56916413ce59
7
+ data.tar.gz: 44c94cfb0f3aa36c8883ff3b193ebcee6112e76a9155dac48448b9b363289f41ab4659dbfd2813702c8a94ab5d37972717af22351b1d0da60e2c2dcfe293bebb
data/README.md CHANGED
@@ -1,111 +1,104 @@
1
- # PatCmd
1
+ # Patcmd
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/patcmd.svg)](https://badge.fury.io/rb/patcmd)
4
4
  [![Build Status](https://github.com/patrick204nqh/patcmd/actions/workflows/ruby.yml/badge.svg)](https://github.com/patrick204nqh/patcmd/actions)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
6
 
7
- PatCmd is a Ruby-based command-line interface (CLI) tool built with Thor, designed to manage and execute tasks efficiently. Whether you're automating scripts, managing deployments, or handling routine operations, PatCmd provides a streamlined and customizable solution.
7
+ Patcmd is a Ruby gem that provides a command-line interface (CLI) for managing and executing tasks from a YAML configuration file. It helps centralize your terminal commands into one file, making it easy to trigger frequently used tasks with memorable aliases.
8
8
 
9
9
  ## Features
10
10
 
11
- - **Task Management:** Easily add, list, and execute tasks.
12
- - **Configurable Environments:** Define environment variables per task.
13
- - **Extensible:** Add new commands and functionalities as needed.
14
- - **User-Friendly:** Intuitive CLI with clear help documentation.
11
+ - **Centralized Task Management:** Store your commands and scripts in a single YAML configuration file.
12
+ - **Preconfigured Default Task:** When initialized, the configuration file includes a default "hello" task that prints "Hello World."
13
+ - **Flexible Task Definitions:** Each task can have a command, arguments, environment variables, description, and group.
14
+ - **Easy Command-Line Interface:** Use Thor to quickly add, list, and run tasks.
15
15
 
16
16
  ## Installation
17
17
 
18
- Ensure you have [Ruby](https://www.ruby-lang.org/en/downloads/) (version 3.0 or higher) installed on your system.
18
+ Add this line to your application's Gemfile:
19
19
 
20
- ### Install via RubyGems
21
-
22
- ```bash
23
- gem install patcmd
24
- ```
25
-
26
- ### From Source
27
-
28
- 1. Clone the Repository:
29
-
30
- ```bash
31
- git clone https://github.com/yourusername/patcmd.git
32
- cd patcmd
20
+ ```ruby
21
+ gem 'patcmd'
33
22
  ```
34
23
 
35
- 2. Build the Gem:
24
+ Then execute:
36
25
 
37
26
  ```bash
38
- gem build patcmd.gemspec
27
+ bundle install
39
28
  ```
40
29
 
41
- 3. Install the Gem Locally:
30
+ Or install it yourself as:
42
31
 
43
32
  ```bash
44
- gem install ./patcmd-0.1.0.gem
33
+ gem install patcmd
45
34
  ```
46
35
 
47
36
  ## Usage
48
37
 
49
- After installation, you can use `patcmd` directly from your terminal.
50
-
51
- ### Initialize Configuration
38
+ ### Initializing the Configuration File
52
39
 
53
- Initialize the PatCmd configuration file. This creates a default configuration file where tasks are stored.
40
+ To create the configuration file (located at `~/.patcmd/config.yml`), run:
54
41
 
55
42
  ```bash
56
43
  patcmd init
57
44
  ```
58
45
 
59
- Example Output:
60
-
61
- ```bash
62
- Configuration initialized at /home/username/.patcmd/config.yml
63
- ```
64
-
65
- ### Add a New Task
66
-
67
- ```bash
68
- patcmd add \
69
- --name "Backup" \
70
- --description "Backup the database" \
71
- --category "Utility" \
72
- --path "/usr/local/bin" \
73
- --action "execute" \
74
- --command "backup_db" \
75
- --args db1 db2 \
76
- --environments NOdE
46
+ This command creates the file with a default task named **hello**. The default task is defined as follows:
47
+
48
+ ```yaml
49
+ ---
50
+ tasks:
51
+ hello:
52
+ command: bash
53
+ args:
54
+ - "-c"
55
+ - '''echo "$GREETING, $TARGET! Args: $ARG1, $ARG2"'''
56
+ env:
57
+ GREETING: Hello
58
+ TARGET: World
59
+ ARG1: Foo
60
+ ARG2: Bar
61
+ description: Print Hello World with multiple arguments and environment variables
62
+ group: default
77
63
  ```
78
64
 
79
- ### List All Tasks
65
+ ### Listing Tasks
80
66
 
81
- Display all configured tasks.
67
+ To list all available tasks, run:
82
68
 
83
69
  ```bash
84
70
  patcmd list
85
71
  ```
86
72
 
87
- ### Execute a Task
73
+ ### Adding a Task with Multiple Arguments and Environment Variables
74
+
75
+ You can add custom tasks using the CLI. For example, to add a task called **complex** that demonstrates multiple arguments and environment variables, run:
88
76
 
89
77
  ```bash
90
- patcmd exec Utility Backup execute
78
+ patcmd add complex \
79
+ --command "bash" \
80
+ --args "-c" "echo 'Value1: $VAL1, Value2: $VAL2, extra args: arg1 arg2'" \
81
+ --env VAL1=value1,VAL2=value2 \
82
+ --description "A complex task with many args and env variables" \
83
+ --group custom
91
84
  ```
92
85
 
93
- ### Help
86
+ *Note:* The `--env` option is expected to be passed as a hash. Adjust the input format as needed based on your CLI parsing.
87
+
88
+ ### Running a Task
94
89
 
95
- Access help information for all commands or a specific command.
90
+ To execute a task, for example the default **hello** task, run:
96
91
 
97
92
  ```bash
98
- patcmd help
99
- patcmd help add
100
- patcmd help list
93
+ patcmd exec hello
101
94
  ```
102
95
 
103
- ### Configuration
96
+ This command executes the task, applying the defined environment variables and arguments.
104
97
 
105
- PatCmd uses a YAML configuration file to store tasks and settings. The default configuration file is located at `~/.patcmd/config.yml`. You can specify a different configuration file using the --config option.
98
+ ## Contributing
106
99
 
107
- **Example:**
100
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/patrick204nqh/patcmd](https://github.com/patrick204nqh/patcmd).
108
101
 
109
- ```bash
110
- patcmd list --config=/path/to/custom_config.yml
111
- ```
102
+ ## License
103
+
104
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
data/lib/patcmd/cli.rb CHANGED
@@ -1,13 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
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"
3
+ require "thor"
4
+ require_relative "commands/version"
5
+ require_relative "commands/init"
6
+ require_relative "commands/list"
7
+ require_relative "commands/add"
8
+ require_relative "commands/exec"
9
9
 
10
10
  module Patcmd
11
- module CLI
11
+ class CLI < Thor
12
+ class << self
13
+ def exit_on_failure?
14
+ true
15
+ end
16
+ end
17
+
18
+ # Register subcommands with Thor
19
+ register(Commands::Version, "version", "version", "Show Patcmd gem version")
20
+ register(Commands::Init, "init", "init", "Initialize configuration file")
21
+ register(Commands::List, "list", "list", "List all tasks")
22
+ register(Commands::Add, "add", "add NAME", "Add a new task")
23
+ register(Commands::Exec, "exec", "exec NAME", "Exec a specific task")
12
24
  end
13
25
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require "patcmd/configuration"
5
+
6
+ module Patcmd
7
+ module Commands
8
+ class Add < Base
9
+ desc "add NAME", "Add a new task"
10
+ option :description, desc: "Task description"
11
+ option :group, desc: "Task group"
12
+ option :command, required: true, desc: "The command to run"
13
+ option :args, type: :array, default: [], desc: "Command arguments"
14
+ option :env, type: :hash, default: {}, desc: "Environment variables"
15
+ def execute(name)
16
+ new_task = {
17
+ "description" => options[:description] || "",
18
+ "group" => options[:group] || "default",
19
+ "command" => options[:command],
20
+ "args" => options[:args],
21
+ "env" => options[:env],
22
+ }
23
+ Configuration.add_task(name, new_task)
24
+ say("Task '#{name}' added successfully.", :green)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ module Patcmd
6
+ module Commands
7
+ class Base < Thor
8
+ default_task :execute
9
+
10
+ desc "execute", "Execute the command"
11
+ def execute
12
+ raise NotImplementedError
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require "patcmd/configuration"
5
+ require "patcmd/task"
6
+
7
+ module Patcmd
8
+ module Commands
9
+ class Exec < Base
10
+ desc "exec NAME", "Exec a specific task"
11
+ def execute(name)
12
+ tasks = Configuration.load_tasks
13
+ unless tasks[name]
14
+ say("Task '#{name}' not found.", :red)
15
+ exit(1)
16
+ end
17
+ task = Task.new(name, tasks[name])
18
+ say("Running task '#{name}'...", :green)
19
+ task.execute
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require "patcmd/configuration"
5
+
6
+ module Patcmd
7
+ module Commands
8
+ class Init < Base
9
+ desc "init", "Initialize configuration file"
10
+ def execute(*)
11
+ if Configuration.exists?
12
+ say("Configuration file already exists at #{Configuration::CONFIG_PATH}", :yellow)
13
+ else
14
+ Configuration.create_default
15
+ say("Initialized configuration file at #{Configuration::CONFIG_PATH}", :green)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require "patcmd/configuration"
5
+ require "patcmd/task"
6
+
7
+ module Patcmd
8
+ module Commands
9
+ class List < Base
10
+ desc "list", "List all tasks"
11
+ def execute(*)
12
+ tasks = Configuration.load_tasks
13
+ if tasks.empty?
14
+ say("No tasks found. Use 'patcmd add <name>' to add tasks.", :yellow)
15
+ else
16
+ tasks.each do |name, task_data|
17
+ task = Task.new(name, task_data)
18
+ say("#{name} - #{task.description}", :blue)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require "patcmd/version"
5
+
6
+ module Patcmd
7
+ module Commands
8
+ class Version < Base
9
+ desc "version", "Show Patcmd gem version"
10
+ def execute(*)
11
+ say("Patcmd version #{Patcmd::VERSION}", :green)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ module Patcmd
7
+ class Configuration
8
+ CONFIG_PATH = File.expand_path("~/.patcmd/config.yml")
9
+
10
+ class << self
11
+ def exists?
12
+ File.exist?(CONFIG_PATH)
13
+ end
14
+
15
+ def create_default
16
+ default_config = {
17
+ "tasks" => {
18
+ "hello" => {
19
+ "command" => "bash",
20
+ "args" => ["-c", "'echo \"$GREETING, $TARGET! Args: $ARG1, $ARG2\"'"],
21
+ "env" => {
22
+ "GREETING" => "Hello",
23
+ "TARGET" => "World",
24
+ "ARG1" => "Foo",
25
+ "ARG2" => "Bar",
26
+ },
27
+ "description" => "Print Hello World with multiple arguments and environment variables",
28
+ "group" => "default",
29
+ },
30
+ },
31
+ }
32
+ File.write(CONFIG_PATH, default_config.to_yaml)
33
+ end
34
+
35
+ def load_config
36
+ if exists?
37
+ YAML.load_file(CONFIG_PATH) || { "tasks" => {} }
38
+ else
39
+ create_default
40
+ load_config
41
+ end
42
+ end
43
+
44
+ def load_tasks
45
+ load_config["tasks"] || {}
46
+ end
47
+
48
+ def add_task(name, task_data)
49
+ config = load_config
50
+ config["tasks"] ||= {}
51
+ config["tasks"][name] = task_data
52
+ File.write(CONFIG_PATH, config.to_yaml)
53
+ end
54
+
55
+ # TODO: Implement update and remove methods as needed.
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Patcmd
4
+ class Task
5
+ attr_accessor :name, :group, :description, :command, :args, :env
6
+
7
+ def initialize(name, attributes = {})
8
+ @name = name
9
+ @description = attributes["description"] || ""
10
+ @group = attributes["group"] || "default"
11
+ @command = attributes["command"]
12
+ @args = attributes["args"] || []
13
+ @env = attributes["env"] || {}
14
+ end
15
+
16
+ def execute
17
+ # Save original environment variables
18
+ original_env = ENV.to_hash
19
+ # Set the specified environment variables
20
+ @env.each { |key, value| ENV[key] = value }
21
+
22
+ # Build and run the command string
23
+ full_command = [@command, *@args].join(" ")
24
+ system(full_command)
25
+
26
+ # Restore original environment.
27
+ ENV.replace(original_env)
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Patcmd
4
- VERSION = "0.1.1"
4
+ VERSION = "1.0.0"
5
5
  end
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.1
4
+ version: 1.0.0
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-09 00:00:00.000000000 Z
11
+ date: 2025-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -24,8 +24,8 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- description: PatCmd allows you to define and execute tasks using a simple command-line
28
- interface.
27
+ description: Patcmd is a Ruby CLI tool that centralizes command execution via a YAML
28
+ config file.
29
29
  email:
30
30
  - patrick204nqh@gmail.com
31
31
  executables:
@@ -45,25 +45,14 @@ files:
45
45
  - bin/patcmd
46
46
  - lib/patcmd.rb
47
47
  - lib/patcmd/cli.rb
48
- - lib/patcmd/cli/command_runner.rb
49
- - lib/patcmd/cli/commands.rb
50
- - lib/patcmd/cli/commands/add_command.rb
51
- - lib/patcmd/cli/commands/base_command.rb
52
- - lib/patcmd/cli/commands/core.rb
53
- - lib/patcmd/cli/commands/exec_command.rb
54
- - lib/patcmd/cli/commands/init_command.rb
55
- - lib/patcmd/cli/commands/list_command.rb
56
- - lib/patcmd/cli/configuration_manager.rb
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
66
- - lib/patcmd/cli/task_executor.rb
48
+ - lib/patcmd/commands/add.rb
49
+ - lib/patcmd/commands/base.rb
50
+ - lib/patcmd/commands/exec.rb
51
+ - lib/patcmd/commands/init.rb
52
+ - lib/patcmd/commands/list.rb
53
+ - lib/patcmd/commands/version.rb
54
+ - lib/patcmd/configuration.rb
55
+ - lib/patcmd/task.rb
67
56
  - lib/patcmd/version.rb
68
57
  - sig/patcmd.rbs
69
58
  homepage: https://github.com/patrick204nqh/patcmd
@@ -73,7 +62,8 @@ metadata:
73
62
  homepage_uri: https://github.com/patrick204nqh/patcmd
74
63
  source_code_uri: https://github.com/patrick204nqh/patcmd
75
64
  changelog_uri: https://github.com/patrick204nqh/patcmd/blob/main/CHANGELOG.md
76
- post_install_message:
65
+ documentation_uri: https://www.rubydoc.info/gems/patcmd
66
+ post_install_message:
77
67
  rdoc_options: []
78
68
  require_paths:
79
69
  - lib
@@ -89,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
79
  version: '0'
90
80
  requirements: []
91
81
  rubygems_version: 3.5.3
92
- signing_key:
82
+ signing_key:
93
83
  specification_version: 4
94
- summary: A CLI tool for running tasks quickly.
84
+ summary: A CLI tool to manage tasks using a YAML configuration.
95
85
  test_files: []
@@ -1,49 +0,0 @@
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
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Patcmd
4
- module CLI
5
- module Commands
6
- class AddCommand < BaseCommand
7
- default_task :add
8
-
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"
18
-
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
31
- end
32
- end
33
- end
34
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Patcmd
4
- module CLI
5
- module Commands
6
- class BaseCommand < Thor
7
- CONFIG_PATH = File.expand_path("~/.patcmd/config.yml")
8
-
9
- # Define global options
10
- class_option :config, type: :string, default: CONFIG_PATH, desc: "Path to configuration file"
11
-
12
- def initialize(*args)
13
- super
14
- @config_manager = ConfigurationManager.new(options[:config])
15
- @logger = Logger.new(verbose: options[:verbose])
16
- end
17
-
18
- private
19
-
20
- attr_reader :config_manager, :logger
21
- end
22
- end
23
- end
24
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
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
-
9
- module Patcmd
10
- module CLI
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
18
- end
19
-
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
25
- end
26
- end
27
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Patcmd
4
- module CLI
5
- module Commands
6
- class ExecCommand < BaseCommand
7
- default_task :exec
8
-
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
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Patcmd
4
- module CLI
5
- module Commands
6
- class InitCommand < BaseCommand
7
- default_task :init
8
-
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
14
- end
15
- end
16
- end
17
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Patcmd
4
- module CLI
5
- module Commands
6
- class ListCommand < BaseCommand
7
- default_task :list
8
-
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)
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "thor"
4
- require "patcmd/cli/commands/core"
5
-
6
- module Patcmd
7
- module CLI
8
- class << self
9
- def start(argv)
10
- Commands::Core.start(argv)
11
- end
12
- end
13
- end
14
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Patcmd
4
- module CLI
5
- class ConfigurationManager
6
- require "yaml"
7
- require "fileutils"
8
-
9
- attr_reader :config_path
10
-
11
- def initialize(config_path)
12
- @config_path = config_path
13
- ensure_config_file
14
- @config = load_config
15
- end
16
-
17
- def init_config
18
- unless File.exist?(@config_path)
19
- default_task = {
20
- "category" => "Default",
21
- "name" => "HelloWorld",
22
- "description" => "A simple Hello World task",
23
- "path" => "/usr/local/bin",
24
- "action" => "execute",
25
- "command" => "echo",
26
- "args" => ["Hello, World!"],
27
- "environments" => { "ENV" => "development" },
28
- }
29
-
30
- default_config = { "tasks" => [default_task] }
31
- FileUtils.mkdir_p(File.dirname(@config_path))
32
- File.write(@config_path, default_config.to_yaml)
33
- end
34
- end
35
-
36
- def add_task(task)
37
- @config["tasks"] << task
38
- save_config
39
- end
40
-
41
- def find_task(category, name, action)
42
- @config["tasks"].find do |task|
43
- task["category"] == category && task["name"] == name && task["action"] == action
44
- end
45
- end
46
-
47
- def all_tasks
48
- @config["tasks"]
49
- end
50
-
51
- private
52
-
53
- def ensure_config_file
54
- unless File.exist?(@config_path)
55
- init_config
56
- end
57
- end
58
-
59
- def load_config
60
- YAML.load_file(@config_path)
61
- end
62
-
63
- def save_config
64
- File.write(@config_path, @config.to_yaml)
65
- end
66
- end
67
- end
68
- end
@@ -1,24 +0,0 @@
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
@@ -1,44 +0,0 @@
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
@@ -1,20 +0,0 @@
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
@@ -1,28 +0,0 @@
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
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Patcmd
4
- module CLI
5
- module Presenters
6
- Dir[File.join(__dir__, "presenters", "*.rb")].each do |file|
7
- require file
8
- end
9
- end
10
- end
11
- end
@@ -1,24 +0,0 @@
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
@@ -1,33 +0,0 @@
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
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Patcmd
4
- module CLI
5
- module Services
6
- Dir[File.join(__dir__, "services", "*.rb")].each do |file|
7
- require file
8
- end
9
- end
10
- end
11
- end
@@ -1,17 +0,0 @@
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,22 +0,0 @@
1
- # frozen_string_literal: true
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
-
8
- module Patcmd
9
- module CLI
10
- class TaskExecutor
11
- def initialize(task, options)
12
- @task = Task.new(task)
13
- @options = options
14
- end
15
-
16
- def execute
17
- env_vars = EnvironmentPreparer.new(@options).prepare(@task.environments)
18
- CommandRunner.new(@task, @options, env_vars).execute
19
- end
20
- end
21
- end
22
- end