cnvrg 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,26 @@
1
+ module Cnvrg
2
+ class Experiment
3
+ attr_reader :slug
4
+ def initialize(owner, project_slug)
5
+ @project_slug = project_slug
6
+ @owner = owner
7
+ @base_resource = "users/#{owner}/projects/#{project_slug}/"
8
+ @slug = nil
9
+ end
10
+
11
+ def start(input, platform, machine_name, start_commit,name)
12
+ res = Cnvrg::API.request(@base_resource + "experiment/start", 'POST', { input: input, platform: platform, machine_name: machine_name, start_commit: start_commit , title:name})
13
+ Cnvrg::CLI.is_response_success(res)
14
+
15
+ @slug = res.to_h["result"].to_h["slug"]
16
+
17
+ return res
18
+
19
+ end
20
+
21
+ def end(output, exit_status, end_commit,cpu_average, memory_average)
22
+ response = Cnvrg::API.request(@base_resource + "experiment/end", 'POST', { output: output, exp_slug: @slug, exit_status: exit_status, end_commit: end_commit, cpu_average:cpu_average,memory_average:memory_average })
23
+ Cnvrg::CLI.is_response_success(response)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,115 @@
1
+ require 'mimemagic'
2
+ require 'pry'
3
+ module Cnvrg
4
+ class Files
5
+
6
+ attr_reader :base_resource
7
+
8
+ def initialize(owner, project_slug)
9
+ @project_slug = project_slug
10
+ @owner = owner
11
+ @base_resource = "users/#{owner}/projects/#{project_slug}/"
12
+ end
13
+
14
+ def upload_file(absolute_path, relative_path, commit_sha1)
15
+ file_name = File.basename relative_path
16
+ file_size = File.size(relative_path).to_f
17
+ upload_resp = Cnvrg::API.request(@base_resource + "upload_file", 'POST_FILE', { absolute_path: absolute_path, relative_path: relative_path,
18
+ commit_sha1: commit_sha1, file_name: file_name ,file_size:file_size})
19
+ if Cnvrg::CLI.is_response_success(upload_resp, false)
20
+ path = upload_resp["result"]["path"]
21
+ s3_res = upload_s3(path,relative_path)
22
+ if s3_res
23
+ Cnvrg::API.request(@base_resource + "update_s3", 'POST', { path:path,commit_id:upload_resp["result"]["commit_id"],
24
+ blob_id:upload_resp["result"]["blob_id"]})
25
+ return true
26
+ end
27
+ end
28
+ return false
29
+ end
30
+ def upload_s3(url,file)
31
+ url = URI.parse(url)
32
+ mime_type = MimeMagic.by_path(file)
33
+ content_type = !mime_type.nil? ? mime_type.type : ""
34
+ file = File.open(file, "rb")
35
+ body = file.read
36
+ begin
37
+ Net::HTTP.start(url.host) do |http|
38
+ http.send_request("PUT", url.request_uri, body, {
39
+ "content-type" => content_type,
40
+ })
41
+ end
42
+ return true
43
+ rescue Interrupt
44
+ return false
45
+ rescue => e
46
+ return false
47
+ end
48
+ end
49
+ def upload_url(file_path)
50
+ response = Cnvrg::API.request(@base_resource + "upload_url", 'POST', { file_s3_path: file_path})
51
+ if Cnvrg::CLI.is_response_success(response, false)
52
+ return response
53
+ else
54
+ return nil
55
+ end
56
+
57
+ end
58
+ def delete_file(absolute_path, relative_path, commit_sha1)
59
+ response = Cnvrg::API.request(@base_resource + "delete_file", 'DELETE',{ absolute_path: absolute_path, relative_path: relative_path, commit_sha1: commit_sha1 })
60
+ return Cnvrg::CLI.is_response_success(response, false)
61
+ end
62
+
63
+ def delete_dir(absolute_path, relative_path, commit_sha1)
64
+ response = Cnvrg::API.request(@base_resource + "delete_dir", 'DELETE', { absolute_path: absolute_path, relative_path: relative_path, commit_sha1: commit_sha1 })
65
+ return Cnvrg::CLI.is_response_success(response, false)
66
+ end
67
+
68
+ def create_dir(absolute_path, relative_path, commit_sha1)
69
+ response = Cnvrg::API.request(@base_resource + "create_dir", 'POST',{ absolute_path: absolute_path, relative_path: relative_path, commit_sha1: commit_sha1 })
70
+ return Cnvrg::CLI.is_response_success(response, false)
71
+ end
72
+
73
+ def download_file(absolute_path, relative_path, project_home, conflict=false)
74
+ res = Cnvrg::API.request(@base_resource + "download_file", 'POST', { absolute_path: absolute_path, relative_path: relative_path })
75
+ Cnvrg::CLI.is_response_success(res, false)
76
+ if res["result"]
77
+ res = res["result"]
78
+ return false if res["link"].empty? or res["filename"].empty?
79
+ filename = res["filename"]
80
+ file_location = absolute_path.gsub(/#{filename}\/?$/, "")
81
+
82
+ FileUtils.mkdir_p project_home + "/" + file_location
83
+ filename += ".conflict" if conflict
84
+
85
+ File.open("#{project_home}/#{file_location}/#{filename}", "wb") do |file|
86
+ file.write open(res["link"]).read
87
+ end
88
+ else
89
+ return false
90
+ end
91
+ return true
92
+ end
93
+
94
+ def download_dir(absolute_path, relative_path, project_home)
95
+ FileUtils.mkdir_p("#{project_home}/#{absolute_path}")
96
+ end
97
+
98
+ def start_commit
99
+
100
+ response = Cnvrg::API.request("#{base_resource}/commit/start", 'POST', { project_slug: @project_slug,
101
+ username: @owner} )
102
+ Cnvrg::CLI.is_response_success(response)
103
+ return response
104
+ end
105
+
106
+ def end_commit(commit_sha1)
107
+ response = Cnvrg::API.request("#{base_resource}/commit/end", 'POST', { commit_sha1: commit_sha1 } )
108
+ return response
109
+ end
110
+ def rollback_commit(commit_sha1)
111
+ response = Cnvrg::API.request("#{base_resource}/commit/rollback", 'POST', { commit_sha1: commit_sha1 } )
112
+ Cnvrg::CLI.is_response_success(response, false)
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,90 @@
1
+ module Cnvrg
2
+ module Helpers
3
+
4
+ extend self
5
+ def checkmark
6
+ checkmark = "\u2713"
7
+ return checkmark.encode('utf-8')
8
+ end
9
+
10
+ def remote_url
11
+ "https://cnvrg.io"
12
+ end
13
+
14
+ def windows?
15
+ !!(RUBY_PLATFORM =~ /mswin32|mingw32/)
16
+ end
17
+
18
+ def mac?
19
+ !!(RUBY_PLATFORM =~ /-darwin\d/)
20
+ end
21
+
22
+ def linux?
23
+ not mac? and not windows?
24
+ end
25
+
26
+ def cnvrgignore_content
27
+ %{
28
+ # cnvrg ignore: Ignore the following directories and files
29
+ # for example:
30
+ # some_dir/
31
+ # some_file.txt
32
+ }.strip
33
+ end
34
+
35
+ def readme_content
36
+ %{
37
+ # README
38
+
39
+ This README would normally contain some context and description about the project.
40
+
41
+ Things you may want to cover:
42
+
43
+ * Data description
44
+
45
+ * Benchmark and measurement guidelines
46
+
47
+ * Used algorithms
48
+
49
+ * Scores
50
+
51
+ * Configurations
52
+
53
+ * Requirements
54
+
55
+ * How to run the experiments
56
+
57
+ * ...}.strip
58
+ end
59
+
60
+ def netrc_domain
61
+ "cnvrg.io"
62
+ end
63
+
64
+ def look_for_in_path(path, name)
65
+ url_split = path.split("/")
66
+ url_split.each_with_index do |u, i|
67
+ if u == name
68
+ return i
69
+ end
70
+ end
71
+ return -1
72
+ end
73
+
74
+ # cpu
75
+
76
+ def cpu_time
77
+ Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :microsecond)
78
+ end
79
+
80
+ def wall_time
81
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :microsecond)
82
+ end
83
+
84
+ # memory
85
+ #
86
+ def get_mem(pid)
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,332 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'commander/import'
5
+ require "open4"
6
+ require 'netrc'
7
+ require 'net/http'
8
+ require 'uri'
9
+ require 'json'
10
+ require 'yaml'
11
+ require 'digest' # sha1
12
+
13
+ # DEV VERSION
14
+ #require 'pry'
15
+ #
16
+
17
+
18
+ program :name, 'cnvrg'
19
+ program :version, '0.0.1'
20
+ program :description, 'cnvrg\'s cli for running scripts'
21
+
22
+ command :idx do |c|
23
+ c.action do |args,options|
24
+ generate_idx
25
+ end
26
+ end
27
+ command :status do |c|
28
+ c.action do |args,options|
29
+ status
30
+ end
31
+ end
32
+ command :run do |c|
33
+ c.syntax = 'cnvrg run script [options]'
34
+ c.summary = 'monitor run of script'
35
+ c.description = 'Runs scripts and sending notification when finished'
36
+ c.option '--script_args script arguments', String, 'script arguments if exist'
37
+ c.option '--sms', String, 'set sms if you want to be notify by sms when the run is over'
38
+ c.option '--email', String, 'set email if you want to be notify by email when the run is over'
39
+ c.option '--silent', String, 'set silent if you want to run script in non-blocking'
40
+ c.action do |args, options|
41
+ is_exist = verify_auth_exist()
42
+ unless is_exist
43
+ puts("You have to be logged in to continue. Please login.\n")
44
+ loged_in = login_process()
45
+ if !loged_in
46
+ puts("Error: Couldn't logged you in, please run cnvr login separately")
47
+ end
48
+ end
49
+
50
+ silent = ''
51
+ if options.silent
52
+ silent = '&'
53
+ end
54
+ script = args[0]
55
+ if args.length != 1
56
+ puts "Error: only one script should be listed to run"
57
+ found = false
58
+ args.each do |arg|
59
+ ans = agree("should I run #{arg}?")
60
+ if ans
61
+ found = true
62
+ script = arg
63
+ break
64
+ end
65
+ end
66
+ if not found
67
+ exit(0)
68
+ end
69
+ end
70
+ #check if file exist
71
+ exist = File.file?(script)
72
+ if not exist
73
+ puts "Error: Can't find #{script}, try using the full path"
74
+ exit(0)
75
+ end
76
+ puts "Running #{script} with args: #{options.script_args}"
77
+ body = {try: 'yay'}.to_json
78
+ puts run(true,body)
79
+ pid, stdin, stdout, stderr = Open4::popen4 "sh"
80
+ stdin.puts "./#{script} #{options.script_args}"
81
+ stdin.close
82
+
83
+ ignored, status = Process::waitpid2 pid
84
+
85
+ #try to run
86
+ if stderr.read.strip.include? "Permission denied"
87
+ ans = agree("Your script #{script} isn't executable, should I make it executable?")
88
+ if ans
89
+ puts "Making #{script} executable"
90
+ run_result = %x(chmod +x ./#{script} 2>&1)
91
+ if run_result.include? "Operation not permitted"
92
+ puts "Can't make script executable,you should first run sudo chmod +x #{script}"
93
+ exit(0)
94
+ end
95
+ puts "Running again #{script} with args: #{options.script_args}"
96
+
97
+ pid, stdin, stdout, stderr = Open4::popen4 "sh"
98
+ stdin.puts "./#{script} #{options.script_args}"
99
+ stdin.close
100
+ ignored, status = Process::waitpid2 pid
101
+
102
+ if !stderr.read.strip.empty?
103
+ puts "Error: #{stderr.read.strip}"
104
+ end
105
+ end
106
+ end
107
+ puts stdout.read.strip
108
+ # send results to the server
109
+ puts "Finished running with status #{status.exitstatus}"
110
+ puts run(false, body)
111
+
112
+ end
113
+ end
114
+
115
+ command :new do |c|
116
+ c.syntax = "cnvrg new project-name"
117
+ c.summary = "Create a new data science project"
118
+
119
+ c.action do |args, options|
120
+ is_exist = verify_auth_exist()
121
+ unless is_exist
122
+ "You have to login"
123
+ else
124
+ if args[0].to_s.size == 0
125
+ exit(0)
126
+ else
127
+ new(args[0])
128
+ link_dir(args[0], "")
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ command :login do |c|
135
+ c.syntax = 'cnvrg login'
136
+ c.summary = 'login to cnvrg app'
137
+ c.description = 'Login to the CNVRG system'
138
+ c.option '--reset', String, 'set reset if you want to change current login credentials'
139
+ c.action do |args, options|
140
+ n = Netrc.read
141
+ user, pass = n["cnvrg.io"]
142
+ if user and pass
143
+ relogin = agree("You are already authenticated with email: #{user}, do you want to login again? (This will delete you're current login credentials")
144
+ if !relogin
145
+ exit(0)
146
+ end
147
+ end
148
+ if options.reset
149
+ n["cnvrg.io"] = "", ""
150
+
151
+ end
152
+ login_process()
153
+
154
+
155
+ end
156
+ end
157
+
158
+ def login_process()
159
+ n = Netrc.read
160
+
161
+ email = ask("Please enter your email")
162
+ email_regex = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
163
+ is_valid = email_regex.match(email)
164
+ while !is_valid do
165
+ email = ask("Please enter a valid email address:")
166
+ is_valid = email_regex.match(email)
167
+ end
168
+
169
+ password = ask("Please enter your password: ") { |q| q.echo = false }
170
+ #send API to login
171
+ token = sign_in(email, password)
172
+ count = 0
173
+ while token.nil? and count<3 do
174
+ do_retry = agree("Wrong email or password, try again?")
175
+ if do_retry
176
+ count +=1
177
+ email = ask("Please enter your email")
178
+ password = ask("Please enter your password: ") { |q| q.echo = false }
179
+ token = sign_in(email, password)
180
+ end
181
+ end
182
+ if token.nil?
183
+ puts "Error: Too many sign in retries"
184
+ exit(0)
185
+ else
186
+
187
+
188
+ n.new_item_prefix = "# This entry was added automatically by CNVRG\n"
189
+ n["cnvrg.io"] = email, token
190
+ n.save
191
+ puts "Great, you're in."
192
+ return true
193
+ end
194
+ end
195
+
196
+ def sign_in(email, password)
197
+ url = URI.parse("http://localhost:3000/api/v1/users/sign_in")
198
+
199
+ req = Net::HTTP::Post.new(url.path)
200
+ req.add_field("EMAIL", email)
201
+ req.add_field("PASSWORD", password)
202
+
203
+ response = Net::HTTP.new(url.host, url.port).start do |http|
204
+ http.request(req)
205
+ end
206
+
207
+ result = JSON.parse(response.body)
208
+ if result["status"] == 200
209
+ return result["token"]
210
+ else
211
+ return nil
212
+ end
213
+ end
214
+
215
+ def verify_auth_exist
216
+ n = Netrc.read
217
+ user, pass = n["cnvrg.io"]
218
+ if user.nil? or pass.nil?
219
+ puts "Please login first, using \"cnvrg login\" command"
220
+ return false
221
+ end
222
+ return true
223
+ end
224
+
225
+ def get_logged_token
226
+ n = Netrc.read
227
+ user, token = n["cnvrg.io"]
228
+ return token
229
+
230
+ end
231
+ def run(is_start, body)
232
+ token = get_logged_token()
233
+ if is_start
234
+ url = URI.parse("http://localhost:3000/api/v1/cli/start_run")
235
+ else
236
+ url = URI.parse("http://localhost:3000/api/v1/cli/end_run")
237
+ end
238
+
239
+
240
+ req = Net::HTTP::Post.new(url.path)
241
+ req.add_field("AUTH_TOKEN", token)
242
+ req.body = body
243
+ response = Net::HTTP.new(url.host, url.port).start do |http|
244
+ http.request(req)
245
+ end
246
+
247
+ result = JSON.parse(response.body)
248
+ puts result
249
+ end
250
+
251
+ def new(project_name)
252
+ begin
253
+ `mkdir -p #{project_name} #{project_name}/data #{project_name}/models #{project_name}/notebooks #{project_name}/src #{project_name}/src/data #{project_name}/src/features #{project_name}/src/models #{project_name}/src/visualizations #{project_name}/.cnvrg`
254
+ `touch #{project_name}/README.md`
255
+ `touch #{project_name}/.cnvrgignore`
256
+ rescue
257
+ "Error"
258
+ end
259
+ end
260
+
261
+ def link_dir(project_name, user, host="cnvrg.io")
262
+ `touch #{project_name}/.cnvrg/project`
263
+ `echo "owner: #{user}\nproject_slug: #{project_name}\nhost: #{host}" >> #{project_name}/.cnvrg/project`
264
+ end
265
+
266
+ def download
267
+
268
+ status_output = status
269
+ downloadables = status_output["updated_on_server"].merge(status_output["deleted"])
270
+
271
+
272
+ downloadables.each do |d|
273
+ if d[-1] == "/"
274
+ # make dir
275
+ else
276
+ files << #download(d)
277
+ end
278
+ end
279
+
280
+ def upload
281
+
282
+ end
283
+
284
+ def generate_idx
285
+
286
+ idx = Hash.new(0)
287
+ list = Dir['**/**']
288
+
289
+ # remove files that are in CNVRGIGNORE
290
+ # list.select { |x| ! cnvrgignore.include? x }
291
+
292
+ list.each do |e|
293
+ if File.directory? e
294
+ idx[e+"/"] = nil
295
+ else
296
+ idx[e] = { sha1: Digest::SHA1.hexdigest(File.read(e)),
297
+ commit_time: nil }
298
+ end
299
+ end
300
+
301
+ File.open("hello/.cnvrg/idx.yml", 'w') { |f| f.write idx.to_yaml }
302
+
303
+
304
+ end
305
+
306
+ def status
307
+ url = URI.parse("http://localhost:3000/api/v1/users/yochze/projects/porject/status")
308
+ token = get_logged_token()
309
+ load_idx = YAML.load(File.read("hello/.cnvrg/idx.yml"))
310
+ req = Net::HTTP::Get.new(url, 'Content-Type' => 'application/json')
311
+ req.add_field("AUTH_TOKEN", token)
312
+ req.body = { snapshot: load_idx }.to_json
313
+ response = Net::HTTP.new(url.host, url.port).start do |http|
314
+ http.request(req)
315
+ end
316
+
317
+ result = JSON.parse(response.body)
318
+
319
+ result["status"]["added"].each do |a|
320
+ puts "A:\t#{a}"
321
+ end
322
+
323
+ result["status"]["updated_on_server"].each do |a|
324
+ puts "M:\t#{a}"
325
+ end
326
+
327
+ result["status"]["deleted"].each do |a|
328
+ puts "D:\t#{a}"
329
+ end
330
+
331
+ return result["status"]
332
+ end