devbox_launcher 0.3.0 → 0.3.5

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: 2b3edb043751826ec3d3dfec5c5cbfe867cecd1da4938f5f5b7fee2401903387
4
- data.tar.gz: 51d6d27541b6933ab9f7e2eca6a3c1d74bcf455fd6a447dabb9dcfe09852abb7
3
+ metadata.gz: 0ec99b19a115672c4122d2c1b8827727d32d184fa9fee7328ab503b85529f3d9
4
+ data.tar.gz: 230126704d2e2d5cc7d8c9be29450ec35ccc9d716b605c2831696155f6889eca
5
5
  SHA512:
6
- metadata.gz: b213b9982c3c7ffbc16db6b2555e4ef1ed4ab7ff59a0a3e10bbd6a7c800ce60006615dedb2caae32353ea27331a9c89b97fc30b973b6e73bf85ba34d2c86bbae
7
- data.tar.gz: 0f6a627362ff12fb49e7f1f508ee374adaaff932ca248c8d88cfb3209ea28ec94521e1443b7144a66ea270fe896b53aeb740c042dea1134de2aa28ee568b70bb
6
+ metadata.gz: 0b770f908bb60e3108b5b99b8f83f008f5ca77f83be40349da8f283f95ce725b9edbac6a6dcc9439769ee2206ccc3d8ba35cec6b0458a879d8afcf2d97a4faab
7
+ data.tar.gz: 53ac5dfd4eaa3356b15bdb846bbc418b277758458381e2b9f903a2900f0685a2e1a051181aa5e4e165d75ee2003537c241f98a9392f2c6e42bba7533fd55be33
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.3.5]
8
+ ### Fixed
9
+ - When running commands, also rescue from whitelist of exceptions, and retry
10
+
11
+ ## [0.3.4]
12
+ ### Added
13
+ - Rescue from `Errno::ECONNREFUSED` and retry
14
+
15
+ ## [0.3.3]
16
+ ### Fixed
17
+ - Support launching multiple boxes at the same time
18
+
19
+ ## [0.3.2]
20
+ ### Fixed
21
+ - Fix: add missing file
22
+
23
+ ## [0.3.1]
24
+ ### Fixed
25
+ - Recover when the devbox is in a shutdown cycle
26
+
7
27
  ## [0.3.0]
8
28
  ### Changed
9
29
  - Label sessions with devbox
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- devbox_launcher (0.3.0)
4
+ devbox_launcher (0.3.5)
5
5
  activesupport (~> 6.0)
6
6
  bcrypt_pbkdf (~> 1.0)
7
7
  ed25519 (~> 1.2)
@@ -14,24 +14,24 @@ PATH
14
14
  GEM
15
15
  remote: https://rubygems.org/
16
16
  specs:
17
- activesupport (6.0.2.1)
17
+ activesupport (6.0.3.4)
18
18
  concurrent-ruby (~> 1.0, >= 1.0.2)
19
19
  i18n (>= 0.7, < 2)
20
20
  minitest (~> 5.1)
21
21
  tzinfo (~> 1.1)
22
- zeitwerk (~> 2.2)
22
+ zeitwerk (~> 2.2, >= 2.2.2)
23
23
  bcrypt_pbkdf (1.0.1)
24
24
  byebug (11.0.1)
25
25
  coderay (1.1.2)
26
- concurrent-ruby (1.1.5)
26
+ concurrent-ruby (1.1.7)
27
27
  diff-lcs (1.3)
28
28
  ed25519 (1.2.4)
29
- i18n (1.8.2)
29
+ i18n (1.8.5)
30
30
  concurrent-ruby (~> 1.0)
31
31
  method_source (0.9.2)
32
- minitest (5.14.0)
32
+ minitest (5.14.2)
33
33
  net-ssh (5.2.0)
34
- os (1.0.1)
34
+ os (1.1.1)
35
35
  pry (0.12.2)
36
36
  coderay (~> 1.1.0)
37
37
  method_source (~> 0.9.0)
@@ -56,9 +56,9 @@ GEM
56
56
  ssh-config (0.1.3)
57
57
  thor (1.0.1)
58
58
  thread_safe (0.3.6)
59
- tzinfo (1.2.6)
59
+ tzinfo (1.2.8)
60
60
  thread_safe (~> 0.1)
