cnvrg 0.0.5 → 0.0.6
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/cnvrg.gemspec +6 -1
- data/lib/cnvrg/api.rb +12 -5
- data/lib/cnvrg/auth.rb +4 -4
- data/lib/cnvrg/cli.rb +1023 -532
- data/lib/cnvrg/files.rb +187 -95
- data/lib/cnvrg/helpers.rb +11 -1
- data/lib/cnvrg/version.rb +1 -1
- metadata +58 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6d6742b8d329e83b4eba3acbc60dc05bd2a881d
|
4
|
+
data.tar.gz: a20f65edcc1666973f12d7d8f24c4e7837cea0ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1eb7c4e30a407596bbce0c8e86094a76ad417a7f8bc4003c1d4f72d6eb03c4ae8bc5bb7bb1f9baf88b2a2f31d4971a90afa67b73ee2a91e7190549805664ad0
|
7
|
+
data.tar.gz: 74415b8949fc00dd752add66aa441359716e23004ad4decb3fff796e994ef309a1028a0cedd7b073fa0616f307a917344433185df9f4a7828ce233867fc17f85
|
data/cnvrg.gemspec
CHANGED
@@ -23,12 +23,17 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
24
24
|
spec.add_development_dependency 'vcr', '~> 3.0'
|
25
25
|
spec.add_development_dependency 'aruba'
|
26
|
-
|
26
|
+
spec.add_development_dependency 'pry'
|
27
|
+
|
27
28
|
spec.add_runtime_dependency 'mimemagic', '~> 0.3.1','>=0.3.2'
|
28
29
|
spec.add_runtime_dependency 'faraday', '~> 0.10.0'
|
29
30
|
spec.add_runtime_dependency 'netrc', '~> 0.11.0'
|
30
31
|
spec.add_runtime_dependency 'open4', '~> 1.3', '>= 1.3.4'
|
31
32
|
spec.add_runtime_dependency 'highline', '~> 1.7', '>= 1.7.8'
|
32
33
|
spec.add_runtime_dependency 'thor', '~> 0.19.0','>=0.19.1'
|
34
|
+
spec.add_runtime_dependency 'aws-sdk'
|
35
|
+
spec.add_runtime_dependency 'urlcrypt', '~> 0.1.1'
|
36
|
+
spec.add_runtime_dependency 'terminal-table'
|
37
|
+
|
33
38
|
end
|
34
39
|
|
data/lib/cnvrg/api.rb
CHANGED
@@ -7,11 +7,17 @@ require 'cnvrg/helpers'
|
|
7
7
|
module Cnvrg
|
8
8
|
class API
|
9
9
|
USER_AGENT = "CnvrgCLI/#{Cnvrg::VERSION}"
|
10
|
-
# ENDPOINT = 'http://localhost:3000/api'
|
11
|
-
ENDPOINT = 'https://cnvrg.io/api'
|
12
10
|
ENDPOINT_VERSION = 'v1'
|
13
|
-
URL = "#{ENDPOINT}/#{ENDPOINT_VERSION}"
|
14
11
|
|
12
|
+
def self.get_api
|
13
|
+
home_dir = File.expand_path('~')
|
14
|
+
config = YAML.load_file(home_dir+"/.cnvrg/config.yml")
|
15
|
+
if config.empty? or config.to_h[:api].nil?
|
16
|
+
return "https://cnvrg.io/api"
|
17
|
+
else
|
18
|
+
return config.to_h[:api]
|
19
|
+
end
|
20
|
+
end
|
15
21
|
def self.request(resource, method = 'GET', data = {}, parse_request = true)
|
16
22
|
begin
|
17
23
|
n = Netrc.read
|
@@ -65,7 +71,7 @@ module Cnvrg
|
|
65
71
|
# what if windows?
|
66
72
|
# data[:file] = Faraday::UploadIO.new(data[:absolute_path], content_type)
|
67
73
|
file_base = File.basename(data[:relative_path])
|
68
|
-
temp_path = "
|
74
|
+
temp_path = File.expand_path('~')+"/.cnvrg/tmp/#{file_base}"
|
69
75
|
FileUtils.touch(temp_path)
|
70
76
|
data[:file] = Faraday::UploadIO.new("#{temp_path}", "plain/text")
|
71
77
|
response = conn.post "#{endpoint_uri}/#{resource}", data
|
@@ -89,7 +95,8 @@ module Cnvrg
|
|
89
95
|
end
|
90
96
|
|
91
97
|
def self.endpoint_uri
|
92
|
-
|
98
|
+
api = get_api()
|
99
|
+
return "#{api}/#{Cnvrg::API::ENDPOINT_VERSION}"
|
93
100
|
end
|
94
101
|
|
95
102
|
|
data/lib/cnvrg/auth.rb
CHANGED
@@ -45,7 +45,7 @@ module Cnvrg
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def sign_in(email, password)
|
48
|
-
url = API
|
48
|
+
url = Cnvrg::API.endpoint_uri()
|
49
49
|
url = URI.parse(url+ "/users/sign_in")
|
50
50
|
http = Net::HTTP.new(url.host, url.port)
|
51
51
|
|
@@ -60,11 +60,11 @@ module Cnvrg
|
|
60
60
|
response = http.request(req)
|
61
61
|
|
62
62
|
result = JSON.parse(response.body)
|
63
|
-
if result
|
63
|
+
if Cnvrg::CLI.is_response_success(result)
|
64
64
|
return result["result"]
|
65
|
-
else
|
66
|
-
return nil
|
67
65
|
end
|
66
|
+
|
67
|
+
|
68
68
|
end
|
69
69
|
|
70
70
|
|
data/lib/cnvrg/cli.rb
CHANGED
@@ -19,29 +19,67 @@ require 'cnvrg/files'
|
|
19
19
|
require 'cnvrg/experiment'
|
20
20
|
require 'etc'
|
21
21
|
|
22
|
+
|
22
23
|
# DEV VERSION
|
23
24
|
#
|
24
25
|
module Cnvrg
|
25
26
|
class CLI < Thor
|
26
27
|
|
28
|
+
INSTALLATION_URLS = {docker: "https://docs.docker.com/engine/installation/", jupyter: "http://jupyter.readthedocs.io/en/latest/install.html"}
|
29
|
+
|
27
30
|
desc 'version', 'Prints cnvrg current version'
|
28
31
|
|
29
32
|
def version
|
33
|
+
|
30
34
|
puts Cnvrg::VERSION
|
31
35
|
end
|
32
36
|
|
33
37
|
map %w(-v --version) => :version
|
38
|
+
|
39
|
+
desc 'set api url', 'set api url'
|
40
|
+
|
41
|
+
def set_api_url(url)
|
42
|
+
home_dir = File.expand_path('~')
|
43
|
+
if !url.end_with? "/api"
|
44
|
+
url = url+"/api"
|
45
|
+
end
|
46
|
+
begin
|
47
|
+
if !File.directory? home_dir+"/.cnvrg"
|
48
|
+
FileUtils.mkdir_p([home_dir+"/.cnvrg", home_dir+"/.cnvrg/tmp"])
|
49
|
+
end
|
50
|
+
if !File.exist?(home_dir+"/.cnvrg/config.yml")
|
51
|
+
FileUtils.touch [home_dir+"/.cnvrg/config.yml"]
|
52
|
+
end
|
53
|
+
config = YAML.load_file(home_dir+"/.cnvrg/config.yml")
|
54
|
+
say "Setting default api to be: #{url}", Thor::Shell::Color::BLUE
|
55
|
+
if config.empty?
|
56
|
+
config = {owner: "", username: "", version_last_check: get_start_day(), api: url}
|
57
|
+
else
|
58
|
+
config = {owner: config.to_h[:owner], username: config.to_h[:username], version_last_check: config.to_h[:version_last_check], api: url}
|
59
|
+
end
|
60
|
+
checks = Helpers.checkmark
|
61
|
+
|
62
|
+
|
63
|
+
File.open(home_dir+"/.cnvrg/config.yml", "w+") { |f| f.write config.to_yaml }
|
64
|
+
say "#{checks} Done", Thor::Shell::Color::GREEN
|
65
|
+
rescue
|
66
|
+
say "Couldn't set default api, contact help@cnvrg.io", Thor::Shell::Color::RED
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
map %w(-api --api) => :set_api_url
|
71
|
+
|
34
72
|
desc 'set default owner', 'set default owner'
|
35
73
|
|
36
74
|
def set_default_owner
|
37
75
|
|
38
76
|
path = File.expand_path('~')+"/.cnvrg/config.yml"
|
39
77
|
if !File.exist?(path)
|
40
|
-
say "Couldn't find ~/.cnvrg/config.yml file, please logout and login again"
|
78
|
+
say "Couldn't find ~/.cnvrg/config.yml file, please logout and login again", Thor::Shell::Color::RED
|
41
79
|
|
42
80
|
exit(0)
|
43
81
|
end
|
44
|
-
|
82
|
+
config = YAML.load_file(path)
|
45
83
|
|
46
84
|
username = config.to_h[:username]
|
47
85
|
res = Cnvrg::API.request("/users/#{username}/get_possible_owners", 'GET')
|
@@ -66,66 +104,83 @@ module Cnvrg
|
|
66
104
|
desc 'login', 'Authenticate with cnvrg.io and store credentials'
|
67
105
|
|
68
106
|
def login
|
69
|
-
|
107
|
+
begin
|
108
|
+
cmd = HighLine.new
|
70
109
|
|
71
|
-
|
110
|
+
say 'Authenticating with cnvrg', Thor::Shell::Color::YELLOW
|
72
111
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
puts owner
|
112
|
+
@auth = Cnvrg::Auth.new
|
113
|
+
netrc = Netrc.read
|
114
|
+
@email, token = netrc[Cnvrg::Helpers.netrc_domain]
|
77
115
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
if (token = result["token"])
|
86
|
-
netrc[Cnvrg::Helpers.netrc_domain] = @email, token
|
87
|
-
netrc.save
|
116
|
+
if @email and token
|
117
|
+
say 'Seems you\'re already logged in', Thor::Shell::Color::BLUE
|
118
|
+
exit(0)
|
119
|
+
end
|
120
|
+
@email = ask("Enter your email:")
|
121
|
+
password = cmd.ask("Enter your password (hidden):") { |q| q.echo = "*" }
|
122
|
+
result = @auth.sign_in(@email, password)
|
88
123
|
|
89
|
-
|
90
|
-
|
91
|
-
|
124
|
+
if !result["token"].nil?
|
125
|
+
netrc[Cnvrg::Helpers.netrc_domain] = @email, result["token"]
|
126
|
+
netrc.save
|
92
127
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
128
|
+
say "Authenticated successfully as #{@email}", Thor::Shell::Color::GREEN
|
129
|
+
owners = result["owners"]
|
130
|
+
choose_owner = result["username"]
|
131
|
+
|
132
|
+
if owners.empty?
|
133
|
+
else
|
134
|
+
owners << choose_owner
|
135
|
+
choose_owner = ask("Choose default owner:\n"+owners.join("\n")+"\n")
|
136
|
+
|
137
|
+
end
|
138
|
+
if set_owner(choose_owner, result["username"])
|
139
|
+
say "Setting default owner: #{choose_owner}", Thor::Shell::Color::GREEN
|
140
|
+
else
|
141
|
+
say "Setting default owenr has failed, try to run cnvrg --config-default-owner", Thor::Shell::Color::RED
|
142
|
+
end
|
97
143
|
|
98
|
-
end
|
99
|
-
if set_owner(choose_owner, result["username"])
|
100
|
-
say "Setting default owner: #{choose_owner}", Thor::Shell::Color::GREEN
|
101
144
|
else
|
102
|
-
say "
|
145
|
+
say "Failed to authenticate, wrong email/password", Thor::Shell::Color::RED
|
146
|
+
exit false
|
103
147
|
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
exit false
|
148
|
+
rescue SignalException
|
149
|
+
say "/nAborting"
|
150
|
+
exit(1)
|
108
151
|
end
|
109
152
|
end
|
110
153
|
|
154
|
+
|
111
155
|
desc 'logout', 'Logout existing user'
|
112
156
|
|
113
157
|
def logout
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
158
|
+
begin
|
159
|
+
netrc = Netrc.read
|
160
|
+
netrc.delete(Cnvrg::Helpers.netrc_domain)
|
161
|
+
netrc.save
|
162
|
+
say "Logged out successfully.\n", Thor::Shell::Color::GREEN
|
163
|
+
rescue SignalException
|
164
|
+
say "/nAborting"
|
165
|
+
exit(1)
|
166
|
+
end
|
167
|
+
|
118
168
|
end
|
119
169
|
|
120
170
|
desc 'me', 'Prints the current logged in user email'
|
121
171
|
|
122
172
|
def me
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
173
|
+
begin
|
174
|
+
verify_logged_in()
|
175
|
+
auth = Cnvrg::Auth.new
|
176
|
+
if (email = auth.get_email)
|
177
|
+
say "Logged in as: #{email}", Thor::Shell::Color::GREEN
|
178
|
+
else
|
179
|
+
say "You're not logged in.", Thor::Shell::Color::RED
|
180
|
+
end
|
181
|
+
rescue SignalException
|
182
|
+
say "/nAborting"
|
183
|
+
exit(1)
|
129
184
|
end
|
130
185
|
end
|
131
186
|
|
@@ -133,613 +188,1049 @@ module Cnvrg
|
|
133
188
|
|
134
189
|
desc 'new', 'Create a new cnvrg project'
|
135
190
|
method_option :clean, :type => :boolean, :aliases => ["-c", "--c"], :default => false
|
191
|
+
method_option :docker_image, :type => :string, :aliases => ["-d", "--d"], :default => ""
|
136
192
|
|
137
193
|
def new(project_name)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
else
|
151
|
-
say "Error creating project, please contact support.", Thor::Shell::Color::RED
|
152
|
-
exit(0)
|
153
|
-
end
|
194
|
+
begin
|
195
|
+
verify_logged_in()
|
196
|
+
clean = options["clean"]
|
197
|
+
docker_image = options["docker_image"]
|
198
|
+
if !docker_image.nil? and !docker_image.empty?
|
199
|
+
pull_image(docker_image)
|
200
|
+
end
|
201
|
+
say "Creating #{project_name}", Thor::Shell::Color::BLUE
|
202
|
+
if Dir.exists? project_name or File.exists? project_name
|
203
|
+
say "Conflict with dir/file #{project_name}", Thor::Shell::Color::RED
|
204
|
+
exit(1)
|
205
|
+
end
|
154
206
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
207
|
+
if Project.create(project_name, clean)
|
208
|
+
path = Dir.pwd + "/" + project_name
|
209
|
+
@project = Project.new(path)
|
210
|
+
@project.generate_idx
|
211
|
+
else
|
212
|
+
say "Error creating project, please contact support.", Thor::Shell::Color::RED
|
213
|
+
exit(0)
|
214
|
+
end
|
159
215
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
project_name =File.basename(Dir.getwd)
|
167
|
-
say "Linking #{project_name}", Thor::Shell::Color::BLUE
|
168
|
-
if File.directory?(Dir.getwd+"/.cnvrg")
|
169
|
-
config = YAML.load_file("#{Dir.getwd}/.cnvrg/config.yml")
|
170
|
-
say "Directory is already linked to #{config[:project_slug]}", Thor::Shell::Color::RED
|
171
|
-
exit(0)
|
216
|
+
say "created\t\tproject's tree", Thor::Shell::Color::GREEN
|
217
|
+
say "created\t\tproject's config", Thor::Shell::Color::GREEN
|
218
|
+
say "Linked directory to\t#{@project.url}", Thor::Shell::Color::GREEN
|
219
|
+
rescue SignalException
|
220
|
+
say "/nAborting"
|
221
|
+
exit(1)
|
172
222
|
end
|
173
|
-
if Project.link(project_name)
|
174
|
-
path = Dir.pwd
|
175
|
-
@project = Project.new(path)
|
176
|
-
@project.generate_idx()
|
177
|
-
if sync
|
178
|
-
upload(true)
|
179
|
-
end
|
180
|
-
|
181
|
-
url = @project.url
|
182
|
-
say "#{project_name}'s location is: #{url}\n", Thor::Shell::Color::BLUE
|
183
|
-
else
|
184
|
-
say "Error linking project, please contact support.", Thor::Shell::Color::RED
|
185
|
-
exit(0)
|
186
223
|
end
|
187
|
-
end
|
188
224
|
|
189
|
-
desc 'clone', 'Clone a project'
|
190
|
-
|
191
|
-
def clone(project_url)
|
192
|
-
verify_logged_in()
|
193
|
-
url_parts = project_url.split("/")
|
194
|
-
project_index = Cnvrg::Helpers.look_for_in_path(project_url, "projects")
|
195
|
-
slug = url_parts[project_index+1]
|
196
|
-
owner = url_parts[project_index-1]
|
197
|
-
response = Cnvrg::API.request("users/#{owner}/projects/#{slug}/get_project", 'GET')
|
198
|
-
Cnvrg::CLI.is_response_success(response)
|
199
|
-
response = JSON.parse response["result"]
|
200
|
-
project_name = response["title"]
|
201
|
-
say "Cloning #{project_name}", Thor::Shell::Color::BLUE
|
202
|
-
if Dir.exists? project_name or File.exists? project_name
|
203
|
-
say "Error: Conflict with dir/file #{project_name}", Thor::Shell::Color::RED
|
204
|
-
exit(1)
|
205
|
-
end
|
206
225
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
226
|
+
desc 'link', 'Link current directory to a cnvrg project'
|
227
|
+
method_option :sync, :type => :boolean, :aliases => ["-s", "--s"], :default => true
|
228
|
+
|
229
|
+
def link
|
230
|
+
begin
|
231
|
+
verify_logged_in()
|
232
|
+
sync = options["sync"]
|
233
|
+
project_name =File.basename(Dir.getwd)
|
234
|
+
say "Linking #{project_name}", Thor::Shell::Color::BLUE
|
235
|
+
if File.directory?(Dir.getwd+"/.cnvrg")
|
236
|
+
config = YAML.load_file("#{Dir.getwd}/.cnvrg/config.yml")
|
237
|
+
say "Directory is already linked to #{config[:project_slug]}", Thor::Shell::Color::RED
|
238
|
+
exit(0)
|
239
|
+
end
|
240
|
+
if Project.link(project_name)
|
241
|
+
path = Dir.pwd
|
242
|
+
@project = Project.new(path)
|
243
|
+
@project.generate_idx()
|
244
|
+
if sync
|
245
|
+
upload(true)
|
223
246
|
end
|
247
|
+
|
248
|
+
url = @project.url
|
249
|
+
say "#{project_name}'s location is: #{url}\n", Thor::Shell::Color::BLUE
|
224
250
|
else
|
225
|
-
|
226
|
-
|
227
|
-
successful_changes << relative_path
|
228
|
-
end
|
251
|
+
say "Error linking project, please contact support.", Thor::Shell::Color::RED
|
252
|
+
exit(0)
|
229
253
|
end
|
254
|
+
rescue SignalException
|
255
|
+
say "/nAborting"
|
256
|
+
exit(1)
|
230
257
|
end
|
231
|
-
say "Done.\nDownloaded total of #{successful_changes.size} files", Thor::Shell::Color::BLUE
|
232
|
-
else
|
233
|
-
say "Error: Couldn't create directory: #{project_name}", Thor::Shell::Color::RED
|
234
|
-
exit(1)
|
235
258
|
end
|
236
259
|
|
237
|
-
|
260
|
+
desc 'clone', 'Clone a project'
|
238
261
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
say "\t\tA:\t#{a}", Thor::Shell::Color::GREEN
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
if result["deleted"].size > 0
|
260
|
-
say "Deleted files:\n", Thor::Shell::Color::BLUE
|
261
|
-
result["deleted"].each do |a|
|
262
|
-
say "\t\tD:\t#{a}", Thor::Shell::Color::GREEN
|
263
|
-
end
|
264
|
-
end
|
265
|
-
if result["updated_on_local"].size > 0
|
266
|
-
say "Local changes:\n", Thor::Shell::Color::BLUE
|
267
|
-
result["updated_on_local"].each do |a|
|
268
|
-
say "\t\tM:\t#{a}", Thor::Shell::Color::GREEN
|
269
|
-
end
|
270
|
-
end
|
262
|
+
def clone(project_url)
|
263
|
+
begin
|
264
|
+
verify_logged_in()
|
265
|
+
url_parts = project_url.split("/")
|
266
|
+
project_index = Cnvrg::Helpers.look_for_in_path(project_url, "projects")
|
267
|
+
slug = url_parts[project_index+1]
|
268
|
+
owner = url_parts[project_index-1]
|
269
|
+
response = Cnvrg::API.request("users/#{owner}/projects/#{slug}/get_project", 'GET')
|
270
|
+
Cnvrg::CLI.is_response_success(response)
|
271
|
+
response = JSON.parse response["result"]
|
272
|
+
project_name = response["title"]
|
273
|
+
say "Cloning #{project_name}", Thor::Shell::Color::BLUE
|
274
|
+
if Dir.exists? project_name or File.exists? project_name
|
275
|
+
say "Error: Conflict with dir/file #{project_name}", Thor::Shell::Color::RED
|
276
|
+
exit(1)
|
277
|
+
end
|
271
278
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
279
|
+
if Project.clone_dir(slug, owner, project_name)
|
280
|
+
project_home = Dir.pwd+"/"+project_name
|
281
|
+
@project = Project.new(project_home)
|
282
|
+
@files = Cnvrg::Files.new(@project.owner, slug)
|
283
|
+
response = @project.clone
|
284
|
+
Cnvrg::CLI.is_response_success response
|
285
|
+
idx = {commit: response["result"]["commit"], tree: response["result"]["tree"]}
|
286
|
+
File.open(project_name + "/.cnvrg/idx.yml", "w+") { |f| f.write idx.to_yaml }
|
287
|
+
successful_changes = []
|
288
|
+
say "Downloading files", Thor::Shell::Color::BLUE
|
289
|
+
response["result"]["tree"].each do |f|
|
290
|
+
relative_path = f[0].gsub(/^#{@project.local_path}/, "")
|
291
|
+
if f[0].end_with? "/"
|
292
|
+
# dir
|
293
|
+
if @files.download_dir(f[0], relative_path, project_home)
|
294
|
+
successful_changes << relative_path
|
295
|
+
end
|
296
|
+
else
|
297
|
+
# blob
|
298
|
+
if @files.download_file(f[0], relative_path, project_home)
|
299
|
+
successful_changes << relative_path
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
say "Done.\nDownloaded total of #{successful_changes.size} files", Thor::Shell::Color::GREEN
|
304
|
+
else
|
305
|
+
say "Error: Couldn't create directory: #{project_name}", Thor::Shell::Color::RED
|
306
|
+
exit(1)
|
307
|
+
end
|
308
|
+
rescue SignalException
|
309
|
+
say "/nAborting"
|
310
|
+
exit(1)
|
276
311
|
end
|
277
|
-
end
|
278
312
|
|
279
|
-
if result["conflicts"].size > 0
|
280
|
-
say "Conflicted changes:\n", Thor::Shell::Color::BLUE
|
281
|
-
result["conflicts"].each do |a|
|
282
|
-
say "\t\tC:\t#{a}", Thor::Shell::Color::RED
|
283
|
-
end
|
284
313
|
end
|
285
|
-
end
|
286
|
-
|
287
314
|
|
288
|
-
|
289
|
-
|
315
|
+
desc 'status', 'Show the working tree status'
|
316
|
+
def status
|
317
|
+
begin
|
318
|
+
verify_logged_in()
|
319
|
+
@project = Project.new(get_project_home)
|
320
|
+
result = @project.compare_idx["result"]
|
321
|
+
commit = result["commit"]
|
322
|
+
result = result["tree"]
|
323
|
+
say "Comparing local changes with remote version:", Thor::Shell::Color::BLUE
|
324
|
+
if result["added"].empty? and result["updated_on_local"].empty? and result["updated_on_server"].empty? and result["deleted"].empty? and result["conflicts"].empty?
|
325
|
+
say "Project is up to date", Thor::Shell::Color::GREEN
|
326
|
+
return true
|
327
|
+
end
|
328
|
+
if result["added"].size > 0
|
329
|
+
say "Added files:\n", Thor::Shell::Color::BLUE
|
330
|
+
result["added"].each do |a|
|
331
|
+
say "\t\tA:\t#{a}", Thor::Shell::Color::GREEN
|
332
|
+
end
|
333
|
+
end
|
290
334
|
|
291
|
-
|
335
|
+
if result["deleted"].size > 0
|
336
|
+
say "Deleted files:\n", Thor::Shell::Color::BLUE
|
337
|
+
result["deleted"].each do |a|
|
338
|
+
say "\t\tD:\t#{a}", Thor::Shell::Color::GREEN
|
339
|
+
end
|
340
|
+
end
|
341
|
+
if result["updated_on_local"].size > 0
|
342
|
+
say "Local changes:\n", Thor::Shell::Color::BLUE
|
343
|
+
result["updated_on_local"].each do |a|
|
344
|
+
say "\t\tM:\t#{a}", Thor::Shell::Color::GREEN
|
345
|
+
end
|
346
|
+
end
|
292
347
|
|
293
|
-
|
294
|
-
|
348
|
+
if result["updated_on_server"].size > 0
|
349
|
+
say "Remote changes:\n", Thor::Shell::Color::BLUE
|
350
|
+
result["updated_on_server"].each do |a|
|
351
|
+
say "\t\tM:\t#{a}", Thor::Shell::Color::GREEN
|
352
|
+
end
|
353
|
+
end
|
295
354
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
if commit != @project.last_local_commit and !@project.last_local_commit.nil?
|
305
|
-
say "Remote server has an updated version, please run `cnvrg download` first, or alternatively: `cnvrg sync`", Thor::Shell::Color::YELLOW
|
355
|
+
if result["conflicts"].size > 0
|
356
|
+
say "Conflicted changes:\n", Thor::Shell::Color::BLUE
|
357
|
+
result["conflicts"].each do |a|
|
358
|
+
say "\t\tC:\t#{a}", Thor::Shell::Color::RED
|
359
|
+
end
|
360
|
+
end
|
361
|
+
rescue SignalException
|
362
|
+
say "/nAborting"
|
306
363
|
exit(1)
|
307
364
|
end
|
308
|
-
say "Comparing local changes with remote version:", Thor::Shell::Color::BLUE
|
309
|
-
end
|
310
|
-
result = result["result"]["tree"]
|
311
|
-
if result["added"].empty? and result["updated_on_local"].empty? and result["deleted"].empty?
|
312
|
-
say "Project is up to date", Thor::Shell::Color::GREEN
|
313
|
-
return true
|
314
|
-
end
|
315
|
-
update_count = 0
|
316
|
-
update_total = result["added"].size + result["updated_on_local"].size + result["deleted"].size
|
317
|
-
successful_updates = []
|
318
|
-
successful_deletions = []
|
319
|
-
if update_total == 1
|
320
|
-
say "Updating #{update_total} file", Thor::Shell::Color::BLUE
|
321
|
-
else
|
322
|
-
say "Updating #{update_total} files", Thor::Shell::Color::BLUE
|
323
365
|
end
|
324
366
|
|
325
|
-
# Start commit
|
326
367
|
|
327
|
-
|
368
|
+
desc 'upload', 'Upload updated files'
|
369
|
+
method_option :ignore, :type => :array, :aliases => ["-i", "--i"], :desc => "ignore following files"
|
328
370
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
371
|
+
def upload(link=false, sync=false)
|
372
|
+
|
373
|
+
begin
|
374
|
+
verify_logged_in()
|
375
|
+
@project = Project.new(get_project_home)
|
376
|
+
|
377
|
+
@files = Cnvrg::Files.new(@project.owner, @project.slug)
|
378
|
+
ignore = options[:ignore] || []
|
379
|
+
if !@project.update_ignore_list(ignore)
|
380
|
+
say "Couldn't append new ignore files to .cnvrgignore", Thor::Shell::Color::YELLOW
|
381
|
+
end
|
382
|
+
result = @project.compare_idx
|
383
|
+
commit = result["result"]["commit"]
|
384
|
+
if !link
|
385
|
+
if commit != @project.last_local_commit and !@project.last_local_commit.nil? and !result["result"]["tree"]["updated_on_server"].empty?
|
386
|
+
say "Remote server has an updated version, please run `cnvrg download` first, or alternatively: `cnvrg sync`", Thor::Shell::Color::YELLOW
|
387
|
+
exit(1)
|
340
388
|
end
|
389
|
+
say "Comparing local changes with remote version:", Thor::Shell::Color::BLUE
|
390
|
+
end
|
391
|
+
result = result["result"]["tree"]
|
392
|
+
if result["added"].empty? and result["updated_on_local"].empty? and result["deleted"].empty?
|
393
|
+
say "Project is up to date", Thor::Shell::Color::GREEN
|
394
|
+
return true
|
395
|
+
end
|
396
|
+
update_count = 0
|
397
|
+
update_total = result["added"].size + result["updated_on_local"].size + result["deleted"].size
|
398
|
+
successful_updates = []
|
399
|
+
successful_deletions = []
|
400
|
+
if update_total == 1
|
401
|
+
say "Updating #{update_total} file", Thor::Shell::Color::BLUE
|
341
402
|
else
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
403
|
+
say "Updating #{update_total} files", Thor::Shell::Color::BLUE
|
404
|
+
end
|
405
|
+
|
406
|
+
# Start commit
|
407
|
+
|
408
|
+
commit_sha1 = @files.start_commit["result"]["commit_sha1"]
|
409
|
+
|
410
|
+
# upload / update
|
411
|
+
begin
|
412
|
+
(result["added"] + result["updated_on_local"]).each do |f|
|
413
|
+
puts f
|
414
|
+
relative_path = f.gsub(/^#{@project.local_path + "/"}/, "")
|
415
|
+
|
416
|
+
if File.directory?(f)
|
417
|
+
resDir = @files.create_dir(f, relative_path, commit_sha1)
|
418
|
+
if resDir
|
419
|
+
update_count += 1
|
420
|
+
successful_updates<< relative_path
|
421
|
+
end
|
422
|
+
else
|
423
|
+
res = @files.upload_file(f, relative_path, commit_sha1)
|
424
|
+
if res
|
425
|
+
update_count += 1
|
426
|
+
successful_updates<< relative_path
|
427
|
+
else
|
428
|
+
@files.rollback_commit(commit_sha1)
|
429
|
+
say "Couldn't upload, Rolling Back all changes.", Thor::Shell::Color::RED
|
430
|
+
exit(0)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
# delete
|
436
|
+
result["deleted"].each do |f|
|
437
|
+
relative_path = f.gsub(/^#{@project.local_path + "/"}/, "")
|
438
|
+
if relative_path.end_with?("/")
|
439
|
+
if @files.delete_dir(f, relative_path, commit_sha1)
|
440
|
+
update_count += 1
|
441
|
+
successful_updates<< relative_path
|
442
|
+
end
|
443
|
+
else
|
444
|
+
if @files.delete_file(f, relative_path, commit_sha1)
|
445
|
+
update_count += 1
|
446
|
+
successful_updates<< relative_path
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
rescue SignalException
|
452
|
+
@files.rollback_commit(commit_sha1)
|
453
|
+
say "User aborted, Rolling Back all changes.", Thor::Shell::Color::RED
|
454
|
+
exit(0)
|
455
|
+
rescue
|
456
|
+
@files.rollback_commit(commit_sha1)
|
457
|
+
say "Exception while trying to upload, Rolling back", Thor::Shell::Color::RED
|
458
|
+
exit(0)
|
459
|
+
end
|
460
|
+
if update_count == update_total
|
461
|
+
res = @files.end_commit(commit_sha1)
|
462
|
+
if (Cnvrg::CLI.is_response_success(res, false))
|
463
|
+
# save idx
|
464
|
+
begin
|
465
|
+
@project.update_idx_with_files_commits!((successful_deletions+successful_updates), res["result"]["commit_time"])
|
466
|
+
|
467
|
+
@project.update_idx_with_commit!(commit_sha1)
|
468
|
+
rescue
|
469
|
+
@files.rollback_commit(commit_sha1)
|
470
|
+
say "Couldn't commit updates, Rolling Back all changes.", Thor::Shell::Color::RED
|
471
|
+
exit(1)
|
472
|
+
|
473
|
+
end
|
474
|
+
|
475
|
+
say "Done", Thor::Shell::Color::BLUE
|
476
|
+
if successful_updates.size >0
|
477
|
+
say "Updated:", Thor::Shell::Color::GREEN
|
478
|
+
suc = successful_updates.map { |x| x=Helpers.checkmark() +" "+x }
|
479
|
+
say suc.join("\n"), Thor::Shell::Color::GREEN
|
480
|
+
end
|
481
|
+
if successful_deletions.size >0
|
482
|
+
say "Deleted:", Thor::Shell::Color::GREEN
|
483
|
+
del = successful_updates.map { |x| x=Helpers.checkmark() +" "+x }
|
484
|
+
say del.join("\n"), Thor::Shell::Color::GREEN
|
485
|
+
end
|
486
|
+
say "Total of #{update_count} / #{update_total} files.", Thor::Shell::Color::GREEN
|
346
487
|
else
|
347
488
|
@files.rollback_commit(commit_sha1)
|
348
|
-
say "
|
349
|
-
exit(0)
|
489
|
+
say "Error. Rolling Back all changes.", Thor::Shell::Color::RED
|
350
490
|
end
|
491
|
+
else
|
492
|
+
@files.rollback_commit(commit_sha1)
|
351
493
|
end
|
494
|
+
rescue SignalException
|
495
|
+
say "/nAborting"
|
496
|
+
exit(1)
|
352
497
|
end
|
353
498
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
499
|
+
end
|
500
|
+
|
501
|
+
desc 'download', 'Download updated files'
|
502
|
+
|
503
|
+
def download
|
504
|
+
begin
|
505
|
+
verify_logged_in()
|
506
|
+
project_home = get_project_home
|
507
|
+
@project = Project.new(project_home)
|
508
|
+
@files = Cnvrg::Files.new(@project.owner, @project.slug)
|
509
|
+
|
510
|
+
res = @project.compare_idx["result"]
|
511
|
+
result = res["tree"]
|
512
|
+
commit = res["commit"]
|
513
|
+
if result["updated_on_server"].empty? and result["conflicts"] and result["deleted"].empty?
|
514
|
+
say "Project is up to date", Thor::Shell::Color::GREEN
|
515
|
+
return true
|
516
|
+
end
|
517
|
+
update_count = 0
|
518
|
+
update_total = result["updated_on_server"].size + result["conflicts"].size
|
519
|
+
|
520
|
+
successful_changes = []
|
521
|
+
if update_total ==1
|
522
|
+
say "Downloading #{update_total} file", Thor::Shell::Color::BLUE
|
362
523
|
else
|
363
|
-
|
364
|
-
|
365
|
-
|
524
|
+
say "Downloading #{update_total} files", Thor::Shell::Color::BLUE
|
525
|
+
|
526
|
+
end
|
527
|
+
|
528
|
+
result["conflicts"].each do |f|
|
529
|
+
relative_path = f.gsub(/^#{@project.local_path}/, "")
|
530
|
+
if @files.download_file(f, relative_path, project_home, conflict=true)
|
531
|
+
successful_changes << relative_path
|
366
532
|
end
|
533
|
+
|
367
534
|
end
|
535
|
+
result["updated_on_server"].each do |f|
|
536
|
+
relative_path = f.gsub(/^#{@project.local_path}/, "")
|
537
|
+
if f.end_with? "/"
|
538
|
+
# dir
|
539
|
+
if @files.download_dir(f, relative_path, project_home)
|
540
|
+
successful_changes << relative_path
|
541
|
+
end
|
542
|
+
else
|
543
|
+
# blob
|
544
|
+
if @files.download_file(f, relative_path, project_home)
|
545
|
+
successful_changes << relative_path
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
end
|
550
|
+
if update_total == successful_changes.size
|
551
|
+
# update idx with latest commit
|
552
|
+
@project.update_idx_with_commit!(commit)
|
553
|
+
say "Done. Downloaded:", Thor::Shell::Color::GREEN
|
554
|
+
say successful_changes.join("\n"), Thor::Shell::Color::GREEN
|
555
|
+
say "Total of #{successful_changes.size} / #{update_total} files.", Thor::Shell::Color::GREEN
|
556
|
+
end
|
557
|
+
rescue SignalException
|
558
|
+
say "/nAborting"
|
559
|
+
exit(1)
|
368
560
|
end
|
561
|
+
end
|
369
562
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
exit(0)
|
563
|
+
|
564
|
+
desc 'sync', 'Sync with remote server'
|
565
|
+
|
566
|
+
def sync
|
567
|
+
say 'Checking for new updates from remote version', Thor::Shell::Color::BLUE
|
568
|
+
invoke :download
|
569
|
+
invoke :upload
|
378
570
|
end
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
571
|
+
|
572
|
+
# desc 'random', 'random'
|
573
|
+
# def random
|
574
|
+
# say "Fun trivia game for taking a recess :-)", Thor::Shell::Color::BLUE
|
575
|
+
# subject = ask("Pick a subject\n1.NBA\n2.American History\n3.Data Science\n")
|
576
|
+
# file = "ds.txt"
|
577
|
+
# case subject
|
578
|
+
# when "1"
|
579
|
+
# file = "nba.txt"
|
580
|
+
# when "2"
|
581
|
+
# file = "ah.txt"
|
582
|
+
# when "3"
|
583
|
+
# file = "ds.txt"
|
584
|
+
# end
|
585
|
+
# line = File.readlines(file).sample
|
586
|
+
# q = line[0,line.index('?')+1]
|
587
|
+
# a = line[line.index('?')+1,line.size]
|
588
|
+
# answer = ask(q+"/n")
|
589
|
+
#
|
590
|
+
#
|
591
|
+
#
|
592
|
+
# end
|
593
|
+
# Run
|
594
|
+
#
|
595
|
+
desc 'exec CMD', 'Execute a process'
|
596
|
+
method_option :sync_before, :type => :boolean, :aliases => ["-sb", "--sb"], :default => true
|
597
|
+
method_option :sync_after, :type => :boolean, :aliases => ["-sa", "--sa"], :default => true
|
598
|
+
method_option :title, :type => :string, :aliases => ["-t", "--t"], :default => ""
|
599
|
+
method_option :log, :type => :boolean, :aliases => ["-l", "--l"], :default => false
|
600
|
+
method_option :email_notification, :type => :boolean, :aliases => ["-en", "--en"], :default => false
|
601
|
+
method_option :upload_output, :type => :string, :aliases => ["--uo", "-uo"], :default => ""
|
602
|
+
|
603
|
+
def exec(*cmd)
|
604
|
+
begin
|
605
|
+
verify_logged_in()
|
606
|
+
|
607
|
+
project_home = get_project_home
|
608
|
+
@project = Project.new(project_home)
|
609
|
+
sync_before = options["sync_before"]
|
610
|
+
sync_after = options["sync_after"]
|
611
|
+
print_log = options["log"]
|
612
|
+
title = options["title"]
|
613
|
+
email_notification = options["email_notification"]
|
614
|
+
upload_output = options["upload_output"]
|
615
|
+
time_to_upload = calc_output_time(upload_output)
|
616
|
+
|
617
|
+
if sync_before
|
618
|
+
# Sync before run
|
619
|
+
say "Syncing project before running", Thor::Shell::Color::BLUE
|
620
|
+
say 'Checking for new updates from remote version', Thor::Shell::Color::BLUE
|
621
|
+
download()
|
622
|
+
upload()
|
623
|
+
say "Done Syncing", Thor::Shell::Color::BLUE
|
624
|
+
end
|
625
|
+
|
626
|
+
start_commit = @project.last_local_commit
|
627
|
+
cmd = cmd.join("\s")
|
628
|
+
log = []
|
629
|
+
say "Running: #{cmd}\n", Thor::Shell::Color::BLUE
|
630
|
+
|
631
|
+
@exp = Experiment.new(@project.owner, @project.slug)
|
632
|
+
|
633
|
+
platform = RUBY_PLATFORM
|
634
|
+
machine_name = Socket.gethostname
|
383
635
|
begin
|
384
|
-
@project.update_idx_with_files_commits!((successful_deletions+successful_updates), res["result"]["commit_time"])
|
385
636
|
|
386
|
-
@
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
637
|
+
@exp.start(cmd, platform, machine_name, start_commit, title, email_notification)
|
638
|
+
unless @exp.slug.nil?
|
639
|
+
real = Time.now
|
640
|
+
exp_success = true
|
641
|
+
memory_total = []
|
642
|
+
cpu_total = []
|
643
|
+
start_loop = Time.now
|
644
|
+
begin
|
645
|
+
PTY.spawn(cmd) do |stdout, stdin, pid, stderr|
|
646
|
+
begin
|
647
|
+
stdout.each do |line|
|
648
|
+
cur_time = Time.now
|
649
|
+
monitor = %x{ps aux|awk '{print $2,$3,$4}'|grep #{pid} }
|
650
|
+
monitor_by = monitor.split(" ")
|
651
|
+
memory = monitor_by[2]
|
652
|
+
cpu = monitor_by[1]
|
653
|
+
memory_total << memory.to_f
|
654
|
+
cpu_total << cpu.to_f
|
655
|
+
real_time= Time.now-real
|
656
|
+
|
657
|
+
cur_log = {time: cur_time,
|
658
|
+
message: line,
|
659
|
+
type: "stdout",
|
660
|
+
real: real_time}
|
661
|
+
if print_log
|
662
|
+
puts cur_log
|
663
|
+
end
|
664
|
+
log << cur_log
|
665
|
+
|
666
|
+
begin
|
667
|
+
if time_to_upload !=0
|
668
|
+
if time_to_upload <= Time.now - start_loop
|
669
|
+
#upload current log
|
670
|
+
cpu_average = cpu_total.inject(0) { |sum, el| sum + el }.to_f / cpu_total.size
|
671
|
+
memory_average = memory_total.inject(0) { |sum, el| sum + el }.to_f / memory_total.size
|
672
|
+
|
673
|
+
@exp.upload_temp_log(log, cpu_average, memory_average)
|
674
|
+
log = []
|
675
|
+
start_loop = Time.now
|
676
|
+
end
|
677
|
+
|
678
|
+
end
|
679
|
+
rescue
|
680
|
+
say "Failed to upload ongoing results, continuing with experiment", Thor::Shell::Color::YELLOW
|
681
|
+
end
|
391
682
|
|
392
|
-
|
683
|
+
end
|
684
|
+
|
685
|
+
|
686
|
+
if stderr
|
687
|
+
|
688
|
+
stderr.each do |err|
|
689
|
+
|
690
|
+
log << {time: Time.now, message: err, type: "stderr"}
|
691
|
+
puts err
|
692
|
+
end
|
693
|
+
end
|
694
|
+
|
695
|
+
rescue Errno::EIO => e
|
696
|
+
break
|
697
|
+
rescue Errno::ENOENT
|
698
|
+
|
699
|
+
exp_success = false
|
700
|
+
say "command \"#{cmd}\" couldn't be executed, verify command is valid", Thor::Shell::Color::RED
|
701
|
+
rescue PTY::ChildExited
|
702
|
+
|
703
|
+
exp_success = false
|
704
|
+
say "The process exited!", Thor::Shell::Color::RED
|
705
|
+
rescue => e
|
706
|
+
ensure
|
707
|
+
::Process.wait pid
|
708
|
+
|
709
|
+
end
|
710
|
+
cpu_average = cpu_total.inject(0) { |sum, el| sum + el }.to_f / cpu_total.size
|
711
|
+
memory_average = memory_total.inject(0) { |sum, el| sum + el }.to_f / memory_total.size
|
712
|
+
exit_status = $?.exitstatus
|
713
|
+
puts exit_status
|
714
|
+
if exit_status != 0
|
715
|
+
exp_success = false
|
716
|
+
end
|
717
|
+
if !exp_success
|
718
|
+
end_commit = @project.last_local_commit
|
719
|
+
res = @exp.end(log, exit_status, end_commit, cpu_average, memory_average)
|
720
|
+
say "Experiment has failed, look at the log for more details or run cnvrg exec --log", Thor::Shell::Color::RED
|
721
|
+
exit(0)
|
722
|
+
end
|
723
|
+
if sync_after
|
724
|
+
say "Syncing project after running", Thor::Shell::Color::BLUE
|
725
|
+
# Sync after run
|
726
|
+
download()
|
727
|
+
upload()
|
728
|
+
say "Done Syncing", Thor::Shell::Color::BLUE
|
729
|
+
end
|
730
|
+
end_commit = @project.last_local_commit
|
731
|
+
|
732
|
+
res = @exp.end(log, exit_status, end_commit, cpu_average, memory_average)
|
733
|
+
check = Helpers.checkmark()
|
734
|
+
say "#{check} Done. Experiment's result: #{Cnvrg::Helpers.remote_url}/#{@project.owner}/projects/#{@project.slug}/experiments/#{@exp.slug}", Thor::Shell::Color::GREEN
|
735
|
+
end
|
736
|
+
rescue
|
737
|
+
say "Couldn't run #{cmd}, check your input parameters", Thor::Shell::Color::RED
|
738
|
+
exit(1)
|
739
|
+
end
|
740
|
+
|
741
|
+
|
742
|
+
end
|
393
743
|
|
394
|
-
say "Done", Thor::Shell::Color::BLUE
|
395
|
-
if successful_updates.size >0
|
396
|
-
say "Updated:", Thor::Shell::Color::GREEN
|
397
|
-
suc = successful_updates.map { |x| x=Helpers.checkmark() +" "+x }
|
398
|
-
say suc.join("\n"), Thor::Shell::Color::GREEN
|
399
|
-
end
|
400
|
-
if successful_deletions.size >0
|
401
|
-
say "Deleted:", Thor::Shell::Color::GREEN
|
402
|
-
del = successful_updates.map { |x| x=Helpers.checkmark() +" "+x }
|
403
|
-
say del.join("\n"), Thor::Shell::Color::GREEN
|
404
744
|
end
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
say "Error. Rolling Back all changes.", Thor::Shell::Color::RED
|
745
|
+
rescue SignalException
|
746
|
+
say "/nAborting"
|
747
|
+
exit(1)
|
409
748
|
end
|
410
|
-
else
|
411
|
-
@files.rollback_commit(commit_sha1)
|
412
749
|
end
|
413
750
|
|
414
|
-
|
751
|
+
desc 'run_notebook', 'Starts a new notebook environment'
|
752
|
+
method_option :notebook_dir, :type => :string, :aliases => ["-n", "--n"], :default => "", :desc => "relative path to notebook dir from current directory"
|
753
|
+
method_option :docker, :type => :boolean, :aliases => ["-d", "--d"], :default => true
|
754
|
+
method_option :image_name, :type => :string, :aliases => ["-i", "--i"], :default => ""
|
415
755
|
|
416
|
-
|
756
|
+
def run_notebook
|
757
|
+
begin
|
758
|
+
cur_path = Dir.pwd
|
759
|
+
notebook_dir = options["notebook_dir"]
|
760
|
+
if notebook_dir.empty?
|
761
|
+
notebook_dir = cur_path
|
762
|
+
else
|
763
|
+
notebook_dir = cur_path+ notebook_dir
|
764
|
+
end
|
765
|
+
say "Linking notebook directory to: #{notebook_dir}", Thor::Shell::Color::BLUE
|
766
|
+
docker = options["docker"]
|
767
|
+
try_again = true
|
768
|
+
|
769
|
+
|
770
|
+
if docker
|
771
|
+
docker_path = verify_software_installed("docker")
|
772
|
+
image_name = options["image_name"]
|
773
|
+
if image_name.empty?
|
774
|
+
images_list = `#{docker_path} images`
|
775
|
+
if images_list.empty? or images_list.nil?
|
776
|
+
say "you don't have any images to run", Thor::Shell::Color::BLUE
|
777
|
+
else
|
778
|
+
say "Choose image name to run as a container\n", Thor::Shell::Color::BLUE
|
779
|
+
say images_list
|
780
|
+
image_name = ask("\nwhat is the image name?\n")
|
781
|
+
end
|
417
782
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
783
|
+
end
|
784
|
+
while (try_again) do
|
785
|
+
run_docker = `#{docker_path} run -d -p 8888:8888 -v #{notebook_dir}:/home/ds/notebooks -t -i #{image_name} 2>&1`
|
786
|
+
if !run_docker.match(/[a-z0-9]{64}/).nil? and !run_docker.include? "Error"
|
787
|
+
container_id = get_container_id()
|
788
|
+
sleep(3)
|
789
|
+
logs = `docker logs #{container_id}`
|
790
|
+
url = URI.extract(logs).reject { |x| x if !x.include? "http" }.uniq![0]
|
791
|
+
if !url.empty?
|
792
|
+
check = Helpers.checkmark()
|
793
|
+
|
794
|
+
say "#{check} Notebook server started successfully, view notebook in url: #{url}", Thor::Shell::Color::GREEN
|
795
|
+
try_again= false
|
796
|
+
else
|
797
|
+
say "Couldn't start notebook server", Thor::Shell::Color::RED
|
798
|
+
exit(1)
|
799
|
+
end
|
423
800
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
801
|
+
elsif run_docker.include? "port is already allocated"
|
802
|
+
say "Couldn't start notebook with port 8888, port is taken", Thor::Shell::Color::RED
|
803
|
+
port_container = `#{docker_path} ps |grep 8888 |awk '{print $1}'`.strip!
|
804
|
+
stop = ask "There is another running notebook server: #{port_container}, do you want to stop it?", Thor::Shell::Color::BLUE, limited_to: ['y', 'n'], default: 'y'
|
805
|
+
if stop == "y"
|
806
|
+
did_stop = system("#{docker_path} stop #{port_container}")
|
807
|
+
if !did_stop
|
808
|
+
say "Couldn't stop notebook server: #{port_container}", Thor::Shell::Color::RED
|
809
|
+
exit(1)
|
433
810
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
811
|
+
end
|
812
|
+
else
|
813
|
+
logs = `#{docker_path} logs #{port_container}`
|
814
|
+
url = URI.extract(logs).reject { |x| x if !x.include? "http" }.uniq![0]
|
815
|
+
say "Okay, you could find the existing server in: #{url}", Thor::Shell::Color::BLUE
|
816
|
+
exit(1)
|
817
|
+
end
|
818
|
+
else
|
819
|
+
say "Couldn't start notebook server", Thor::Shell::Color::RED
|
820
|
+
exit(1)
|
439
821
|
|
440
|
-
|
822
|
+
end
|
823
|
+
end
|
824
|
+
else
|
825
|
+
jup =verify_software_installed("jupyter-notebook")
|
826
|
+
logs = `#{jup} --no-browser --ip=0.0.0.0 --notebook-dir=#{notebook_dir}`
|
827
|
+
url = URI.extract(logs).reject { |x| x if !x.include? "http" }.uniq![0]
|
828
|
+
if !url.empty?
|
829
|
+
check = Helpers.checkmark()
|
441
830
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
831
|
+
say "#{check} Notebook server started successfully, view notebook in url: #{url}", Thor::Shell::Color::GREEN
|
832
|
+
else
|
833
|
+
say "Couldn't start notebook server", Thor::Shell::Color::RED
|
834
|
+
exit(1)
|
835
|
+
end
|
836
|
+
|
837
|
+
end
|
838
|
+
rescue SignalException
|
839
|
+
say "Aborting"
|
840
|
+
exit(1)
|
446
841
|
end
|
447
842
|
|
843
|
+
|
448
844
|
end
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
845
|
+
|
846
|
+
desc 'install_notebook_libraries', 'Starts a new notebook environment'
|
847
|
+
method_option :commit_name, :type => :string, :aliases => ["-c", "--c"], :default => "", :desc => "commit changes to notebook server when finished"
|
848
|
+
|
849
|
+
def install_notebook_libraries
|
850
|
+
begin
|
851
|
+
docker_path = verify_software_installed("docker")
|
852
|
+
container_id = get_container_id
|
853
|
+
say "Opening shell in notebook server\nYou can run pip install [library] to install more tools\ntype exit to finish", Thor::Shell::Color::BLUE
|
854
|
+
system("#{docker_path} exec -it #{container_id} bash")
|
855
|
+
commit_name = options["commit_name"]
|
856
|
+
if !commit_name.empty?
|
857
|
+
return commit_notebook(commit_name)
|
460
858
|
end
|
859
|
+
rescue SignalException
|
860
|
+
say "/nAborting"
|
861
|
+
exit(1)
|
461
862
|
end
|
462
863
|
|
463
864
|
end
|
464
|
-
if update_total == successful_changes.size
|
465
|
-
# update idx with latest commit
|
466
|
-
@project.update_idx_with_commit!(commit)
|
467
|
-
say "Done. Downloaded:", Thor::Shell::Color::GREEN
|
468
|
-
say successful_changes.join("\n"), Thor::Shell::Color::GREEN
|
469
|
-
say "Total of #{successful_changes.size} / #{update_total} files.", Thor::Shell::Color::GREEN
|
470
|
-
end
|
471
|
-
end
|
472
865
|
|
866
|
+
desc 'commit_notebook', 'commit notebook changes to create a new notebook image'
|
473
867
|
|
474
|
-
|
868
|
+
def commit_notebook(notebook_image_name)
|
869
|
+
begin
|
870
|
+
docker_path = verify_software_installed("docker")
|
475
871
|
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
invoke :upload
|
480
|
-
end
|
872
|
+
container_id = get_container_id
|
873
|
+
owner = Cnvrg::CLI.get_owner()
|
874
|
+
say "Commiting notebook changes to a: #{owner}/#{notebook_image_name}", Thor::Shell::Color::BLUE
|
481
875
|
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
# end
|
495
|
-
# line = File.readlines(file).sample
|
496
|
-
# q = line[0,line.index('?')+1]
|
497
|
-
# a = line[line.index('?')+1,line.size]
|
498
|
-
# answer = ask(q+"/n")
|
499
|
-
#
|
500
|
-
#
|
501
|
-
#
|
502
|
-
# end
|
503
|
-
# Run
|
504
|
-
#
|
505
|
-
desc 'exec CMD', 'Execute a process'
|
506
|
-
method_option :sync_before, :type => :boolean, :aliases => ["-sb", "--sb"], :default => true
|
507
|
-
method_option :sync_after, :type => :boolean, :aliases => ["-sa", "--sa"], :default => true
|
508
|
-
method_option :title, :type => :string, :aliases => ["-t", "--t"], :default => ""
|
509
|
-
method_option :log, :type => :boolean, :aliases => ["-l", "--l"], :default => false
|
510
|
-
method_option :email_notification, :type => :boolean, :aliases => ["-en", "--en"], :default => false
|
511
|
-
method_option :upload_output, :type => :string, :aliases => ["--uo", "-uo"], :default => ""
|
512
|
-
|
513
|
-
def exec(*cmd)
|
514
|
-
verify_logged_in()
|
515
|
-
|
516
|
-
project_home = get_project_home
|
517
|
-
@project = Project.new(project_home)
|
518
|
-
sync_before = options["sync_before"]
|
519
|
-
sync_after = options["sync_after"]
|
520
|
-
print_log = options["log"]
|
521
|
-
title = options["title"]
|
522
|
-
email_notification = options["email_notification"]
|
523
|
-
upload_output = options["upload_output"]
|
524
|
-
time_to_upload = calc_output_time(upload_output)
|
525
|
-
|
526
|
-
if sync_before
|
527
|
-
# Sync before run
|
528
|
-
say "Syncing project before running", Thor::Shell::Color::BLUE
|
529
|
-
say 'Checking for new updates from remote version', Thor::Shell::Color::BLUE
|
530
|
-
download()
|
531
|
-
upload()
|
532
|
-
say "Done Syncing", Thor::Shell::Color::BLUE
|
876
|
+
commit_res = system("#{docker_path} commit #{container_id} #{owner}/#{notebook_image_name}")
|
877
|
+
if commit_res
|
878
|
+
checker = Helpers.checkmark()
|
879
|
+
say "#{checker} Done.", Thor::Shell::Color::GREEN
|
880
|
+
else
|
881
|
+
say "Couldn't commit new notebook image ", Thor::Shell::Color::RED
|
882
|
+
|
883
|
+
end
|
884
|
+
rescue SignalException
|
885
|
+
say "/nAborting"
|
886
|
+
exit(1)
|
887
|
+
end
|
533
888
|
end
|
534
889
|
|
535
|
-
|
536
|
-
cmd = cmd.join("\s")
|
537
|
-
log = []
|
538
|
-
say "Running: #{cmd}", Thor::Shell::Color::BLUE
|
890
|
+
desc 'upload_notebook', 'commit notebook changes to create a new notebook image'
|
539
891
|
|
540
|
-
|
892
|
+
def upload_image(image_name)
|
893
|
+
docker_path = verify_software_installed("docker")
|
894
|
+
owner = Cnvrg::CLI.get_owner()
|
895
|
+
# verify image exist
|
896
|
+
# owner = "cnvrgio"
|
897
|
+
images = `#{docker_path} images |grep #{owner}/#{image_name}`
|
898
|
+
if images.empty?
|
899
|
+
say "Couldn't find any images named: #{owner}/#{image_name}", Thor::Shell::Color::RED
|
900
|
+
exit(1)
|
901
|
+
end
|
902
|
+
path = File.expand_path('~')+"/.cnvrg/#{owner}_#{image_name}.tar"
|
903
|
+
begin
|
904
|
+
say "Creating image file to upload", Thor::Shell::Color::BLUE
|
905
|
+
if !(File.exist? path or File.exist? path+"gz")
|
906
|
+
saveRes = system("#{docker_path} save #{owner}/#{image_name}>#{path}")
|
907
|
+
if !saveRes
|
908
|
+
say "Couldn't create tar file from image", Thor::Shell::Color::RED
|
909
|
+
exit(1)
|
910
|
+
end
|
911
|
+
gzipRes = system("gzip -f #{path}")
|
912
|
+
if !gzipRes
|
913
|
+
say "Couldn't create tar file from image", Thor::Shell::Color::RED
|
914
|
+
exit(1)
|
915
|
+
end
|
916
|
+
end
|
541
917
|
|
542
|
-
|
543
|
-
|
544
|
-
begin
|
918
|
+
path = path+".gz"
|
919
|
+
@files = Cnvrg::Files.new(owner, "")
|
545
920
|
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
cpu_total << cpu.to_f
|
566
|
-
real_time= Time.now-real
|
567
|
-
|
568
|
-
cur_log = {time: cur_time,
|
569
|
-
message: line,
|
570
|
-
type: "stdout",
|
571
|
-
rss: memory,
|
572
|
-
cpu: cpu,
|
573
|
-
real: real_time}
|
574
|
-
if print_log
|
575
|
-
puts cur_log
|
576
|
-
end
|
577
|
-
log << cur_log
|
578
|
-
begin
|
579
|
-
if time_to_upload !=0
|
580
|
-
if time_to_upload <= Time.now - start_loop
|
581
|
-
#upload current log
|
582
|
-
cpu_average = cpu_total.inject(0) { |sum, el| sum + el }.to_f / cpu_total.size
|
583
|
-
memory_average = memory_total.inject(0) { |sum, el| sum + el }.to_f / memory_total.size
|
584
|
-
|
585
|
-
@exp.upload_temp_log(log, cpu_average, memory_average)
|
586
|
-
log = []
|
587
|
-
start_loop = Time.now
|
588
|
-
end
|
921
|
+
exit_status = $?.exitstatus
|
922
|
+
if exit_status == 0
|
923
|
+
say "Uploading image file", Thor::Shell::Color::BLUE
|
924
|
+
res = @files.upload_image(path, image_name, owner)
|
925
|
+
if res
|
926
|
+
File.delete(path)
|
927
|
+
checks = Helpers.checkmark()
|
928
|
+
say "#{checks} Done", Thor::Shell::Color::GREEN
|
929
|
+
else
|
930
|
+
say "Couldn't upload image", Thor::Shell::Color::RED
|
931
|
+
end
|
932
|
+
else
|
933
|
+
say "Couldn't create image file for: #{owner}/#{image_name}", Thor::Shell::Color::RED
|
934
|
+
exit(1)
|
935
|
+
end
|
936
|
+
rescue SignalException
|
937
|
+
say "Couldn't upload image file for: #{owner}/#{image_name}", Thor::Shell::Color::RED
|
938
|
+
exit(1)
|
939
|
+
end
|
589
940
|
|
590
|
-
end
|
591
|
-
rescue
|
592
|
-
say "Failed to upload ongoing results, continuing with experiment", Thor::Shell::Color::YELLOW
|
593
|
-
end
|
594
941
|
|
942
|
+
end
|
943
|
+
|
944
|
+
desc 'download_image', 'commit notebook changes to create a new notebook image'
|
945
|
+
|
946
|
+
def download_image(image_name)
|
947
|
+
begin
|
948
|
+
owner = Cnvrg::CLI.get_owner()
|
595
949
|
|
950
|
+
notebooks_res = Cnvrg::API.request("users/#{owner}/images/" + "find", 'POST', {image_name: image_name})
|
951
|
+
|
952
|
+
if Cnvrg::CLI.is_response_success(notebooks_res)
|
953
|
+
|
954
|
+
images = notebooks_res["result"]["images"]
|
955
|
+
if images.empty?
|
956
|
+
say "Couldn't find any image with name: #{image_name}", Thor::Shell::Color::RED
|
957
|
+
exit(1)
|
958
|
+
elsif images.size == 1
|
959
|
+
image_id = images[0]["slug"]
|
960
|
+
else
|
961
|
+
printf "%-20s %-20s %-30s %-20s\n", "name", "version", "last updated", "created by"
|
962
|
+
images.each_with_index do |u, i|
|
963
|
+
time = Time.parse(u["updated_at"])
|
964
|
+
update_at = get_local_time(time)
|
965
|
+
version = u["version"] || "v1"
|
966
|
+
created_by = u["image_file_name"][/^[^\_]*/]
|
967
|
+
printf "%-20s %-20s %-30s %-20s\n", u["name"], version, update_at, created_by
|
596
968
|
end
|
597
|
-
|
598
|
-
|
599
|
-
|
969
|
+
choice = ask("Which version to download for #{image_name}?")
|
970
|
+
images.each do |u|
|
971
|
+
if u["version"] == choice
|
972
|
+
image_id = u["slug"]
|
600
973
|
end
|
974
|
+
|
601
975
|
end
|
602
|
-
Process.wait(pid)
|
603
|
-
rescue Errno::EIO
|
604
|
-
break
|
605
|
-
rescue Errno::ENOENT
|
606
|
-
exp_success = false
|
607
|
-
say "command \"#{cmd}\" couldn't be executed, verify command is valid", Thor::Shell::Color::RED
|
608
|
-
rescue PTY::ChildExited
|
609
|
-
exp_success = false
|
610
|
-
puts "The process exited!"
|
611
|
-
end
|
612
976
|
|
613
|
-
cpu_average = cpu_total.inject(0) { |sum, el| sum + el }.to_f / cpu_total.size
|
614
|
-
memory_average = memory_total.inject(0) { |sum, el| sum + el }.to_f / memory_total.size
|
615
|
-
exit_status = $?.exitstatus
|
616
|
-
if !exp_success
|
617
|
-
end_commit = @project.last_local_commit
|
618
|
-
res = @exp.end(log, exit_status, end_commit, cpu_average, memory_average)
|
619
|
-
say "Experiment has failed", Thor::Shell::Color::RED
|
620
|
-
exit(0)
|
621
977
|
end
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
978
|
+
end
|
979
|
+
path = Dir.pwd+"/#{owner}_#{image_name}.tar.gz"
|
980
|
+
@files = Cnvrg::Files.new(owner, "")
|
981
|
+
|
982
|
+
say "Downloading image file", Thor::Shell::Color::BLUE
|
983
|
+
begin
|
984
|
+
res = @files.download_image(path, image_id, owner)
|
985
|
+
if res
|
986
|
+
checks = Helpers.checkmark()
|
987
|
+
say "#{checks} Done", Thor::Shell::Color::GREEN
|
988
|
+
return true
|
989
|
+
else
|
990
|
+
say "Couldn't download image #{image_name}", Thor::Shell::Color::RED
|
991
|
+
return false
|
628
992
|
end
|
629
|
-
|
993
|
+
rescue Interrupt
|
994
|
+
say "The user has exited to process, aborting", Thor::Shell::Color::BLUE
|
995
|
+
exit(1)
|
996
|
+
end
|
997
|
+
rescue SignalException
|
998
|
+
say "/nAborting"
|
999
|
+
exit(1)
|
1000
|
+
end
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
|
1004
|
+
desc 'list_images', 'lists all custom images you can pull'
|
630
1005
|
|
631
|
-
|
632
|
-
|
633
|
-
|
1006
|
+
def list_images
|
1007
|
+
owner = Cnvrg::CLI.get_owner()
|
1008
|
+
res = Cnvrg::API.request("users/#{owner}/images/list", 'GET')
|
1009
|
+
if Cnvrg::CLI.is_response_success(res)
|
1010
|
+
printf "%-20s %-20s %-30s %-20s\n", "name", "version", "last updated", "created by"
|
1011
|
+
res["result"]["images"].each do |u|
|
1012
|
+
time = Time.parse(u["updated_at"])
|
1013
|
+
update_at = get_local_time(time)
|
1014
|
+
version = u["version"] || "v1"
|
1015
|
+
created_by = u["image_file_name"][/^[^\_]*/]
|
1016
|
+
|
1017
|
+
printf "%-20s %-20s %-30s %-20s\n", u["name"], version, update_at, created_by
|
634
1018
|
end
|
1019
|
+
end
|
1020
|
+
return res["result"]["images"]
|
1021
|
+
end
|
635
1022
|
|
1023
|
+
|
1024
|
+
desc 'pull_image', 'downloads and loads a custom image'
|
1025
|
+
|
1026
|
+
def pull_image(image_name)
|
1027
|
+
begin
|
1028
|
+
|
1029
|
+
if download_image(image_name)
|
1030
|
+
path = Dir.pwd+"/#{owner}_#{image_name}.tar.gz"
|
1031
|
+
loadRes = system("docker load < #{path}")
|
1032
|
+
if loadRes.include? "Loaded image"
|
1033
|
+
say loadRes, Thor::Shell::Color::GREEN
|
1034
|
+
else
|
1035
|
+
say loadRes, Thor::Shell::Color::RED
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
end
|
1039
|
+
rescue SignalException
|
1040
|
+
say "\nAborting"
|
1041
|
+
exit(1)
|
636
1042
|
end
|
637
1043
|
|
638
1044
|
end
|
639
|
-
end
|
640
1045
|
|
1046
|
+
no_tasks do
|
1047
|
+
def get_container_id
|
1048
|
+
docker_path = verify_software_installed("docker")
|
641
1049
|
|
642
|
-
|
643
|
-
|
644
|
-
|
1050
|
+
container_id = `#{docker_path} ps --quiet --last=1 --filter status=running`.strip!
|
1051
|
+
if container_id.empty?
|
1052
|
+
say "Couldn't find a running notebook server, execute run_notebook", Thor::Shell::Color::RED
|
1053
|
+
exit(1)
|
1054
|
+
end
|
1055
|
+
return container_id
|
1056
|
+
end
|
645
1057
|
|
646
|
-
|
647
|
-
|
648
|
-
|
1058
|
+
def set_owner(owner, username)
|
1059
|
+
home_dir = File.expand_path('~')
|
1060
|
+
|
1061
|
+
begin
|
1062
|
+
if !File.directory? home_dir+"/.cnvrg"
|
1063
|
+
FileUtils.mkdir_p([home_dir+"/.cnvrg", home_dir+"/.cnvrg/tmp"])
|
1064
|
+
end
|
1065
|
+
if !File.exist?(home_dir+"/.cnvrg/config.yml")
|
1066
|
+
FileUtils.touch [home_dir+"/.cnvrg/config.yml"]
|
1067
|
+
end
|
1068
|
+
config = YAML.load_file(home_dir+"/.cnvrg/config.yml")
|
1069
|
+
if config.empty?
|
1070
|
+
config = {owner: owner, username: username, version_last_check: get_start_day(), api: "https://cnvrg.io/api"}
|
1071
|
+
else
|
1072
|
+
config = {owner: owner, username: username, version_last_check: get_start_day(), api: config.to_h[:api]}
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
File.open(home_dir+"/.cnvrg/config.yml", "w+") { |f| f.write config.to_yaml }
|
1076
|
+
return true
|
1077
|
+
rescue
|
1078
|
+
return false
|
649
1079
|
end
|
650
|
-
|
651
|
-
|
1080
|
+
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
def get_start_day
|
1084
|
+
time = Time.now
|
1085
|
+
return Time.new(time.year, time.month, time.day)
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
def calc_output_time(upload_output)
|
1089
|
+
if upload_output.nil? or upload_output.empty?
|
1090
|
+
return 0
|
652
1091
|
end
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
1092
|
+
time = upload_output.split(/(\d+)/).reject(&:empty?).map { |x| x.strip }
|
1093
|
+
if time.size!=2
|
1094
|
+
upload_output = ask("upload_output should be {number}{s/m/h/d} i.e. 5m (5 minutes), 1h (1 hour)\nre-enter value for upload_output")
|
1095
|
+
return calc_output_time(upload_output)
|
1096
|
+
end
|
1097
|
+
if time[0] == "0"
|
1098
|
+
return -1
|
1099
|
+
end
|
1100
|
+
case time[1].downcase
|
1101
|
+
when "s"
|
1102
|
+
return time[0].to_f
|
1103
|
+
when "m"
|
1104
|
+
return time[0].to_f*60
|
1105
|
+
when "h"
|
1106
|
+
return time[0].to_f*3600
|
1107
|
+
when "d"
|
1108
|
+
return time[0].to_f*24*3600
|
1109
|
+
else
|
1110
|
+
upload_output = ask("upload_output should be {number}{s/m/h/d} i.e. 5m (5 minutes), 1h (1 hour)\n re-enter value for upload_output")
|
1111
|
+
calc_output_time(upload_output)
|
1112
|
+
end
|
1113
|
+
|
658
1114
|
end
|
659
1115
|
|
660
|
-
|
1116
|
+
def self.is_response_success(response, should_exit=true)
|
1117
|
+
if response["status"]!= 200
|
1118
|
+
error = response['message']
|
1119
|
+
if response["status"] == 500
|
1120
|
+
say("<%= color('Server Error', RED) %>")
|
1121
|
+
else
|
1122
|
+
say("<%= color('Error: #{error}', RED) %>")
|
1123
|
+
end
|
661
1124
|
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
upload_output = ask("upload_output should be {number}{s/m/h/d} i.e. 5m (5 minutes), 1h (1 hour)\nre-enter value for upload_output")
|
670
|
-
return calc_output_time(upload_output)
|
671
|
-
end
|
672
|
-
case time[1].downcase
|
673
|
-
when "s"
|
674
|
-
return time[0].to_f
|
675
|
-
when "m"
|
676
|
-
return time[0].to_f*60
|
677
|
-
when "h"
|
678
|
-
return time[0].to_f*3600
|
679
|
-
when "d"
|
680
|
-
return time[0].to_f*24*3600
|
681
|
-
else
|
682
|
-
upload_output = ask("upload_output should be {number}{s/m/h/d} i.e. 5m (5 minutes), 1h (1 hour)\n re-enter value for upload_output")
|
683
|
-
calc_output_time(upload_output)
|
1125
|
+
if should_exit
|
1126
|
+
exit(1)
|
1127
|
+
else
|
1128
|
+
return false
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
return true
|
684
1132
|
end
|
685
1133
|
|
686
|
-
|
1134
|
+
def self.get_owner
|
1135
|
+
home_dir = File.expand_path('~')
|
687
1136
|
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
say("<%= color('Server Error', RED) %>")
|
1137
|
+
config = YAML.load_file(home_dir+ "/.cnvrg/config.yml")
|
1138
|
+
owner = config.to_h[:owner]
|
1139
|
+
if owner.empty?
|
1140
|
+
invoke :set_default_owner
|
1141
|
+
return get_owner()
|
694
1142
|
else
|
695
|
-
|
1143
|
+
return owner
|
696
1144
|
end
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
def get_project_home
|
1148
|
+
absolute_path = Dir.pwd
|
1149
|
+
dirs = absolute_path.split("/")
|
1150
|
+
dirs.pop while not Dir.exists?("#{dirs.join("/")}/.cnvrg") and dirs.size != 0
|
697
1151
|
|
698
|
-
if
|
1152
|
+
if dirs.size == 0
|
1153
|
+
say "Couldn't find cnvrg directory. Please start a new project", Thor::Shell::Color::RED
|
699
1154
|
exit(1)
|
1155
|
+
end
|
1156
|
+
return dirs.join("/")
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
def should_update_version
|
1160
|
+
res = Cnvrg::API.request("/cli/version", 'GET')
|
1161
|
+
if Cnvrg::CLI.is_response_success(res, false)
|
1162
|
+
updated_version = res["result"]["version"]
|
1163
|
+
if updated_version != Cnvrg::VERSION
|
1164
|
+
return true
|
1165
|
+
else
|
1166
|
+
return false
|
1167
|
+
end
|
700
1168
|
else
|
701
1169
|
return false
|
702
1170
|
end
|
703
1171
|
end
|
704
|
-
return true
|
705
|
-
end
|
706
1172
|
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
1173
|
+
def verify_logged_in
|
1174
|
+
auth = Cnvrg::Auth.new
|
1175
|
+
unless auth.is_logged_in?
|
1176
|
+
say 'You\'re not logged in', Thor::Shell::Color::RED
|
1177
|
+
say 'Please log in via `cnvrg login`', Thor::Shell::Color::YELLOW
|
1178
|
+
exit(1)
|
1179
|
+
end
|
1180
|
+
if !Helpers.internet_connection?
|
1181
|
+
say "you seem to be offline, please check your internet connection", Thor::Shell::Color::RED
|
1182
|
+
exit(1)
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
config = YAML.load_file(File.expand_path('~')+"/.cnvrg/config.yml")
|
1186
|
+
version_date = config.to_h[:version_last_check]
|
1187
|
+
next_day = get_start_day+ 86399
|
1188
|
+
if (version_date..next_day).cover?(Time.now)
|
1189
|
+
return true
|
1190
|
+
else
|
1191
|
+
if should_update_version()
|
1192
|
+
say "There is a new version, run gem update cnvrg", Thor::Shell::Color::BLUE
|
1193
|
+
end
|
1194
|
+
end
|
1195
|
+
|
715
1196
|
end
|
716
|
-
end
|
717
1197
|
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
1198
|
+
def verify_software_installed(software)
|
1199
|
+
install_url = Cnvrg::CLI::INSTALLATION_URLS[software.to_sym]
|
1200
|
+
installed = `which #{software}`
|
1201
|
+
if installed.empty? or installed.nil?
|
1202
|
+
say "#{software} isn't installed, please install it first: #{install_url}", Thor::Shell::Color::RED
|
1203
|
+
exit(1)
|
1204
|
+
end
|
1205
|
+
installed.strip!
|
1206
|
+
case software
|
1207
|
+
when "docker"
|
1208
|
+
is_running = `#{installed} images`
|
1209
|
+
if is_running.include? "Cannot connect to the Docker daemon"
|
1210
|
+
if Helpers.mac?
|
1211
|
+
system("open -a Docker")
|
1212
|
+
else
|
1213
|
+
#is linux
|
1214
|
+
|
722
1215
|
|
723
|
-
|
724
|
-
|
725
|
-
|
1216
|
+
end
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
return installed
|
726
1220
|
end
|
727
|
-
return dirs.join("/")
|
728
|
-
end
|
729
1221
|
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
1222
|
+
def get_local_time(time_to_update)
|
1223
|
+
local = Time.now.localtime
|
1224
|
+
gmt_offset = local.gmt_offset
|
1225
|
+
new_time =time_to_update +gmt_offset
|
1226
|
+
return new_time.to_s.gsub("UTC", "")
|
1227
|
+
|
736
1228
|
end
|
737
|
-
end
|
738
1229
|
|
739
1230
|
|
1231
|
+
end
|
740
1232
|
end
|
741
1233
|
end
|
742
|
-
end
|
743
1234
|
|
744
1235
|
|
745
1236
|
|