jade_systems_toolbox 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.vscode/settings.json +2 -1
- data/README.md +87 -8
- data/lib/jade_systems_toolbox/cli.rb +119 -76
- data/lib/jade_systems_toolbox/docker_initializer.rb +43 -0
- data/lib/jade_systems_toolbox/http.rb +33 -0
- data/lib/jade_systems_toolbox/version.rb +1 -1
- data/lib/jade_systems_toolbox/vscode.rb +52 -0
- data/lib/jade_systems_toolbox.rb +3 -1
- data/templates/.devcontainer.json +36 -0
- metadata +12 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 34c1084f87c203c6d008d7c871bfeeeeba556d5208575df9a00c5c7e6c0f95a2
|
|
4
|
+
data.tar.gz: fa4ced1128644400b4bc691cbf9537570edf6246400dbea55a1944b2a3ec85a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9ad77d436e5dcdd4f8552bd19c60e53d253dd83daa1cba573c4e6a6f9c9a188ab15b5695e85a13612752e5a04acb624dd0c4e3a63a6342c3891c7efc3ee79c08
|
|
7
|
+
data.tar.gz: 303847847a630d6fdb089932957f7415ea163256c14ca728d163df3bfc64319037a7479acb81b127808119a95cccfedb796d36c97297ad0a5f36166869cbd95d
|
data/.rubocop.yml
CHANGED
data/.vscode/settings.json
CHANGED
data/README.md
CHANGED
|
@@ -29,19 +29,21 @@ gem install --user-install jade_systems_toolbox
|
|
|
29
29
|
|
|
30
30
|
```terminal
|
|
31
31
|
Commands:
|
|
32
|
-
tool down
|
|
32
|
+
tool down -- COMPOSE_ARGS # docker compose down. Deletes the container. You probably want stop.
|
|
33
33
|
tool edit # devcontainer open
|
|
34
|
+
tool exec COMMAND [ARGS] # Run a command in the container and exit
|
|
34
35
|
tool help [COMMAND] # Describe available commands or one specific command
|
|
35
36
|
tool init # Initialize compose files and devcontainer.json
|
|
36
37
|
tool initialize_docker # Initialize compose files
|
|
37
|
-
tool
|
|
38
|
-
tool open # Open a page on the services's first port
|
|
38
|
+
tool initialize_vscode # Initialize devcontainer.json for vscode
|
|
39
|
+
tool open # Open a page on the services's first port or specified port
|
|
39
40
|
tool port [CONTAINER_PORT] # Get the host port for the CONTAINER_PORT's container port CONTAINER_PORT
|
|
40
41
|
tool ports # Get the host ports for the container ports defined in `compose.yml`
|
|
41
42
|
tool server [COMMAND] # Run the server in the container
|
|
43
|
+
tool start [COMPOSE_ARGS] # docker compose up -d (aliased as `up`)
|
|
42
44
|
tool stop # Stop the service(s) but preserve the container(s)
|
|
43
45
|
tool terminal # Run a shell in the container
|
|
44
|
-
tool
|
|
46
|
+
tool tree # Print a tree of all available commands
|
|
45
47
|
tool version # Show the version number of the tool.
|
|
46
48
|
|
|
47
49
|
Options:
|
|
@@ -102,19 +104,37 @@ To choose a different ruby version and Debian version:
|
|
|
102
104
|
tool init --ruby-version 3.2 --distro-version bullseye
|
|
103
105
|
```
|
|
104
106
|
|
|
107
|
+
A fairly common variant is to get a `compose.yml` that also has a Playwright container:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
tool init --end-to-end-tool playwright
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This retrieves the compose file, and puts it in your local `compose.yml`.
|
|
114
|
+
|
|
105
115
|
You can choose a currently supported Ruby version, and a Debian version that supports that Ruby version, from the containers built by https://github.com/lcreid/docker.
|
|
106
116
|
|
|
107
|
-
You're free to modify the `compose.yml` (and `compose.override.yml` on Linux).
|
|
117
|
+
You're free to modify the `compose.yml` (and `compose.override.yml` on Linux). Note that if you run `tool init` again, it will over-write your changes.
|
|
108
118
|
|
|
109
119
|
#### Start the Containers
|
|
110
120
|
|
|
111
121
|
```bash
|
|
112
|
-
tool
|
|
122
|
+
tool start
|
|
113
123
|
```
|
|
114
124
|
|
|
115
125
|
This takes a while to run, the first time you run it when the image isn't already downloaded to your computer.
|
|
116
126
|
|
|
117
|
-
|
|
127
|
+
You can add additional Docker Compose arguments to the command line. For example:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
tool start --remove-orphans
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If any of the command's arguments are the same as any of `tool`'s arguments,
|
|
134
|
+
separate the `exec` command from the rest of the command line with `--`,
|
|
135
|
+
like this: `tool start -- -v`.
|
|
136
|
+
|
|
137
|
+
#### Open a Terminal Session
|
|
118
138
|
|
|
119
139
|
```bash
|
|
120
140
|
tool terminal
|
|
@@ -126,6 +146,14 @@ This connects to the `web` service defined in the `compose.yml` file. If you wan
|
|
|
126
146
|
tool terminal --service mysql
|
|
127
147
|
```
|
|
128
148
|
|
|
149
|
+
Set some environment variables in the container (the `docker compose --env` flag):
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
tool terminal -e RAILS_ENV=test
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`tool terminal` supports the `--mapping` argument as described under [Run the Server](run-the-server).
|
|
156
|
+
|
|
129
157
|
#### Start VScode
|
|
130
158
|
|
|
131
159
|
```bash
|
|
@@ -138,10 +166,22 @@ tool edit
|
|
|
138
166
|
tool server
|
|
139
167
|
```
|
|
140
168
|
|
|
169
|
+
By default, the container has environment variables set for port mapping.
|
|
170
|
+
The container environment will have variables named `HOST_PORT_xxxx`,
|
|
171
|
+
and `xxxx` is the container port (e.g. 3000).
|
|
172
|
+
The _value_ of each environment variable
|
|
173
|
+
is the host's port number that the container port is mapped to.
|
|
174
|
+
|
|
175
|
+
If you don't want the mapping, you can turn it off:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
tool server --no-mapping
|
|
179
|
+
```
|
|
180
|
+
|
|
141
181
|
This runs `bin/dev`. To run something else, e.g. a bare Puma so you can debug it:
|
|
142
182
|
|
|
143
183
|
```bash
|
|
144
|
-
tool server
|
|
184
|
+
tool server bin/rails s -b 0.0.0.0
|
|
145
185
|
```
|
|
146
186
|
|
|
147
187
|
If you have other services running servers, or the server is in a sub-directory of your project:
|
|
@@ -152,6 +192,8 @@ tool server --work-dir test/app --service monitor
|
|
|
152
192
|
|
|
153
193
|
To terminate the server, type Control-C.
|
|
154
194
|
|
|
195
|
+
`tool server` supports the `--env` argument as described under [Open a Terminal Session](open-a-terminal-session).
|
|
196
|
+
|
|
155
197
|
#### Open a Browser Window
|
|
156
198
|
|
|
157
199
|
To connect to the server running on service `web` on port 3000:
|
|
@@ -184,6 +226,33 @@ tool open --path letter_opener
|
|
|
184
226
|
tool stop
|
|
185
227
|
```
|
|
186
228
|
|
|
229
|
+
You can add additional Docker Compose arguments to the command line. For example:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
tool stop --remove-orphans
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
If any of the command's arguments are the same as any of `tool`'s arguments,
|
|
236
|
+
separate the `exec` command from the rest of the command line with `--`,
|
|
237
|
+
like this: `tool stop -- -v`.
|
|
238
|
+
|
|
239
|
+
#### Run a Single Command in a Container
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
tool exec ls -l ..
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Some things to watch for:
|
|
246
|
+
|
|
247
|
+
- If any of the command's arguments are the same as any of `tool`'s arguments,
|
|
248
|
+
separate the `exec` command from the rest of the command line with `--`,
|
|
249
|
+
like this: `tool exec -- ls -l -t ..`.
|
|
250
|
+
- The shell on the host processes the command line,
|
|
251
|
+
so you need to quote or escape the command if you want variable expansion
|
|
252
|
+
and other shell features to happen in the container.
|
|
253
|
+
For example: `tool exec ls -l '$HOME'` to show the home directory in the container, not your home directory
|
|
254
|
+
(which probably doesn't exist in the container).
|
|
255
|
+
|
|
187
256
|
#### Bring Down the Containers
|
|
188
257
|
|
|
189
258
|
This destroys the containers, which will likely destroy all your gems.
|
|
@@ -192,6 +261,16 @@ This destroys the containers, which will likely destroy all your gems.
|
|
|
192
261
|
tool down
|
|
193
262
|
```
|
|
194
263
|
|
|
264
|
+
You can add additional Docker Compose arguments to the command line. For example: NOTE THAT THE FOLLOWING COMMAND IS VERY DESTRUCTIVE. It destroys the volume where you might have your development and test databases, or other important data:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
tool start -- -v
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
If any of the command's arguments are the same as any of `tool`'s arguments,
|
|
271
|
+
separate the `exec` command from the rest of the command line with `--`,
|
|
272
|
+
like this: `tool down -- -v`.
|
|
273
|
+
|
|
195
274
|
Skip the confirmation mesage with:
|
|
196
275
|
|
|
197
276
|
```bash
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module JadeSystemsToolbox
|
|
4
4
|
class Cli < Thor
|
|
5
|
-
|
|
6
|
-
check_unknown_options!
|
|
5
|
+
stop_on_unknown_option! :down
|
|
7
6
|
|
|
8
7
|
class << self
|
|
8
|
+
# This and other improvements from Matt: https://mattbrictson.com/blog/fixing-thor-cli-behavior
|
|
9
9
|
def exit_on_failure? = true
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -14,13 +14,13 @@ module JadeSystemsToolbox
|
|
|
14
14
|
|
|
15
15
|
class_option :verbose, type: :boolean, default: false, aliases: "-v"
|
|
16
16
|
|
|
17
|
-
desc "down", "docker compose down. Deletes the container. You probably want stop."
|
|
17
|
+
desc "down -- COMPOSE_ARGS", "docker compose down. Deletes the container. You probably want stop."
|
|
18
18
|
option :force, default: "n", aliases: "-f"
|
|
19
|
-
def down
|
|
20
|
-
force = ask("tool down destroys the containers. Are you sure?").downcase unless options[:force] == "y"
|
|
19
|
+
def down(*compose_args)
|
|
20
|
+
force = ask("tool down destroys the containers. Are you sure [y/N]?").downcase unless options[:force] == "y"
|
|
21
21
|
exit(1) if force[0] != "y"
|
|
22
22
|
|
|
23
|
-
system("docker compose down")
|
|
23
|
+
system(([ "docker compose down" ] + compose_args).join(" "))
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
desc "edit", "devcontainer open"
|
|
@@ -28,57 +28,64 @@ module JadeSystemsToolbox
|
|
|
28
28
|
`devcontainer open`
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
desc "exec COMMAND [ARGS]", "Run a command in the container and exit"
|
|
32
|
+
option :env, repeatable: true, default: [], aliases: "-e", banner: "VAR=value"
|
|
33
|
+
option :mapping, type: :boolean, default: true, aliases: "-m"
|
|
34
|
+
option :service, default: "web", aliases: "-s"
|
|
35
|
+
option :work_dir, aliases: "-w"
|
|
36
|
+
def exec(command_for_container, *args)
|
|
37
|
+
service = options[:service]
|
|
38
|
+
workdir = "-w #{options[:work_dir]} " unless options[:work_dir].nil?
|
|
39
|
+
environment_variables = options[:env].map { "-e #{_1}" }.join(" ")
|
|
40
|
+
port_map_environment_variables = port_map_for_environment(service) if options[:mapping]
|
|
41
|
+
shell_command = [ command_for_container, *args ].join(" ")
|
|
42
|
+
command = [
|
|
43
|
+
"docker compose exec",
|
|
44
|
+
environment_variables,
|
|
45
|
+
port_map_environment_variables,
|
|
46
|
+
workdir,
|
|
47
|
+
"-it",
|
|
48
|
+
service,
|
|
49
|
+
"sh -c",
|
|
50
|
+
"'#{shell_command}'",
|
|
51
|
+
].compact.join(" ")
|
|
52
|
+
|
|
53
|
+
system(command)
|
|
54
|
+
end
|
|
55
|
+
|
|
31
56
|
desc "init", "Initialize compose files and devcontainer.json"
|
|
32
|
-
option :compose_file, default: "compose.yml"
|
|
33
57
|
option :database, default: "sqlite", aliases: "-d"
|
|
34
|
-
option :ruby_version, default: "
|
|
35
|
-
option :distro_version, default: "
|
|
58
|
+
option :ruby_version, default: "4.0", aliases: "-r"
|
|
59
|
+
option :distro_version, default: "trixie", aliases: "-t" # For Toy Story.
|
|
36
60
|
def init
|
|
37
61
|
invoke :initialize_docker
|
|
38
62
|
invoke :initialize_vscode, [], {}
|
|
39
63
|
end
|
|
40
64
|
|
|
41
65
|
desc "initialize_docker", "Initialize compose files"
|
|
42
|
-
option :compose_file, default: "compose.yml"
|
|
43
66
|
option :database, default: "sqlite", aliases: "-d"
|
|
44
|
-
option :ruby_version, default: "
|
|
45
|
-
option :distro_version, default: "
|
|
67
|
+
option :ruby_version, default: "4.0", aliases: "-r"
|
|
68
|
+
option :distro_version, default: "trixie", aliases: "-t" # For Toy Story.
|
|
69
|
+
method_option :end_to_end_tool,
|
|
70
|
+
type: :string,
|
|
71
|
+
enum: [ "playwright", "selenium" ],
|
|
72
|
+
desc: "Use an end-to-end (browser) testing tool",
|
|
73
|
+
aliases: "-e"
|
|
46
74
|
def initialize_docker
|
|
47
|
-
|
|
48
|
-
"https://github.com/lcreid/docker/raw/refs/heads/main/rails-app-sqlite/compose.yml",
|
|
49
|
-
) do |file_contents|
|
|
50
|
-
file_contents.gsub!(
|
|
51
|
-
/jade:rails-app-[0-9]+\.[0-9]+-\w+-\w+$/,
|
|
52
|
-
"jade:rails-app-#{options[:ruby_version] || "3.4"}" \
|
|
53
|
-
"-#{options[:database] || "sqlite"}" \
|
|
54
|
-
"-#{options[:distro_version] || "bookworm"}",
|
|
55
|
-
)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
case Gem::Platform.local.os
|
|
59
|
-
when "linux"
|
|
60
|
-
get_and_save_file("https://github.com/lcreid/docker/raw/refs/heads/main/Linux/compose.override.yml")
|
|
61
|
-
else
|
|
62
|
-
raise Error.new("Not implemented for #{Gem::Platform.local.os}", options[:verbose])
|
|
63
|
-
end
|
|
75
|
+
DockerInitializer.new(**options.transform_keys(&:to_sym).except(:verbose)).get_and_save_compose_files
|
|
64
76
|
end
|
|
65
77
|
|
|
66
|
-
desc "
|
|
78
|
+
desc "initialize_vscode", "Initialize devcontainer.json for vscode"
|
|
67
79
|
def initialize_vscode
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
Dir.mkdir(".vscode") unless Dir.exist?(".vscode")
|
|
73
|
-
[
|
|
74
|
-
"https://github.com/lcreid/jade_systems_toolbox/raw/refs/heads/main/templates/extensions.json",
|
|
75
|
-
"https://github.com/lcreid/jade_systems_toolbox/raw/refs/heads/main/templates/settings.json",
|
|
76
|
-
].each { get_and_save_file(_1, target_directory: File.join(".", ".vscode")) }
|
|
80
|
+
initializer = Vscode.new
|
|
81
|
+
initializer.write_devcontainer_json
|
|
82
|
+
initializer.write_extensions_json
|
|
83
|
+
initializer.write_settings_json
|
|
77
84
|
end
|
|
78
85
|
|
|
79
|
-
desc "open", "Open a page on the services's first port"
|
|
80
|
-
option :service, default: "web"
|
|
81
|
-
option :path, default: "/"
|
|
86
|
+
desc "open", "Open a page on the services's first port or specified port"
|
|
87
|
+
option :service, default: "web", aliases: "-s"
|
|
88
|
+
option :path, default: "/", alias: "-p"
|
|
82
89
|
option :container_port, default: 3000, type: :numeric
|
|
83
90
|
option :protocol, default: "http"
|
|
84
91
|
def open
|
|
@@ -87,14 +94,14 @@ module JadeSystemsToolbox
|
|
|
87
94
|
container_port = options[:container_port]
|
|
88
95
|
protocol = options[:protocol]
|
|
89
96
|
|
|
90
|
-
container_ports = compose_yaml.dig("services",
|
|
97
|
+
container_ports = compose_yaml.dig("services", service, "ports")
|
|
91
98
|
container_port = container_ports&.[](0) || container_port
|
|
92
99
|
path = "/#{path}" if path[0] != "/"
|
|
93
100
|
`open "#{protocol}://localhost:#{host_port_from_container_port(service:, container_port:)}#{path}"`
|
|
94
101
|
end
|
|
95
102
|
|
|
96
103
|
desc "port [CONTAINER_PORT]", "Get the host port for the CONTAINER_PORT's container port CONTAINER_PORT"
|
|
97
|
-
option :service, default: "web"
|
|
104
|
+
option :service, default: "web", aliases: "-s"
|
|
98
105
|
def port(container_port = 3000)
|
|
99
106
|
service = options[:service]
|
|
100
107
|
puts host_port_from_container_port(service:, container_port:)
|
|
@@ -113,14 +120,35 @@ module JadeSystemsToolbox
|
|
|
113
120
|
end
|
|
114
121
|
end
|
|
115
122
|
|
|
116
|
-
desc "server [COMMAND]", "Run the server in the container"
|
|
117
|
-
option :
|
|
123
|
+
desc "server [COMMAND] [ARGS]", "Run the server in the container"
|
|
124
|
+
option :env, repeatable: true, default: [], aliases: "-e", banner: "VAR=value"
|
|
125
|
+
option :mapping, type: :boolean, default: true, aliases: "-m"
|
|
126
|
+
option :service, default: "web", aliases: "-s"
|
|
118
127
|
option :work_dir, aliases: "-w"
|
|
119
|
-
def server(command = "bin/dev")
|
|
128
|
+
def server(command = "bin/dev", *args)
|
|
120
129
|
service = options[:service]
|
|
121
130
|
workdir = "-w #{options[:work_dir]} " unless options[:work_dir].nil?
|
|
122
|
-
|
|
131
|
+
environment_variables = options[:env].map { "-e #{_1}" }.join(" ")
|
|
132
|
+
port_map_environment_variables = port_map_for_environment(service) if options[:mapping]
|
|
133
|
+
shell_command = [ command, *args ].join(" ")
|
|
134
|
+
compose_command = [
|
|
135
|
+
"docker compose exec",
|
|
136
|
+
environment_variables,
|
|
137
|
+
port_map_environment_variables,
|
|
138
|
+
workdir,
|
|
139
|
+
service,
|
|
140
|
+
"sh -c",
|
|
141
|
+
"'#{shell_command}'",
|
|
142
|
+
].compact.join(" ")
|
|
143
|
+
|
|
144
|
+
system(compose_command)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
desc "start [COMPOSE_ARGS]", "docker compose up -d (aliased as `up`)"
|
|
148
|
+
def start(*compose_args)
|
|
149
|
+
system(([ "docker compose up -d" ] + compose_args).join(" "))
|
|
123
150
|
end
|
|
151
|
+
map "up" => :start
|
|
124
152
|
|
|
125
153
|
desc "stop", "Stop the service(s) but preserve the container(s)"
|
|
126
154
|
def stop
|
|
@@ -128,15 +156,22 @@ module JadeSystemsToolbox
|
|
|
128
156
|
end
|
|
129
157
|
|
|
130
158
|
desc "terminal", "Run a shell in the container"
|
|
131
|
-
option :
|
|
159
|
+
option :env, repeatable: true, default: [], aliases: "-e", banner: "VAR=value"
|
|
160
|
+
option :mapping, type: :boolean, default: true, aliases: "-m"
|
|
161
|
+
option :service, default: "web", aliases: "-s"
|
|
132
162
|
def terminal
|
|
133
163
|
service = options[:service]
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
164
|
+
environment_variables = options[:env].map { "-e #{_1}" }.join(" ")
|
|
165
|
+
port_map_environment_variables = port_map_for_environment(service) if options[:mapping]
|
|
166
|
+
command = [
|
|
167
|
+
"docker compose exec",
|
|
168
|
+
environment_variables,
|
|
169
|
+
port_map_environment_variables,
|
|
170
|
+
"-it",
|
|
171
|
+
service,
|
|
172
|
+
"'/bin/bash'",
|
|
173
|
+
].join(" ")
|
|
174
|
+
system(command)
|
|
140
175
|
end
|
|
141
176
|
|
|
142
177
|
desc "version", "Show the version number of the tool."
|
|
@@ -148,32 +183,14 @@ module JadeSystemsToolbox
|
|
|
148
183
|
|
|
149
184
|
def compose_yaml = @compose_yaml ||= YAML.load_file(options[:compose_file] || "compose.yml")
|
|
150
185
|
|
|
151
|
-
def get_and_save_file(url, target_directory: nil)
|
|
152
|
-
file_contents =
|
|
186
|
+
def get_and_save_file(url, target_directory: nil, target_file_name: nil)
|
|
187
|
+
file_contents = Http.get_file(url:)
|
|
153
188
|
yield file_contents if block_given?
|
|
154
|
-
file_name = Pathname.new(url).basename.to_s
|
|
189
|
+
file_name = target_file_name || Pathname.new(url).basename.to_s
|
|
155
190
|
file_name = Pathname.new(target_directory) + file_name unless target_directory.nil?
|
|
156
191
|
File.write(file_name, file_contents)
|
|
157
192
|
end
|
|
158
193
|
|
|
159
|
-
def get_file_from_internet(url:, redirects: 10)
|
|
160
|
-
raise Errorl.new("Too many redirects", options[:verbose]) if redirects.zero?
|
|
161
|
-
|
|
162
|
-
uri = URI.parse(url)
|
|
163
|
-
request = Net::HTTP.new(uri.host, uri.port)
|
|
164
|
-
request.use_ssl = true
|
|
165
|
-
response = request.get(uri.path)
|
|
166
|
-
|
|
167
|
-
case response
|
|
168
|
-
when Net::HTTPSuccess
|
|
169
|
-
response.body
|
|
170
|
-
when Net::HTTPRedirection
|
|
171
|
-
get_file_from_internet(redirects: redirects - 1, url: response["location"])
|
|
172
|
-
else
|
|
173
|
-
response.error!
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
194
|
def host_port_from_container_port(container_port:, service: "web")
|
|
178
195
|
ports = container_port.to_s.match(/([0-9]+:){0,1}([0-9]+$)/)
|
|
179
196
|
if !ports[1].nil?
|
|
@@ -183,5 +200,31 @@ module JadeSystemsToolbox
|
|
|
183
200
|
output.match(/[0-9]+$/)
|
|
184
201
|
end
|
|
185
202
|
end
|
|
203
|
+
|
|
204
|
+
def port_map(service)
|
|
205
|
+
service_ports = compose_yaml.dig("services", service, "ports")
|
|
206
|
+
service_ports&.reduce({}) do |acc, port|
|
|
207
|
+
acc[port] = host_port_from_container_port(container_port: port, service:).to_s
|
|
208
|
+
acc
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def port_map_for_environment(service)
|
|
213
|
+
port_map(service).map do |container_port, host_port|
|
|
214
|
+
"-e HOST_PORT_#{container_port}=#{host_port}"
|
|
215
|
+
end.join(" ")
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def handle_argument_error(command, error, args, arity)
|
|
219
|
+
# Check if the error is due to an unknown option or incorrect invocation
|
|
220
|
+
if (error.is_a?(Thor::UnknownArgumentError) || error.message.include?("was called with arguments")) &&
|
|
221
|
+
[ "down" ].include?(command)
|
|
222
|
+
# Return to let Thor proceed instead of raising the error
|
|
223
|
+
nil
|
|
224
|
+
else
|
|
225
|
+
# Fallback to standard Thor behavior for actual code bugs
|
|
226
|
+
super
|
|
227
|
+
end
|
|
228
|
+
end
|
|
186
229
|
end
|
|
187
230
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JadeSystemsToolbox
|
|
4
|
+
class DockerInitializer
|
|
5
|
+
def initialize(compose_file: nil, database: nil, ruby_version: nil, distro_version: nil, end_to_end_tool: nil)
|
|
6
|
+
@end_to_end_tool = end_to_end_tool&.downcase&.strip
|
|
7
|
+
database = database.to_s.downcase.strip
|
|
8
|
+
@database = database unless %w[false none nil ""].include?(database)
|
|
9
|
+
@ruby_version = ruby_version&.downcase&.strip
|
|
10
|
+
@distro_version = distro_version&.downcase&.strip
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def compose_file_path
|
|
14
|
+
base_dir = [ "rails-app", database ].compact.join("-")
|
|
15
|
+
Pathname("compose-files").join(*([ base_dir, end_to_end_tool, "compose.yml" ].compact))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def get_and_save_compose_files
|
|
19
|
+
compose_file = Http.get_file(url: Http.url(path: compose_file_path))
|
|
20
|
+
customize_compose_file!(compose_file)
|
|
21
|
+
File.write("compose.yml", compose_file)
|
|
22
|
+
|
|
23
|
+
case Gem::Platform.local.os
|
|
24
|
+
when "linux"
|
|
25
|
+
compose_override_file = Http.get_file(url: Http.url(path: "compose-files/Linux/compose.override.yml"))
|
|
26
|
+
File.write("compose.override.yml", compose_override_file)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def customize_compose_file!(base_file)
|
|
31
|
+
base_file.gsub!("${RUBY_VERSION:-4.0}", ruby_version) unless ruby_version.nil?
|
|
32
|
+
base_file.gsub!("${DISTRO_VERSION:-trixie}", distro_version) unless distro_version.nil?
|
|
33
|
+
base_file
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
attr_reader :end_to_end_tool
|
|
39
|
+
attr_reader :database
|
|
40
|
+
attr_reader :ruby_version
|
|
41
|
+
attr_reader :distro_version
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JadeSystemsToolbox
|
|
4
|
+
class Http
|
|
5
|
+
class << self
|
|
6
|
+
def url(path:)
|
|
7
|
+
base_url + path.to_s
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def get_file(url:, redirects: 10)
|
|
11
|
+
raise Error.new("Too many redirects", options[:verbose]) if redirects.zero?
|
|
12
|
+
|
|
13
|
+
uri = URI.parse(url)
|
|
14
|
+
request = Net::HTTP.new(uri.host, uri.port)
|
|
15
|
+
request.use_ssl = true
|
|
16
|
+
response = request.get(uri.path)
|
|
17
|
+
|
|
18
|
+
case response
|
|
19
|
+
when Net::HTTPSuccess
|
|
20
|
+
response.body
|
|
21
|
+
when Net::HTTPRedirection
|
|
22
|
+
get_file(redirects: redirects - 1, url: response["location"])
|
|
23
|
+
else
|
|
24
|
+
response.value
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def base_url = "https://github.com/lcreid/jade_systems_toolbox/raw/refs/heads/main/"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module JadeSystemsToolbox
|
|
6
|
+
class Vscode
|
|
7
|
+
def write_settings_json
|
|
8
|
+
target_file = target_directory.join("settings.json")
|
|
9
|
+
settings = if !target_file.exist? || target_file.empty?
|
|
10
|
+
{}
|
|
11
|
+
else
|
|
12
|
+
JSON.load_file(target_file)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
settings["window.title"] = Pathname.pwd.basename
|
|
16
|
+
File.write(target_file, JSON.pretty_generate(settings))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def write_devcontainer_json
|
|
20
|
+
devcontainer_text = Http.get_file(url: Http.url(path: "templates/.devcontainer.json"))
|
|
21
|
+
devcontainer_json = JSON.parse(devcontainer_text, allow_comments: true)
|
|
22
|
+
unless Gem::Platform.local.os == "linux"
|
|
23
|
+
devcontainer_json["dockerComposeFile"] = [ "compose.yml" ]
|
|
24
|
+
end
|
|
25
|
+
Pathname(".devcontainer.json").write(JSON.pretty_generate(devcontainer_json))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def write_extensions_json
|
|
29
|
+
extensions_text = Http.get_file(url: Http.url(path: "templates/extensions.json"))
|
|
30
|
+
target_directory.join("extensions.json").write(extensions_text)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def get_and_write_settings_json
|
|
34
|
+
settings_text = Http.get_file(url: Http.url(path: "templates/settings.json"))
|
|
35
|
+
settings = JSON.parse(settings_text, allow_comments: true)
|
|
36
|
+
settings["window.title"] = Pathname.pwd.basename
|
|
37
|
+
|
|
38
|
+
target_file = target_directory.join("settings.json")
|
|
39
|
+
File.write(target_file, JSON.pretty_generate(settings))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def target_directory
|
|
45
|
+
@target_directory unless @target_directory.nil?
|
|
46
|
+
|
|
47
|
+
@target_directory = Pathname("./.vscode")
|
|
48
|
+
FileUtils.mkdir(@target_directory) unless @target_directory.exist?
|
|
49
|
+
@target_directory
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/jade_systems_toolbox.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "debug"
|
|
4
3
|
require "net/http"
|
|
5
4
|
require "pathname"
|
|
6
5
|
require "thor"
|
|
@@ -8,7 +7,10 @@ require "yaml"
|
|
|
8
7
|
|
|
9
8
|
require_relative "jade_systems_toolbox/version"
|
|
10
9
|
require_relative "jade_systems_toolbox/cli"
|
|
10
|
+
require_relative "jade_systems_toolbox/docker_initializer"
|
|
11
11
|
require_relative "jade_systems_toolbox/error_reporter"
|
|
12
|
+
require_relative "jade_systems_toolbox/http"
|
|
13
|
+
require_relative "jade_systems_toolbox/vscode"
|
|
12
14
|
|
|
13
15
|
module JadeSystemsToolbox
|
|
14
16
|
class Error < StandardError
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
|
2
|
+
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose
|
|
3
|
+
{
|
|
4
|
+
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
|
|
5
|
+
"dockerComposeFile": ["compose.yml", "compose.override.yml"],
|
|
6
|
+
|
|
7
|
+
// The 'service' property is the name of the service for the container that VS Code should
|
|
8
|
+
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
|
|
9
|
+
"service": "web",
|
|
10
|
+
|
|
11
|
+
// The optional 'workspaceFolder' property is the path VS Code should open by default when
|
|
12
|
+
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
|
|
13
|
+
"workspaceFolder": "/home/dev/app",
|
|
14
|
+
// "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}"
|
|
15
|
+
|
|
16
|
+
// Features to add to the dev container. More info: https://containers.dev/features.
|
|
17
|
+
// "features": {},
|
|
18
|
+
|
|
19
|
+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
|
20
|
+
// "forwardPorts": [],
|
|
21
|
+
|
|
22
|
+
// Uncomment the next line if you want start specific services in your Docker Compose config.
|
|
23
|
+
// "runServices": [],
|
|
24
|
+
|
|
25
|
+
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
|
|
26
|
+
"shutdownAction": "none"
|
|
27
|
+
|
|
28
|
+
// Uncomment the next line to run commands after the container is created.
|
|
29
|
+
// "postCreateCommand": "cat /etc/os-release",
|
|
30
|
+
|
|
31
|
+
// Configure tool-specific properties.
|
|
32
|
+
// "customizations": {},
|
|
33
|
+
|
|
34
|
+
// Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
|
|
35
|
+
// "remoteUser": "devcontainer"
|
|
36
|
+
}
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jade_systems_toolbox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Larry Reid
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-11-09 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: thor
|
|
@@ -23,6 +24,7 @@ dependencies:
|
|
|
23
24
|
- - "~>"
|
|
24
25
|
- !ruby/object:Gem::Version
|
|
25
26
|
version: '1.3'
|
|
27
|
+
description:
|
|
26
28
|
email:
|
|
27
29
|
- lcreid@jadesystems.ca
|
|
28
30
|
executables:
|
|
@@ -41,9 +43,13 @@ files:
|
|
|
41
43
|
- exe/tool
|
|
42
44
|
- lib/jade_systems_toolbox.rb
|
|
43
45
|
- lib/jade_systems_toolbox/cli.rb
|
|
46
|
+
- lib/jade_systems_toolbox/docker_initializer.rb
|
|
44
47
|
- lib/jade_systems_toolbox/error_reporter.rb
|
|
48
|
+
- lib/jade_systems_toolbox/http.rb
|
|
45
49
|
- lib/jade_systems_toolbox/version.rb
|
|
50
|
+
- lib/jade_systems_toolbox/vscode.rb
|
|
46
51
|
- sig/jade_systems_toolbox.rbs
|
|
52
|
+
- templates/.devcontainer.json
|
|
47
53
|
- templates/extensions.json
|
|
48
54
|
- templates/settings.json
|
|
49
55
|
homepage: https://github.com/lcreid/jade_systems_toolbox
|
|
@@ -53,6 +59,7 @@ metadata:
|
|
|
53
59
|
homepage_uri: https://github.com/lcreid/jade_systems_toolbox
|
|
54
60
|
source_code_uri: https://github.com/lcreid/jade_systems_toolbox
|
|
55
61
|
changelog_uri: https://github.com/lcreid/jade_systems_toolbox/CHANGELOG.nd
|
|
62
|
+
post_install_message:
|
|
56
63
|
rdoc_options: []
|
|
57
64
|
require_paths:
|
|
58
65
|
- lib
|
|
@@ -60,14 +67,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
60
67
|
requirements:
|
|
61
68
|
- - ">="
|
|
62
69
|
- !ruby/object:Gem::Version
|
|
63
|
-
version: '3.
|
|
70
|
+
version: '3.3'
|
|
64
71
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
72
|
requirements:
|
|
66
73
|
- - ">="
|
|
67
74
|
- !ruby/object:Gem::Version
|
|
68
75
|
version: '0'
|
|
69
76
|
requirements: []
|
|
70
|
-
rubygems_version:
|
|
77
|
+
rubygems_version: 3.5.22
|
|
78
|
+
signing_key:
|
|
71
79
|
specification_version: 4
|
|
72
80
|
summary: A collection of command line commands to support development.
|
|
73
81
|
test_files: []
|