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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bb1d901493c286300b53d74441705dc7402263497e998f5490ca14beac572a5
4
- data.tar.gz: bc12fcce57604c61fe617eac640c3ab38e6204da916e73124162df78c519e803
3
+ metadata.gz: 34c1084f87c203c6d008d7c871bfeeeeba556d5208575df9a00c5c7e6c0f95a2
4
+ data.tar.gz: fa4ced1128644400b4bc691cbf9537570edf6246400dbea55a1944b2a3ec85a5
5
5
  SHA512:
6
- metadata.gz: 58b7e44b6210955e1b50fc2601cc018a2434c92c105436bf923ab818577448c8f11cc90ed81128bfa6290c86f455b6aeb4e444682d4966ebc04c7cab1f382c37
7
- data.tar.gz: 91636de5259a810060040aa51d3cc0fc1bb914358c679e2dc12dad59e639dafcbf3869a0a1f6886228e302154596195503315c92f9ed567cd6394ca708c1d2b1
6
+ metadata.gz: 9ad77d436e5dcdd4f8552bd19c60e53d253dd83daa1cba573c4e6a6f9c9a188ab15b5695e85a13612752e5a04acb624dd0c4e3a63a6342c3891c7efc3ee79c08
7
+ data.tar.gz: 303847847a630d6fdb089932957f7415ea163256c14ca728d163df3bfc64319037a7479acb81b127808119a95cccfedb796d36c97297ad0a5f36166869cbd95d
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 3.2
2
+ TargetRubyVersion: 3.3
3
3
 
4
4
  # Omakase Ruby styling for Rails
5
5
  inherit_gem:
@@ -66,5 +66,6 @@
66
66
  "files.trimTrailingWhitespace": true,
67
67
  "[sql]": {
68
68
  "editor.defaultFormatter": "adpyke.vscode-sql-formatter"
69
- }
69
+ },
70
+ "window.title": "jade_systems_toolbox"
70
71
  }
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 # docker compose down. Deletes the container. You probably want stop.
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 initilize_vscode # Initialize devcontainer.json for vscode
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 up # docker compose up -d
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). If you run `tool init` again, it will over-write your changes.
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 up
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
- ### Open a Terminal Session
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 "bin/rails s -b 0.0.0.0"
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
- # This and other improvements from Matt: https://mattbrictson.com/blog/fixing-thor-cli-behavior
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: "3.4", aliases: "-r"
35
- option :distro_version, default: "bookworm", aliases: "-t" # For Toy Story.
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: "3.4", aliases: "-r"
45
- option :distro_version, default: "bookworm", aliases: "-t" # For Toy Story.
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
- get_and_save_file(
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 "initilize_vscode", "Initialize devcontainer.json for vscode"
78
+ desc "initialize_vscode", "Initialize devcontainer.json for vscode"
67
79
  def initialize_vscode
68
- get_and_save_file("https://github.com/lcreid/docker/raw/refs/heads/main/.devcontainer.json") do |file_contents|
69
- file_contents.gsub!(/, "compose.override.yml"/, "") unless Gem::Platform.local.os == "linux"
70
- end
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", "service", "ports")
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 :service, default: "web"
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
- system("docker compose exec #{workdir}#{service} #{command}")
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 :service, default: "web"
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
- system("docker compose exec -it #{service} '/bin/bash'")
135
- end
136
-
137
- desc "up", "docker compose up -d"
138
- def up
139
- system("docker compose up -d")
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 = get_file_from_internet(url:)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JadeSystemsToolbox
4
- VERSION = "0.1.4"
4
+ VERSION = "0.2.0"
5
5
  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
@@ -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.1.4
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: 1980-01-02 00:00:00.000000000 Z
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.2'
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: 4.0.6
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: []