61
- zeitwerk (2.2.2)
61
+ zeitwerk (2.4.1)
62
62
 
63
63
  PLATFORMS
64
64
  ruby
@@ -16,3 +16,6 @@ end
16
16
 
17
17
  require "devbox_launcher/cli"
18
18
  require "devbox_launcher/watchman"
19
+ require "devbox_launcher/models/description"
20
+ require "devbox_launcher/models/mutagen"
21
+ require "devbox_launcher/models/box"
@@ -0,0 +1,213 @@
1
+ module DevboxLauncher
2
+ class Box
3
+
4
+ WAIT_BOOT_RESCUED_EXCEPTIONS = [
5
+ Net::SSH::ConnectionTimeout,
6
+ Net::SSH::Disconnect,
7
+ Errno::ECONNRESET,
8
+ Errno::ETIMEDOUT,
9
+ Errno::ECONNREFUSED,
10
+ ]
11
+ WAIT_BOOT_IN_SECONDS = 10.freeze
12
+ DEFAULT_IDENTIFY_FILE_PATH = "~/.ssh/google_compute_engine".freeze
13
+ SSH_CONFIG_PATH = File.expand_path("~/.ssh/config").freeze
14
+ CONFIG_PATH = File.expand_path("~/.devbox_launcher.yml").freeze
15
+ CONFIG = YAML.load_file(CONFIG_PATH).freeze
16
+
17
+ attr_reader :account
18
+
19
+ def initialize(account)
20
+ @account = account
21
+ end
22
+
23
+ def start
24
+ start_stdout, start_stderr, start_status =
25
+ run_command(start_cmd)
26
+
27
+ set_ssh_config!(hostname, {
28
+ username: username,
29
+ ip: description.ip,
30
+ })
31
+
32
+ wait_boot
33
+
34
+ reset_mutagen_session(
35
+ mutagen_config: config[:mutagen],
36
+ hostname: hostname,
37
+ )
38
+ end
39
+
40
+ def start_cmd
41
+ args = {
42
+ project: config[:project],
43
+ account: account,
44
+ }.map do |(key, val)|
45
+ ["--#{key}", val].join("=")
46
+ end.join(" ")
47
+
48
+ [
49
+ "gcloud",
50
+ "compute",
51
+ "instances",
52
+ "start",
53
+ name,
54
+ args
55
+ ].join(" ")
56
+ end
57
+
58
+ def wait_boot(tries: 1)
59
+ Net::SSH.start(hostname, username, timeout: WAIT_BOOT_IN_SECONDS) do |ssh|
60
+ puts "[#{ssh.exec!('date').chomp}] Machine booted"
61
+ end
62
+ rescue *WAIT_BOOT_RESCUED_EXCEPTIONS
63
+ puts "Not booted. Waiting #{WAIT_BOOT_IN_SECONDS} seconds before trying again..."
64
+
65
+ sleep WAIT_BOOT_IN_SECONDS
66
+
67
+ description = describe(name)
68
+ if !description.running?
69
+ puts "Detected that the machine is not running " \
70
+ "(status is #{description.status}). Booting it..."
71
+ start_box name, username
72
+ end
73
+
74
+ wait_boot name, username, tries: tries+1
75
+ end
76
+
77
+ def description(reload: false)
78
+ return @description if !reload && @description
79
+
80
+ puts "Fetching box's description..."
81
+
82
+ describe_command = %Q(gcloud compute instances describe #{name})
83
+ describe_stdout, describe_stderr, describe_status =
84
+ run_command(describe_command)
85
+
86
+ if !describe_status.success?
87
+ msg = "Problem fetching the description of #{name}. "
88
+ msg += "Please ensure you can call `#{describe_command}`.\n"
89
+ msg += "Error:\n"
90
+ msg += describe_stderr
91
+ fail msg
92
+ end
93
+
94
+ @description = Description.new(describe_stdout)
95
+ end
96
+
97
+ def set_ssh_config!(hostname, username:, ip:)
98
+ FileUtils.touch(SSH_CONFIG_PATH)
99
+ config = ConfigFile.new
100
+ args = {
101
+ "HostName" => ip,
102
+ "User" => username,
103
+ "IdentityFile" => DEFAULT_IDENTIFY_FILE_PATH,
104
+ }
105
+ args.each do |key, value|
106
+ config.set(hostname, key, value)
107
+ end
108
+ config.save
109
+ end
110
+
111
+ def reset_mutagen_session
112
+ mutagen_config = config[:mutagen]
113
+ return if mutagen_config.nil?
114
+
115
+ alpha_dir = mutagen_config[:alpha]
116
+ beta_dir = mutagen_config[:beta]
117
+
118
+ return if alpha_dir.nil? || beta_dir.nil?
119
+
120
+ terminate_mutagen_session
121
+
122
+ create_mutagen_session(
123
+ alpha_dir: alpha_dir,
124
+ beta_dir: beta_dir,
125
+ hostname: hostname,
126
+ username: username,
127
+ )
128
+
129
+ if OS.linux?
130
+ watch_alpha(alpha_dir: alpha_dir, hostname: hostname)
131
+ end
132
+ end
133
+
134
+ def terminate_mutagen_session(username)
135
+ puts "Terminating mutagen session..."
136
+ terminate_mutagen_command =
137
+ %Q(mutagen terminate --label-selector=#{username})
138
+ terminate_mutagen_stdout,
139
+ terminate_mutagen_stderr,
140
+ terminate_mutagen_status =
141
+ run_command(terminate_mutagen_command)
142
+
143
+ if not terminate_mutagen_status.success?
144
+ # mutagen prints to stdout and stderr
145
+ msg = "Failed to terminate mutagen sessions: " \
146
+ "#{terminate_mutagen_stdout} -" \
147
+ "#{terminate_mutagen_stderr}"
148
+ fail msg
149
+ end
150
+ end
151
+
152
+ def create_mutagen_session(alpha_dir:, beta_dir:, hostname:, username:)
153
+ puts "Create mutagen session syncing local #{alpha_dir} " \
154
+ "with #{hostname} #{beta_dir}"
155
+
156
+ create_mutagen_command = [
157
+ "mutagen sync create",
158
+ alpha_dir,
159
+ "#{hostname}:#{beta_dir}",
160
+ "--label=#{username}",
161
+ ]
162
+ create_mutagen_command << "--watch-mode-alpha=no-watch" if OS.linux?
163
+
164
+ create_mutagen_stdout,
165
+ create_mutagen_stderr,
166
+ create_mutagen_status =
167
+ run_command(create_mutagen_command.join(" "))
168
+
169
+ if not create_mutagen_status.success?
170
+ # mutagen prints to stdout and stderr
171
+ msg = "Failed to create mutagen sessions: " \
172
+ "#{create_mutagen_stdout} -" \
173
+ "#{create_mutagen_stderr}"
174
+ fail msg
175
+ end
176
+ end
177
+
178
+ def watch_alpha(alpha_dir:, hostname:)
179
+ watchman = Watchman.new(dir: alpha_dir)
180
+ watchman.trigger("mutagen sync flush --label-selector=#{hostname}")
181
+ end
182
+
183
+ def name
184
+ @name ||= config[:box]
185
+ end
186
+
187
+ def hostname
188
+ [name, username, "devbox"].join("-")
189
+ end
190
+
191
+ def username
192
+ @username ||= account.gsub(/\W/, "_")
193
+ end
194
+
195
+ def config
196
+ return @config if @config
197
+
198
+ if not CONFIG.has_key?(account)
199
+ fail "No config in #{CONFIG_PATH} found for #{account}"
200
+ end
201
+
202
+ @config = CONFIG[account].with_indifferent_access
203
+ end
204
+
205
+ def run_command(command, tries: 0)
206
+ Open3.capture3(command)
207
+ rescue *WAIT_BOOT_RESCUED_EXCEPTIONS
208
+ sleep WAIT_BOOT_IN_SECONDS
209
+ run_command(command, tries+1)
210
+ end
211
+
212
+ end
213
+ end
@@ -6,164 +6,12 @@ module DevboxLauncher
6
6
  SSH_CONFIG_PATH = File.expand_path("~/.ssh/config").freeze
7
7
  CONFIG_PATH = File.expand_path("~/.devbox_launcher.yml").freeze
8
8
  CONFIG = YAML.load_file(CONFIG_PATH).freeze
9
- LABEL = "devbox".freeze
10
9
 
11
10
  desc "start configured box for account", "Start a devbox by account"
12
11
  option :mosh, type: :boolean, desc: "Mosh in"
13
12
 
14
13
  def start(account)
15
- if not CONFIG.has_key?(account)
16
- fail "No config in #{CONFIG_PATH} found for #{account}"
17
- end
18
-
19
- config = CONFIG[account].with_indifferent_access
20
-
21
- username = account.gsub(/\W/, "_")
22
-
23
- set_account_command = %Q(gcloud config set account #{account})
24
- set_account_stdout, set_account_stderr, set_account_status =
25
- Open3.capture3(set_account_command)
26
-
27
- set_project_command = %Q(gcloud config set project #{config[:project]})
28
- set_project_stdout, set_project_stderr, set_project_status =
29
- Open3.capture3(set_project_command)
30
-
31
- name = config[:box]
32
-
33
- start_command = %Q(gcloud compute instances start #{name})
34
- start_stdout, start_stderr, start_status = Open3.capture3(start_command)
35
-
36
- puts "Fetching IP..."
37
- describe_command = %Q(gcloud compute instances describe #{name})
38
- describe_stdout, describe_stderr, describe_status =
39
- Open3.capture3(describe_command)
40
-
41
- if !describe_status.success?
42
- msg = "Problem fetching the IP address. "
43
- msg += "Please ensure you can call `#{describe_command}`.\n"
44
- msg += "Error:\n"
45
- msg += describe_stderr
46
- fail msg
47
- end
48
-
49
- description = YAML.load(describe_stdout)
50
-
51
- ip = description["networkInterfaces"].first["accessConfigs"].
52
- find { |config| config["kind"] == "compute#accessConfig" }["natIP"]
53
-
54
- puts "IP: #{ip}"
55
-
56
- hostname = "#{name}-devbox"
57
-
58
- set_ssh_config!(hostname, {
59
- username: username,
60
- ip: ip,
61
- })
62
-
63
- wait_boot(hostname, username)
64
-
65
- reset_mutagen_session(
66
- mutagen_config: config[:mutagen],
67
- hostname: hostname,
68
- )
69
-
70
- if options[:mosh]
71
- mosh_command = %Q(mosh #{hostname})
72
- system(mosh_command)
73
- end
74
- end
75
-
76
- no_commands do
77
- def wait_boot(hostname, username)
78
- Net::SSH.start(hostname, username, timeout: WAIT_BOOT_IN_SECONDS) do |ssh|
79
- puts "[#{ssh.exec!('date').chomp}] Machine booted"
80
- end
81
- rescue Net::SSH::ConnectionTimeout, Net::SSH::Disconnect, Errno::ECONNRESET
82
- puts "Not booted. Waiting #{WAIT_BOOT_IN_SECONDS} seconds before trying again..."
83
- wait_boot hostname, username
84
- end
85
-
86
- def set_ssh_config!(hostname, username:, ip:)
87
- FileUtils.touch(SSH_CONFIG_PATH)
88
- config = ConfigFile.new
89
- args = {
90
- "HostName" => ip,
91
- "User" => username,
92
- "IdentityFile" => DEFAULT_IDENTIFY_FILE_PATH,
93
- }
94
- args.each do |key, value|
95
- config.set(hostname, key, value)
96
- end
97
- config.save
98
- end
99
-
100
- def reset_mutagen_session(mutagen_config:, hostname:)
101
- return if mutagen_config.nil?
102
- alpha_dir = mutagen_config[:alpha]
103
- beta_dir = mutagen_config[:beta]
104
-
105
- return if alpha_dir.nil? || beta_dir.nil?
106
-
107
- terminate_mutagen_session
108
- create_mutagen_session(
109
- alpha_dir: alpha_dir,
110
- beta_dir: beta_dir,
111
- hostname: hostname,
112
- )
113
-
114
- if OS.linux?
115
- watch_alpha(alpha_dir: alpha_dir)
116
- end
117
- end
118
-
119
- def terminate_mutagen_session
120
- puts "Terminating mutagen session..."
121
- terminate_mutagen_command =
122
- %Q(mutagen terminate --label-selector=#{LABEL})
123
- terminate_mutagen_stdout,
124
- terminate_mutagen_stderr,
125
- terminate_mutagen_status =
126
- Open3.capture3(terminate_mutagen_command)
127
-
128
- if not terminate_mutagen_status.success?
129
- # mutagen prints to stdout and stderr
130
- msg = "Failed to terminate mutagen sessions: " \
131
- "#{terminate_mutagen_stdout} -" \
132
- "#{terminate_mutagen_stderr}"
133
- fail msg
134
- end
135
- end
136
-
137
- def create_mutagen_session(alpha_dir:, beta_dir:, hostname:)
138
- puts "Create mutagen session syncing local #{alpha_dir} " \
139
- "with #{hostname} #{beta_dir}"
140
-
141
- create_mutagen_command = [
142
- "mutagen sync create",
143
- alpha_dir,
144
- "#{hostname}:#{beta_dir}",
145
- "--label=#{LABEL}",
146
- ]
147
- create_mutagen_command << "--watch-mode-alpha=no-watch" if OS.linux?
148
-
149
- create_mutagen_stdout,
150
- create_mutagen_stderr,
151
- create_mutagen_status =
152
- Open3.capture3(create_mutagen_command.join(" "))
153
-
154
- if not create_mutagen_status.success?
155
- # mutagen prints to stdout and stderr
156
- msg = "Failed to create mutagen sessions: " \
157
- "#{create_mutagen_stdout} -" \
158
- "#{create_mutagen_stderr}"
159
- fail msg
160
- end
161
- end
162
-
163
- def watch_alpha(alpha_dir:)
164
- watchman = Watchman.new(dir: alpha_dir)
165
- watchman.trigger("mutagen sync flush --label-selector=#{LABEL}")
166
- end
14
+ Box.new(account, options).start
167
15
  end
168
16
 
169
17
  end
@@ -0,0 +1,222 @@
1
+ module DevboxLauncher
2
+ class Box
3
+
4
+ WAIT_BOOT_RESCUED_EXCEPTIONS = [
5
+ Net::SSH::ConnectionTimeout,
6
+ Net::SSH::Disconnect,
7
+ Errno::ECONNRESET,
8
+ Errno::ETIMEDOUT,
9
+ ]
10
+ WAIT_BOOT_IN_SECONDS = 10.freeze
11
+ MAX_BOOT_RETRIES = 10
12
+ DEFAULT_IDENTIFY_FILE_PATH = "~/.ssh/google_compute_engine".freeze
13
+ SSH_CONFIG_PATH = File.expand_path("~/.ssh/config").freeze
14
+ CONFIG_PATH = File.expand_path("~/.devbox_launcher.yml").freeze
15
+ CONFIG = YAML.load_file(CONFIG_PATH).freeze
16
+
17
+ attr_reader :account, :options
18
+
19
+ def initialize(account, options)
20
+ @account = account
21
+ @options = options
22
+ end
23
+
24
+ def start
25
+ start_stdout, start_stderr, start_status =
26
+ Open3.capture3(start_cmd)
27
+
28
+ set_ssh_config!
29
+
30
+ wait_boot
31
+
32
+ reset_mutagen_session
33
+
34
+ connect_mosh
35
+ end
36
+
37
+ def start_cmd
38
+ args = {
39
+ project: config[:project],
40
+ account: account,
41
+ }.map do |(key, val)|
42
+ ["--#{key}", val].join("=")
43
+ end.join(" ")
44
+
45
+ [
46
+ "gcloud",
47
+ "compute",
48
+ "instances",
49
+ "start",
50
+ name,
51
+ args
52
+ ].join(" ")
53
+ end
54
+
55
+ def connect_mosh
56
+ return if options[:mosh].nil?
57
+
58
+ mosh_cmd = %Q(mosh #{hostname})
59
+ system(mosh_cmd)
60
+ end
61
+
62
+ def wait_boot(tries: 1)
63
+ Net::SSH.start(hostname, username, timeout: WAIT_BOOT_IN_SECONDS) do |ssh|
64
+ puts "[#{ssh.exec!('date').chomp}] Machine booted"
65
+ end
66
+ rescue *WAIT_BOOT_RESCUED_EXCEPTIONS
67
+ puts "Not booted. Waiting #{WAIT_BOOT_IN_SECONDS} seconds before trying again..."
68
+
69
+ sleep WAIT_BOOT_IN_SECONDS
70
+
71
+ if !description(reload: true).running?
72
+ puts "Detected that the machine is not running " \
73
+ "(status is #{description.status}). Booting it..."
74
+ start
75
+ end
76
+
77
+ fail if tries >= MAX_BOOT_RETRIES
78
+
79
+ wait_boot tries: tries+1
80
+ end
81
+
82
+ def description(reload: false)
83
+ return @description if !reload && @description
84
+
85
+ puts "Fetching box's description..."
86
+
87
+ describe_stdout, describe_stderr, describe_status =
88
+ Open3.capture3(describe_cmd)
89
+
90
+ if !describe_status.success?
91
+ msg = "Problem fetching the description of #{name}. "
92
+ msg += "Please ensure you can call `#{describe_cmd}`.\n"
93
+ msg += "Error:\n"
94
+ msg += describe_stderr
95
+ fail msg
96
+ end
97
+
98
+ @description = Description.new(describe_stdout)
99
+ end
100
+
101
+ def describe_cmd
102
+ args = {
103
+ project: config[:project],
104
+ account: account,
105
+ }.map do |(key, val)|
106
+ ["--#{key}", val].join("=")
107
+ end.join(" ")
108
+
109
+ [
110
+ "gcloud",
111
+ "compute",
112
+ "instances",
113
+ "describe",
114
+ name,
115
+ args
116
+ ].join(" ")
117
+ end
118
+
119
+ def set_ssh_config!
120
+ FileUtils.touch(SSH_CONFIG_PATH)
121
+ config = ConfigFile.new
122
+ args = {
123
+ "HostName" => description.ip,
124
+ "User" => username,
125
+ "IdentityFile" => DEFAULT_IDENTIFY_FILE_PATH,
126
+ }
127
+ args.each do |key, value|
128
+ config.set(hostname, key, value)
129
+ end
130
+ config.save
131
+ end
132
+
133
+ def reset_mutagen_session
134
+ return if !mutagen_config.configured?
135
+
136
+ terminate_mutagen_session
137
+ create_mutagen_session
138
+ watch_alpha if OS.linux?
139
+ end
140
+
141
+ def terminate_mutagen_session
142
+ puts "Terminating mutagen session..."
143
+ terminate_mutagen_cmd =
144
+ %Q(mutagen terminate --label-selector=#{label})
145
+ terminate_mutagen_stdout,
146
+ terminate_mutagen_stderr,
147
+ terminate_mutagen_status =
148
+ Open3.capture3(terminate_mutagen_cmd)
149
+
150
+ if not terminate_mutagen_status.success?
151
+ # mutagen prints to stdout and stderr
152
+ msg = "Failed to terminate mutagen sessions: " \
153
+ "#{terminate_mutagen_stdout} -" \
154
+ "#{terminate_mutagen_stderr}"
155
+ fail msg
156
+ end
157
+ end
158
+
159
+ def label
160
+ "#{username}=#{name}"
161
+ end
162
+
163
+ def create_mutagen_session
164
+ puts "Create mutagen session syncing local " \
165
+ "#{mutagen_config.alpha_dir} with " \
166
+ "#{hostname} #{mutagen_config.beta_dir}"
167
+
168
+ create_mutagen_cmd = [
169
+ "mutagen sync create",
170
+ mutagen_config.alpha_dir,
171
+ "#{hostname}:#{mutagen_config.beta_dir}",
172
+ "--label=#{label}",
173
+ ]
174
+ create_mutagen_cmd << "--watch-mode-alpha=no-watch" if OS.linux?
175
+
176
+ create_mutagen_stdout,
177
+ create_mutagen_stderr,
178
+ create_mutagen_status =
179
+ Open3.capture3(create_mutagen_cmd.join(" "))
180
+
181
+ if not create_mutagen_status.success?
182
+ # mutagen prints to stdout and stderr
183
+ msg = "Failed to create mutagen sessions: " \
184
+ "#{create_mutagen_stdout} -" \
185
+ "#{create_mutagen_stderr}"
186
+ fail msg
187
+ end
188
+ end
189
+
190
+ def watch_alpha
191
+ watchman = Watchman.new(dir: mutagen_config.alpha_dir)
192
+ watchman.trigger("mutagen sync flush --label-selector=#{label}")
193
+ end
194
+
195
+ def name
196
+ @name ||= config[:box]
197
+ end
198
+
199
+ def hostname
200
+ [name, username, "devbox"].join("-")
201
+ end
202
+
203
+ def username
204
+ @username ||= account.gsub(/\W/, "_")
205
+ end
206
+
207
+ def config
208
+ return @config if @config
209
+
210
+ if not CONFIG.has_key?(account)
211
+ fail "No config in #{CONFIG_PATH} found for #{account}"
212
+ end
213
+
214
+ @config = CONFIG[account].with_indifferent_access
215
+ end
216
+
217
+ def mutagen_config
218
+ @mutagen_config ||= Mutagen.new(config[:mutagen])
219
+ end
220
+
221
+ end
222
+ end
@@ -0,0 +1,32 @@
1
+ module DevboxLauncher
2
+ class Description
3
+
4
+ def initialize(yaml)
5
+ @desc = YAML.load(yaml)
6
+ end
7
+
8
+ def ip
9
+ return @ip if @ip
10
+ network_interface = network_interfaces.first
11
+ access_configs = network_interface["accessConfigs"]
12
+
13
+ access_config = access_configs.find do |c|
14
+ c["kind"] == "compute#accessConfig"
15
+ end
16
+ @ip = access_config["natIP"]
17
+ end
18
+
19
+ def status
20
+ @status ||= @desc["status"]
21
+ end
22
+
23
+ def network_interfaces
24
+ @network_interfaces ||= @desc["networkInterfaces"]
25
+ end
26
+
27
+ def running?
28
+ status == "RUNNING"
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,23 @@
1
+ module DevboxLauncher
2
+ class Mutagen
3
+
4
+ attr_reader :config
5
+
6
+ def initialize(config)
7
+ @config = config
8
+ end
9
+
10
+ def configured?
11
+ [config, alpha_dir, beta_dir].none?(&:nil?)
12
+ end
13
+
14
+ def alpha_dir
15
+ config[:alpha]
16
+ end
17
+
18
+ def beta_dir
19
+ config[:beta]
20
+ end
21
+
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module DevboxLauncher
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.5"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devbox_launcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ramon Tayag
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-24 00:00:00.000000000 Z
11
+ date: 2020-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,7 +164,7 @@ dependencies:
164
164
  - - '='
165
165
  - !ruby/object:Gem::Version
166
166
  version: 0.0.2
167
- description:
167
+ description:
168
168
  email:
169
169
  - ramon.tayag@gmail.com
170
170
  executables:
@@ -189,7 +189,11 @@ files:
189
189
  - bin/setup
190
190
  - devbox_launcher.gemspec
191
191
  - lib/devbox_launcher.rb
192
+ - lib/devbox_launcher/box.rb
192
193
  - lib/devbox_launcher/cli.rb
194
+ - lib/devbox_launcher/models/box.rb
195
+ - lib/devbox_launcher/models/description.rb
196
+ - lib/devbox_launcher/models/mutagen.rb
193
197
  - lib/devbox_launcher/version.rb
194
198
  - lib/devbox_launcher/watchman.rb
195
199
  homepage: https://github.com/bloom-solutions/devbox_launcher
@@ -200,7 +204,7 @@ metadata:
200
204
  homepage_uri: https://github.com/bloom-solutions/devbox_launcher
201
205
  source_code_uri: https://github.com/bloom-solutions/devbox_launcher
202
206
  changelog_uri: https://github.com/bloom-solutions/devbox_launcher/blob/master/CHANGELOG.md
203
- post_install_message:
207
+ post_install_message:
204
208
  rdoc_options: []
205
209
  require_paths:
206
210
  - lib
@@ -215,8 +219,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
219
  - !ruby/object:Gem::Version
216
220
  version: '0'
217
221
  requirements: []
218
- rubygems_version: 3.0.6
219
- signing_key:
222
+ rubygems_version: 3.0.8
223
+ signing_key:
220
224
  specification_version: 4
221
225
  summary: Conveniently launch your devbox
222
226
  test_files: []