cnvrg 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/cnvrg +5 -0
- data/cnvrg.gemspec +27 -0
- data/lib/cnvrg.rb +10 -0
- data/lib/cnvrg/api.rb +106 -0
- data/lib/cnvrg/auth.rb +74 -0
- data/lib/cnvrg/cli.rb +574 -0
- data/lib/cnvrg/experiment.rb +26 -0
- data/lib/cnvrg/files.rb +115 -0
- data/lib/cnvrg/helpers.rb +90 -0
- data/lib/cnvrg/old_cli.rb +332 -0
- data/lib/cnvrg/project.rb +237 -0
- data/lib/cnvrg/version.rb +3 -0
- metadata +165 -0
@@ -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
|
data/lib/cnvrg/files.rb
ADDED
@@ -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
|