jade_systems_toolbox 0.1.3 → 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 +106 -11
- data/lib/jade_systems_toolbox/cli.rb +127 -75
- 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
|
@@ -27,20 +27,23 @@ gem install --user-install jade_systems_toolbox
|
|
|
27
27
|
|
|
28
28
|
### Summary
|
|
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
38
|
tool initialize_vscode # Initialize devcontainer.json for vscode
|
|
38
|
-
tool open # Open a page on the services's first port
|
|
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`)
|
|
44
|
+
tool stop # Stop the service(s) but preserve the container(s)
|
|
42
45
|
tool terminal # Run a shell in the container
|
|
43
|
-
tool
|
|
46
|
+
tool tree # Print a tree of all available commands
|
|
44
47
|
tool version # Show the version number of the tool.
|
|
45
48
|
|
|
46
49
|
Options:
|
|
@@ -60,7 +63,8 @@ The broad steps to start a brand new project are:
|
|
|
60
63
|
1. Run the editor and otherwise do what you need to do to create your project.
|
|
61
64
|
1. When the web server is ready to run (if you're developing a web app), run the server.
|
|
62
65
|
1. Open a browser window to the web server.
|
|
63
|
-
1. When you're done,
|
|
66
|
+
1. When you're done, stop the containers.
|
|
67
|
+
1. If you need to delete the containers, down tools.
|
|
64
68
|
|
|
65
69
|
To start:
|
|
66
70
|
|
|
@@ -100,19 +104,37 @@ To choose a different ruby version and Debian version:
|
|
|
100
104
|
tool init --ruby-version 3.2 --distro-version bullseye
|
|
101
105
|
```
|
|
102
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
|
+
|
|
103
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.
|
|
104
116
|
|
|
105
|
-
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.
|
|
106
118
|
|
|
107
119
|
#### Start the Containers
|
|
108
120
|
|
|
109
121
|
```bash
|
|
110
|
-
tool
|
|
122
|
+
tool start
|
|
111
123
|
```
|
|
112
124
|
|
|
113
125
|
This takes a while to run, the first time you run it when the image isn't already downloaded to your computer.
|
|
114
126
|
|
|
115
|
-
|
|
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
|
|
116
138
|
|
|
117
139
|
```bash
|
|
118
140
|
tool terminal
|
|
@@ -124,6 +146,14 @@ This connects to the `web` service defined in the `compose.yml` file. If you wan
|
|
|
124
146
|
tool terminal --service mysql
|
|
125
147
|
```
|
|
126
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
|
+
|
|
127
157
|
#### Start VScode
|
|
128
158
|
|
|
129
159
|
```bash
|
|
@@ -136,10 +166,22 @@ tool edit
|
|
|
136
166
|
tool server
|
|
137
167
|
```
|
|
138
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
|
+
|
|
139
181
|
This runs `bin/dev`. To run something else, e.g. a bare Puma so you can debug it:
|
|
140
182
|
|
|
141
183
|
```bash
|
|
142
|
-
tool server
|
|
184
|
+
tool server bin/rails s -b 0.0.0.0
|
|
143
185
|
```
|
|
144
186
|
|
|
145
187
|
If you have other services running servers, or the server is in a sub-directory of your project:
|
|
@@ -150,6 +192,8 @@ tool server --work-dir test/app --service monitor
|
|
|
150
192
|
|
|
151
193
|
To terminate the server, type Control-C.
|
|
152
194
|
|
|
195
|
+
`tool server` supports the `--env` argument as described under [Open a Terminal Session](open-a-terminal-session).
|
|
196
|
+
|
|
153
197
|
#### Open a Browser Window
|
|
154
198
|
|
|
155
199
|
To connect to the server running on service `web` on port 3000:
|
|
@@ -176,12 +220,63 @@ If you want to connect to a path other than `/`:
|
|
|
176
220
|
tool open --path letter_opener
|
|
177
221
|
```
|
|
178
222
|
|
|
223
|
+
#### Stop the Containers
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
tool stop
|
|
227
|
+
```
|
|
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
|
+
|
|
179
256
|
#### Bring Down the Containers
|
|
180
257
|
|
|
258
|
+
This destroys the containers, which will likely destroy all your gems.
|
|
259
|
+
|
|
181
260
|
```bash
|
|
182
261
|
tool down
|
|
183
262
|
```
|
|
184
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
|
+
|
|
274
|
+
Skip the confirmation mesage with:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
tool down --force
|
|
278
|
+
```
|
|
279
|
+
|
|
185
280
|
## Development
|
|
186
281
|
|
|
187
282
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
@@ -192,13 +287,13 @@ To test locally without installing, run the executable like this:
|
|
|
192
287
|
ruby -I lib exe/tool [COMMAND]
|
|
193
288
|
```
|
|
194
289
|
|
|
195
|
-
To run in another directory, use the path
|
|
290
|
+
To run in another directory, use the path from the directory you're in, to the directory where you checked out the gem's code. For example:
|
|
196
291
|
|
|
197
292
|
```bash
|
|
198
293
|
ruby -I ../jade_systems_toolbox/lib ../jade_systems_toolbox/exe/tool [COMMAND]
|
|
199
294
|
```
|
|
200
295
|
|
|
201
|
-
To install this gem onto your local machine, build it: `gem build jade_systems_toolbox.gemspec`, and install it: `gem install -l jade_systems_toolbox-0.1.
|
|
296
|
+
To install this gem onto your local machine, build it: `gem build jade_systems_toolbox.gemspec`, and install it: `gem install -l jade_systems_toolbox-0.1.4.gem`. (Change the version number to match the current version number.)
|
|
202
297
|
|
|
203
298
|
## Release
|
|
204
299
|
|
|
@@ -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,9 +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"
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
desc "down -- COMPOSE_ARGS", "docker compose down. Deletes the container. You probably want stop."
|
|
18
|
+
option :force, default: "n", aliases: "-f"
|
|
19
|
+
def down(*compose_args)
|
|
20
|
+
force = ask("tool down destroys the containers. Are you sure [y/N]?").downcase unless options[:force] == "y"
|
|
21
|
+
exit(1) if force[0] != "y"
|
|
22
|
+
|
|
23
|
+
system(([ "docker compose down" ] + compose_args).join(" "))
|
|
20
24
|
end
|
|
21
25
|
|
|
22
26
|
desc "edit", "devcontainer open"
|
|
@@ -24,57 +28,64 @@ module JadeSystemsToolbox
|
|
|
24
28
|
`devcontainer open`
|
|
25
29
|
end
|
|
26
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
|
+
|
|
27
56
|
desc "init", "Initialize compose files and devcontainer.json"
|
|
28
|
-
option :compose_file, default: "compose.yml"
|
|
29
57
|
option :database, default: "sqlite", aliases: "-d"
|
|
30
|
-
option :ruby_version, default: "
|
|
31
|
-
option :distro_version, default: "
|
|
58
|
+
option :ruby_version, default: "4.0", aliases: "-r"
|
|
59
|
+
option :distro_version, default: "trixie", aliases: "-t" # For Toy Story.
|
|
32
60
|
def init
|
|
33
61
|
invoke :initialize_docker
|
|
34
62
|
invoke :initialize_vscode, [], {}
|
|
35
63
|
end
|
|
36
64
|
|
|
37
65
|
desc "initialize_docker", "Initialize compose files"
|
|
38
|
-
option :compose_file, default: "compose.yml"
|
|
39
66
|
option :database, default: "sqlite", aliases: "-d"
|
|
40
|
-
option :ruby_version, default: "
|
|
41
|
-
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"
|
|
42
74
|
def initialize_docker
|
|
43
|
-
|
|
44
|
-
"https://github.com/lcreid/docker/raw/refs/heads/main/rails-app-sqlite/compose.yml",
|
|
45
|
-
) do |file_contents|
|
|
46
|
-
file_contents.gsub!(
|
|
47
|
-
/jade:rails-app-[0-9]+\.[0-9]+-\w+-\w+$/,
|
|
48
|
-
"jade:rails-app-#{options[:ruby_version] || "3.4"}" \
|
|
49
|
-
"-#{options[:database] || "sqlite"}" \
|
|
50
|
-
"-#{options[:distro_version] || bookworm}",
|
|
51
|
-
)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
case Gem::Platform.local.os
|
|
55
|
-
when "linux"
|
|
56
|
-
get_and_save_file("https://github.com/lcreid/docker/raw/refs/heads/main/Linux/compose.override.yml")
|
|
57
|
-
else
|
|
58
|
-
raise Error.new("Not implemented for #{Gem::Platform.local.os}", options[:verbose])
|
|
59
|
-
end
|
|
75
|
+
DockerInitializer.new(**options.transform_keys(&:to_sym).except(:verbose)).get_and_save_compose_files
|
|
60
76
|
end
|
|
61
77
|
|
|
62
|
-
desc "
|
|
78
|
+
desc "initialize_vscode", "Initialize devcontainer.json for vscode"
|
|
63
79
|
def initialize_vscode
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Dir.mkdir(".vscode") unless Dir.exist?(".vscode")
|
|
69
|
-
[
|
|
70
|
-
"https://github.com/lcreid/jade_systems_toolbox/raw/refs/heads/main/templates/extensions.json",
|
|
71
|
-
"https://github.com/lcreid/jade_systems_toolbox/raw/refs/heads/main/templates/settings.json",
|
|
72
|
-
].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
|
|
73
84
|
end
|
|
74
85
|
|
|
75
|
-
desc "open", "Open a page on the services's first port"
|
|
76
|
-
option :service, default: "web"
|
|
77
|
-
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"
|
|
78
89
|
option :container_port, default: 3000, type: :numeric
|
|
79
90
|
option :protocol, default: "http"
|
|
80
91
|
def open
|
|
@@ -83,14 +94,14 @@ module JadeSystemsToolbox
|
|
|
83
94
|
container_port = options[:container_port]
|
|
84
95
|
protocol = options[:protocol]
|
|
85
96
|
|
|
86
|
-
container_ports = compose_yaml.dig("services",
|
|
97
|
+
container_ports = compose_yaml.dig("services", service, "ports")
|
|
87
98
|
container_port = container_ports&.[](0) || container_port
|
|
88
99
|
path = "/#{path}" if path[0] != "/"
|
|
89
100
|
`open "#{protocol}://localhost:#{host_port_from_container_port(service:, container_port:)}#{path}"`
|
|
90
101
|
end
|
|
91
102
|
|
|
92
103
|
desc "port [CONTAINER_PORT]", "Get the host port for the CONTAINER_PORT's container port CONTAINER_PORT"
|
|
93
|
-
option :service, default: "web"
|
|
104
|
+
option :service, default: "web", aliases: "-s"
|
|
94
105
|
def port(container_port = 3000)
|
|
95
106
|
service = options[:service]
|
|
96
107
|
puts host_port_from_container_port(service:, container_port:)
|
|
@@ -109,25 +120,58 @@ module JadeSystemsToolbox
|
|
|
109
120
|
end
|
|
110
121
|
end
|
|
111
122
|
|
|
112
|
-
desc "server [COMMAND]", "Run the server in the container"
|
|
113
|
-
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"
|
|
114
127
|
option :work_dir, aliases: "-w"
|
|
115
|
-
def server(command = "bin/dev")
|
|
128
|
+
def server(command = "bin/dev", *args)
|
|
116
129
|
service = options[:service]
|
|
117
130
|
workdir = "-w #{options[:work_dir]} " unless options[:work_dir].nil?
|
|
118
|
-
|
|
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(" "))
|
|
150
|
+
end
|
|
151
|
+
map "up" => :start
|
|
152
|
+
|
|
153
|
+
desc "stop", "Stop the service(s) but preserve the container(s)"
|
|
154
|
+
def stop
|
|
155
|
+
system("docker compose stop")
|
|
119
156
|
end
|
|
120
157
|
|
|
121
158
|
desc "terminal", "Run a shell in the container"
|
|
122
|
-
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"
|
|
123
162
|
def terminal
|
|
124
163
|
service = options[:service]
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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)
|
|
131
175
|
end
|
|
132
176
|
|
|
133
177
|
desc "version", "Show the version number of the tool."
|
|
@@ -139,32 +183,14 @@ module JadeSystemsToolbox
|
|
|
139
183
|
|
|
140
184
|
def compose_yaml = @compose_yaml ||= YAML.load_file(options[:compose_file] || "compose.yml")
|
|
141
185
|
|
|
142
|
-
def get_and_save_file(url, target_directory: nil)
|
|
143
|
-
file_contents =
|
|
186
|
+
def get_and_save_file(url, target_directory: nil, target_file_name: nil)
|
|
187
|
+
file_contents = Http.get_file(url:)
|
|
144
188
|
yield file_contents if block_given?
|
|
145
|
-
file_name = Pathname.new(url).basename.to_s
|
|
189
|
+
file_name = target_file_name || Pathname.new(url).basename.to_s
|
|
146
190
|
file_name = Pathname.new(target_directory) + file_name unless target_directory.nil?
|
|
147
191
|
File.write(file_name, file_contents)
|
|
148
192
|
end
|
|
149
193
|
|
|
150
|
-
def get_file_from_internet(url:, redirects: 10)
|
|
151
|
-
raise Errorl.new("Too many redirects", options[:verbose]) if redirects.zero?
|
|
152
|
-
|
|
153
|
-
uri = URI.parse(url)
|
|
154
|
-
request = Net::HTTP.new(uri.host, uri.port)
|
|
155
|
-
request.use_ssl = true
|
|
156
|
-
response = request.get(uri.path)
|
|
157
|
-
|
|
158
|
-
case response
|
|
159
|
-
when Net::HTTPSuccess
|
|
160
|
-
response.body
|
|
161
|
-
when Net::HTTPRedirection
|
|
162
|
-
get_file_from_internet(redirects: redirects - 1, url: response["location"])
|
|
163
|
-
else
|
|
164
|
-
response.error!
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
194
|
def host_port_from_container_port(container_port:, service: "web")
|
|
169
195
|
ports = container_port.to_s.match(/([0-9]+:){0,1}([0-9]+$)/)
|
|
170
196
|
if !ports[1].nil?
|
|
@@ -174,5 +200,31 @@ module JadeSystemsToolbox
|
|
|
174
200
|
output.match(/[0-9]+$/)
|
|
175
201
|
end
|
|
176
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
|
|
177
229
|
end
|
|
178
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: 3.
|
|
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: []
|