patcmd 0.1.0 → 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 +4 -4
- data/.rubocop.yml +2 -0
- data/.vscode/launch.json +32 -0
- data/README.md +54 -61
- data/lib/patcmd/cli.rb +20 -2
- data/lib/patcmd/commands/add.rb +28 -0
- data/lib/patcmd/commands/base.rb +16 -0
- data/lib/patcmd/commands/exec.rb +23 -0
- data/lib/patcmd/commands/init.rb +20 -0
- data/lib/patcmd/commands/list.rb +24 -0
- data/lib/patcmd/commands/version.rb +15 -0
- data/lib/patcmd/configuration.rb +58 -0
- data/lib/patcmd/task.rb +30 -0
- data/lib/patcmd/version.rb +1 -1
- data/lib/patcmd.rb +2 -2
- metadata +19 -19
- data/lib/patcmd/cli/cli.rb +0 -11
- data/lib/patcmd/cli/commands/add_command.rb +0 -40
- data/lib/patcmd/cli/commands/base_command.rb +0 -24
- data/lib/patcmd/cli/commands/commands.rb +0 -15
- data/lib/patcmd/cli/commands/core.rb +0 -25
- data/lib/patcmd/cli/commands/exec_command.rb +0 -21
- data/lib/patcmd/cli/commands/init_command.rb +0 -15
- data/lib/patcmd/cli/commands/list_command.rb +0 -19
- data/lib/patcmd/cli/configuration_manager.rb +0 -68
- 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
- data/lib/patcmd/cli/task_executor.rb +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca00a46642b861edd38385a45ef93e6d6cae49f2dd0fec6a4a2237d19a90be14
|
4
|
+
data.tar.gz: c3bdbadaf8ab1fc83f712e4a41d64da0b5f3eb1b9e05f12d99fb0914172150db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50203822923ae061412d63b46dc351d9550ded803316372582f2d16b45b49b007fb38ae8e925ef6c91f178c55660352a806ccae2cb771862173a56916413ce59
|
7
|
+
data.tar.gz: 44c94cfb0f3aa36c8883ff3b193ebcee6112e76a9155dac48448b9b363289f41ab4659dbfd2813702c8a94ab5d37972717af22351b1d0da60e2c2dcfe293bebb
|
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
|
+
}
|
data/README.md
CHANGED
@@ -1,111 +1,104 @@
|
|
1
|
-
#
|
1
|
+
# Patcmd
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/patcmd)
|
4
4
|
[](https://github.com/patrick204nqh/patcmd/actions)
|
5
5
|
[](LICENSE)
|
6
6
|
|
7
|
-
|
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:**
|
12
|
-
- **
|
13
|
-
- **
|
14
|
-
- **
|
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
|
-
|
18
|
+
Add this line to your application's Gemfile:
|
19
19
|
|
20
|
-
|
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
|
-
|
24
|
+
Then execute:
|
36
25
|
|
37
26
|
```bash
|
38
|
-
|
27
|
+
bundle install
|
39
28
|
```
|
40
29
|
|
41
|
-
|
30
|
+
Or install it yourself as:
|
42
31
|
|
43
32
|
```bash
|
44
|
-
gem install
|
33
|
+
gem install patcmd
|
45
34
|
```
|
46
35
|
|
47
36
|
## Usage
|
48
37
|
|
49
|
-
|
50
|
-
|
51
|
-
### Initialize Configuration
|
38
|
+
### Initializing the Configuration File
|
52
39
|
|
53
|
-
|
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
|
-
|
60
|
-
|
61
|
-
```
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
###
|
65
|
+
### Listing Tasks
|
80
66
|
|
81
|
-
|
67
|
+
To list all available tasks, run:
|
82
68
|
|
83
69
|
```bash
|
84
70
|
patcmd list
|
85
71
|
```
|
86
72
|
|
87
|
-
###
|
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
|
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
|
-
|
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
|
-
|
90
|
+
To execute a task, for example the default **hello** task, run:
|
96
91
|
|
97
92
|
```bash
|
98
|
-
patcmd
|
99
|
-
patcmd help add
|
100
|
-
patcmd help list
|
93
|
+
patcmd exec hello
|
101
94
|
```
|
102
95
|
|
103
|
-
|
96
|
+
This command executes the task, applying the defined environment variables and arguments.
|
104
97
|
|
105
|
-
|
98
|
+
## Contributing
|
106
99
|
|
107
|
-
|
100
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/patrick204nqh/patcmd](https://github.com/patrick204nqh/patcmd).
|
108
101
|
|
109
|
-
|
110
|
-
|
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,7 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
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
|
+
|
4
10
|
module Patcmd
|
5
|
-
|
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")
|
6
24
|
end
|
7
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,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
|
data/lib/patcmd/task.rb
ADDED
@@ -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
|
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:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Huy Nguyen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
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:
|
28
|
-
|
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:
|
@@ -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,25 +45,24 @@ files:
|
|
44
45
|
- bin/patcmd
|
45
46
|
- lib/patcmd.rb
|
46
47
|
- lib/patcmd/cli.rb
|
47
|
-
- lib/patcmd/
|
48
|
-
- lib/patcmd/
|
49
|
-
- lib/patcmd/
|
50
|
-
- lib/patcmd/
|
51
|
-
- lib/patcmd/
|
52
|
-
- lib/patcmd/
|
53
|
-
- lib/patcmd/
|
54
|
-
- lib/patcmd/
|
55
|
-
- lib/patcmd/cli/configuration_manager.rb
|
56
|
-
- lib/patcmd/cli/helpers/helpers.rb
|
57
|
-
- lib/patcmd/cli/helpers/logger.rb
|
58
|
-
- lib/patcmd/cli/helpers/task_helper.rb
|
59
|
-
- 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
|
60
56
|
- lib/patcmd/version.rb
|
61
57
|
- sig/patcmd.rbs
|
62
58
|
homepage: https://github.com/patrick204nqh/patcmd
|
63
59
|
licenses:
|
64
60
|
- MIT
|
65
|
-
metadata:
|
61
|
+
metadata:
|
62
|
+
homepage_uri: https://github.com/patrick204nqh/patcmd
|
63
|
+
source_code_uri: https://github.com/patrick204nqh/patcmd
|
64
|
+
changelog_uri: https://github.com/patrick204nqh/patcmd/blob/main/CHANGELOG.md
|
65
|
+
documentation_uri: https://www.rubydoc.info/gems/patcmd
|
66
66
|
post_install_message:
|
67
67
|
rdoc_options: []
|
68
68
|
require_paths:
|
@@ -81,5 +81,5 @@ requirements: []
|
|
81
81
|
rubygems_version: 3.5.3
|
82
82
|
signing_key:
|
83
83
|
specification_version: 4
|
84
|
-
summary: A CLI tool
|
84
|
+
summary: A CLI tool to manage tasks using a YAML configuration.
|
85
85
|
test_files: []
|
data/lib/patcmd/cli/cli.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Patcmd
|
4
|
-
module CLI
|
5
|
-
class AddCommand < BaseCommand
|
6
|
-
default_task :add
|
7
|
-
|
8
|
-
desc "add", "Add a new task to the config"
|
9
|
-
method_option :name, aliases: "-n", required: true, desc: "Task name"
|
10
|
-
method_option :description, aliases: "-d", required: true, desc: "Task description"
|
11
|
-
method_option :category, aliases: "-c", required: true, desc: "Category name"
|
12
|
-
method_option :path, aliases: "-p", required: true, desc: "Execution path"
|
13
|
-
method_option :action, aliases: "-a", required: true, desc: "Action name"
|
14
|
-
method_option :command, aliases: "-m", required: true, desc: "Command to execute"
|
15
|
-
method_option :args, aliases: "-g", type: :array, default: [], desc: "Arguments for the command"
|
16
|
-
method_option :environments, aliases: "-e", type: :hash, default: {}, desc: "Environment variables"
|
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
|
25
|
-
|
26
|
-
def build_task_from_options
|
27
|
-
{
|
28
|
-
"name" => options[:name],
|
29
|
-
"description" => options[:description],
|
30
|
-
"category" => options[:category],
|
31
|
-
"path" => options[:path],
|
32
|
-
"action" => options[:action],
|
33
|
-
"command" => options[:command],
|
34
|
-
"args" => options[:args],
|
35
|
-
"environments" => options[:environments],
|
36
|
-
}
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Patcmd
|
4
|
-
module CLI
|
5
|
-
class BaseCommand < Thor
|
6
|
-
include Helpers::TaskHelper
|
7
|
-
include Helpers::Logger
|
8
|
-
|
9
|
-
CONFIG_PATH = File.expand_path("~/.patcmd/config.yml")
|
10
|
-
|
11
|
-
# Define global options
|
12
|
-
class_option :config, type: :string, default: CONFIG_PATH, desc: "Path to configuration file"
|
13
|
-
|
14
|
-
def initialize(*args)
|
15
|
-
super
|
16
|
-
@config_manager = ConfigurationManager.new(options[:config])
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
attr_reader :config_manager
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "base_command"
|
4
|
-
require_relative "init_command"
|
5
|
-
require_relative "add_command"
|
6
|
-
require_relative "list_command"
|
7
|
-
require_relative "exec_command"
|
8
|
-
|
9
|
-
module Patcmd
|
10
|
-
module CLI
|
11
|
-
class Core < Thor
|
12
|
-
class << self
|
13
|
-
# Ensure the CLI exits with a non-zero status code on failure
|
14
|
-
def exit_on_failure?
|
15
|
-
true
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
register InitCommand, "init", "init", "Initialize the PatCmd configuration"
|
20
|
-
register AddCommand, "add", "add", "Add a new task to the config"
|
21
|
-
register ListCommand, "list", "list", "List all configured tasks"
|
22
|
-
register ExecCommand, "exec", "exec CATEGORY NAME ACTION", "Execute a defined task"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Patcmd
|
4
|
-
module CLI
|
5
|
-
class ExecCommand < BaseCommand
|
6
|
-
default_task :exec
|
7
|
-
|
8
|
-
desc "exec CATEGORY NAME ACTION", "Execute a defined task"
|
9
|
-
def exec(category, name, action)
|
10
|
-
task = config_manager.find_task(category, name, action)
|
11
|
-
if task
|
12
|
-
executor = TaskExecutor.new(task, options)
|
13
|
-
executor.execute
|
14
|
-
else
|
15
|
-
puts "Task not found for category '#{category}', name '#{name}', and action '#{action}'."
|
16
|
-
exit(1)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Patcmd
|
4
|
-
module CLI
|
5
|
-
class InitCommand < BaseCommand
|
6
|
-
default_task :init
|
7
|
-
|
8
|
-
desc "init", "Initialize the PatCmd configuration"
|
9
|
-
def init
|
10
|
-
config_manager.init_config
|
11
|
-
puts "Configuration initialized at #{config_manager.config_path}"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Patcmd
|
4
|
-
module CLI
|
5
|
-
class ListCommand < BaseCommand
|
6
|
-
default_task :list
|
7
|
-
|
8
|
-
desc "list", "List all configured tasks"
|
9
|
-
def list
|
10
|
-
tasks = config_manager.all_tasks
|
11
|
-
if tasks.empty?
|
12
|
-
puts "No tasks configured."
|
13
|
-
else
|
14
|
-
tasks.each { |task| display_task(task) }
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
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,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
|
@@ -1,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Patcmd
|
4
|
-
module CLI
|
5
|
-
class TaskExecutor
|
6
|
-
require "shellwords"
|
7
|
-
|
8
|
-
def initialize(task, options)
|
9
|
-
@task = task
|
10
|
-
@options = options
|
11
|
-
end
|
12
|
-
|
13
|
-
def execute
|
14
|
-
command = prepare_command
|
15
|
-
env_vars = prepare_environment_variables
|
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))
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|