transcriptic 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/transcriptic +2 -4
- data/lib/thor/monkies.rb +3 -0
- data/lib/thor/monkies/shell.rb +3 -0
- data/lib/transcriptic.rb +86 -2
- data/lib/transcriptic/auth.rb +2 -63
- data/lib/transcriptic/base_generator.rb +25 -0
- data/lib/transcriptic/cli.rb +199 -8
- data/lib/transcriptic/client.rb +45 -38
- data/lib/transcriptic/commands/project.rb +37 -0
- data/lib/transcriptic/core_ext.rb +3 -0
- data/lib/transcriptic/core_ext/file.rb +7 -0
- data/lib/transcriptic/core_ext/file_utils.rb +15 -0
- data/lib/transcriptic/core_ext/pathname.rb +13 -0
- data/lib/transcriptic/core_ext/string.rb +8 -0
- data/lib/transcriptic/dependencies_generator.rb +13 -0
- data/lib/transcriptic/errors.rb +32 -0
- data/lib/transcriptic/labfile.rb +73 -0
- data/lib/transcriptic/project_generator.rb +56 -0
- data/lib/transcriptic/sbt.rb +58 -0
- data/lib/transcriptic/templates/LICENSE.erb +20 -0
- data/lib/transcriptic/templates/Labfile.erb +12 -0
- data/lib/transcriptic/templates/README.erb +3 -0
- data/lib/transcriptic/templates/app/Main.erb +11 -0
- data/lib/transcriptic/templates/project/Build.erb +59 -0
- data/lib/transcriptic/templates/project/Dependencies.erb +10 -0
- data/lib/transcriptic/templates/project/build.properties +1 -0
- data/lib/transcriptic/templates/project/plugins.sbt +5 -0
- data/lib/transcriptic/templates/sbt +1 -0
- data/lib/transcriptic/{helpers.rb → ui.rb} +124 -109
- data/lib/transcriptic/version.rb +2 -1
- data/lib/vendor/{transcriptic/okjson.rb → okjson.rb} +0 -0
- metadata +203 -46
- data/lib/transcriptic/command.rb +0 -233
- data/lib/transcriptic/command/base.rb +0 -157
- data/lib/transcriptic/command/console.rb +0 -10
- data/lib/transcriptic/command/data.rb +0 -29
- data/lib/transcriptic/command/help.rb +0 -124
- data/lib/transcriptic/command/login.rb +0 -35
- data/lib/transcriptic/command/run.rb +0 -108
data/lib/transcriptic/client.rb
CHANGED
@@ -1,11 +1,3 @@
|
|
1
|
-
require 'rexml/document'
|
2
|
-
require 'rest-client'
|
3
|
-
require 'uri'
|
4
|
-
require 'time'
|
5
|
-
require 'transcriptic/auth'
|
6
|
-
require 'transcriptic/helpers'
|
7
|
-
require 'transcriptic/version'
|
8
|
-
|
9
1
|
# A Ruby class to call the Transcriptic REST API. You might use this if you want to
|
10
2
|
# manage your Transcriptic apps from within a Ruby program, such as Capistrano.
|
11
3
|
#
|
@@ -16,9 +8,7 @@ require 'transcriptic/version'
|
|
16
8
|
# transcriptic.create('myapp')
|
17
9
|
#
|
18
10
|
class Transcriptic::Client
|
19
|
-
|
20
|
-
include Transcriptic::Helpers
|
21
|
-
extend Transcriptic::Helpers
|
11
|
+
include Transcriptic::UI
|
22
12
|
|
23
13
|
def self.version
|
24
14
|
Transcriptic::VERSION
|
@@ -41,14 +31,12 @@ class Transcriptic::Client
|
|
41
31
|
@host = host
|
42
32
|
end
|
43
33
|
|
44
|
-
|
45
|
-
|
46
|
-
|
34
|
+
def list_projects
|
35
|
+
json_decode get("/api/projects.json").to_s
|
36
|
+
end
|
47
37
|
|
48
|
-
|
49
|
-
|
50
|
-
:accept => 'application/json'
|
51
|
-
).to_s
|
38
|
+
def project_info(name)
|
39
|
+
json_decode get("/api/projects/#{name}.json").to_s
|
52
40
|
end
|
53
41
|
|
54
42
|
class ProtocolException < RuntimeError; end
|
@@ -57,16 +45,24 @@ class Transcriptic::Client
|
|
57
45
|
def list
|
58
46
|
json_decode get('/api/runs.json').to_s
|
59
47
|
end
|
60
|
-
|
48
|
+
|
49
|
+
def list_datasets(run_id = nil, project_id = nil)
|
50
|
+
json_decode get("/api/datasets.json?run_id=#{run_id}&project_id=#{project_id}").to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_dataset_info(dataset_id)
|
54
|
+
json_decode get("/api/datasets/#{dataset_id}").to_s
|
55
|
+
end
|
56
|
+
|
57
|
+
def delete_dataset(dataset_id)
|
58
|
+
json_decode delete("/api/datasets/#{dataset_id}").to_s
|
59
|
+
end
|
60
|
+
|
61
61
|
# Show info such as mode, custom domain, and collaborators on an app.
|
62
62
|
def info(name_or_domain)
|
63
63
|
name_or_domain = name_or_domain.gsub(/^(http:\/\/)?(www\.)?/, '')
|
64
64
|
end
|
65
65
|
|
66
|
-
def organizations
|
67
|
-
json_decode resource("/organizations").get(:accept => 'application/json').to_s
|
68
|
-
end
|
69
|
-
|
70
66
|
class Protocol
|
71
67
|
attr_accessor :attached, :upid
|
72
68
|
|
@@ -80,9 +76,9 @@ class Transcriptic::Client
|
|
80
76
|
def launch(command, attached=false)
|
81
77
|
@attached = attached
|
82
78
|
@response = @client.post(
|
83
|
-
"/runs/#{@app}/
|
79
|
+
"/api/runs/#{@app}/confirm",
|
84
80
|
command,
|
85
|
-
:content_type => '
|
81
|
+
:content_type => 'application/json'
|
86
82
|
)
|
87
83
|
@next_chunk = @response.to_s
|
88
84
|
@interval = 0
|
@@ -137,18 +133,29 @@ class Transcriptic::Client
|
|
137
133
|
json_decode get("/api/runs/#{run_id}").to_s
|
138
134
|
end
|
139
135
|
|
140
|
-
def create_run(fd)
|
141
|
-
|
136
|
+
def create_run(fd, project_id)
|
137
|
+
payload = {
|
138
|
+
'zipdata' => Base64.encode64(File.open(fd).read),
|
139
|
+
'project_id' => project_id
|
140
|
+
}
|
141
|
+
json_decode post("/api/runs", payload, { 'Content-Type' => 'application/zip; charset=UTF-8' }).to_s
|
142
|
+
end
|
143
|
+
|
144
|
+
def launch_run(run_id)
|
145
|
+
json_decode post("/api/runs/#{run_id}/confirm").to_s
|
142
146
|
end
|
143
147
|
|
144
|
-
# Get a Protocol instance to execute commands against.
|
145
148
|
def protocol(run_id, upid)
|
146
149
|
Protocol.new(self, run_id, upid)
|
147
150
|
end
|
148
151
|
|
149
152
|
def read_logs(run_id, options=[])
|
150
153
|
query = "&" + options.join("&") unless options.empty?
|
151
|
-
url = get("/api/runs/#{run_id}/logs?#{query}").to_s
|
154
|
+
url = get("/api/runs/#{run_id}/logs.json?#{query}").to_s
|
155
|
+
if 'not_found' == url
|
156
|
+
error "Run #{run_id} not found!"
|
157
|
+
end
|
158
|
+
|
152
159
|
uri = URI.parse(url);
|
153
160
|
http = Net::HTTP.new(uri.host, uri.port)
|
154
161
|
|
@@ -180,9 +187,9 @@ class Transcriptic::Client
|
|
180
187
|
|
181
188
|
##################
|
182
189
|
|
183
|
-
def resource(uri, options={})
|
190
|
+
def resource(uri, options={}, host=host)
|
184
191
|
RestClient.proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
|
185
|
-
resource = RestClient::Resource.new(realize_full_uri(uri), options)
|
192
|
+
resource = RestClient::Resource.new(realize_full_uri(uri, host), options)
|
186
193
|
resource
|
187
194
|
end
|
188
195
|
|
@@ -190,8 +197,8 @@ class Transcriptic::Client
|
|
190
197
|
process(:get, uri, extra_headers)
|
191
198
|
end
|
192
199
|
|
193
|
-
def post(uri, payload="", extra_headers={}) # :nodoc:
|
194
|
-
process(:post, uri, extra_headers, payload)
|
200
|
+
def post(uri, payload="", extra_headers={}, host=host) # :nodoc:
|
201
|
+
process(:post, uri, extra_headers, payload, host)
|
195
202
|
end
|
196
203
|
|
197
204
|
def put(uri, payload, extra_headers={}) # :nodoc:
|
@@ -202,19 +209,19 @@ class Transcriptic::Client
|
|
202
209
|
process(:delete, uri, extra_headers)
|
203
210
|
end
|
204
211
|
|
205
|
-
def process(method, uri, extra_headers={}, payload=nil)
|
212
|
+
def process(method, uri, extra_headers={}, payload=nil, host=host)
|
206
213
|
headers = transcriptic_headers.merge(extra_headers)
|
207
214
|
args = [method, payload, headers].compact
|
208
215
|
|
209
216
|
resource_options = default_resource_options_for_uri(uri)
|
210
217
|
|
211
218
|
begin
|
212
|
-
response = resource(uri, resource_options).send(*args)
|
219
|
+
response = resource(uri, resource_options, host).send(*args)
|
213
220
|
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketError
|
214
|
-
host = URI.parse(realize_full_uri(uri)).host
|
221
|
+
host = URI.parse(realize_full_uri(uri, host)).host
|
215
222
|
error " ! Unable to connect to #{host}"
|
216
223
|
rescue RestClient::SSLCertificateNotVerified => ex
|
217
|
-
host = URI.parse(realize_full_uri(uri)).host
|
224
|
+
host = URI.parse(realize_full_uri(uri, host)).host
|
218
225
|
error "WARNING: Unable to verify SSL certificate for #{host}\nTo disable SSL verification, run with TRANSCRIPTIC_SSL_VERIFY=disable"
|
219
226
|
end
|
220
227
|
|
@@ -262,7 +269,7 @@ class Transcriptic::Client
|
|
262
269
|
|
263
270
|
private
|
264
271
|
|
265
|
-
def realize_full_uri(given)
|
272
|
+
def realize_full_uri(given, host=host)
|
266
273
|
full_host = (host =~ /^http/) ? host : "https://www.#{host}"
|
267
274
|
host = URI.parse(full_host)
|
268
275
|
uri = URI.parse(given)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Transcriptic
|
2
|
+
module CLI
|
3
|
+
|
4
|
+
# manage projects
|
5
|
+
#
|
6
|
+
class Project < Thor
|
7
|
+
|
8
|
+
desc "index", "upload FILENAME or DIRECTORY and launch it"
|
9
|
+
def index
|
10
|
+
if args.empty?
|
11
|
+
error("Usage: transcriptic project NAME")
|
12
|
+
end
|
13
|
+
name = args.shift
|
14
|
+
data = transcriptic.project_info(name)
|
15
|
+
display "Project \"#{data["name"]}\":"
|
16
|
+
display " shortname: #{data["codename"]}"
|
17
|
+
display " active runs: #{data["active_runs"].length}"
|
18
|
+
display " archived runs: #{data["completed_runs"].length}"
|
19
|
+
display " datasets created: #{data["datasets"].length}"
|
20
|
+
display " created at: #{data["created_at"]}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# transcriptic project:list
|
24
|
+
desc "list", "list the projects the user can see"
|
25
|
+
def list
|
26
|
+
ret = transcriptic.list_projects
|
27
|
+
if ret.empty?
|
28
|
+
error("No projects for #{transcriptic.user}")
|
29
|
+
return
|
30
|
+
end
|
31
|
+
ret.each do |project|
|
32
|
+
display "\t" + project["codename"] + "\t\t" + project["name"]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module FileUtils
|
4
|
+
class << self
|
5
|
+
# Override mv to avoid several bugs (Errno::EACCES in Windows, Errno::ENOENT
|
6
|
+
# with relative softlinks on Linux), by forcing to copy and delete instead
|
7
|
+
#
|
8
|
+
# @see {FileUtils::mv}
|
9
|
+
# @see {safe_mv}
|
10
|
+
def mv(src, dest, options = {})
|
11
|
+
FileUtils.cp_r(src, dest, options)
|
12
|
+
FileUtils.rm_rf(src)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'transcriptic/base_generator'
|
2
|
+
|
3
|
+
module Transcriptic
|
4
|
+
class DependenciesGenerator < BaseGenerator
|
5
|
+
include Transcriptic::UI
|
6
|
+
|
7
|
+
argument :dependencies
|
8
|
+
|
9
|
+
def generate
|
10
|
+
template 'project/Dependencies.erb', target.join('project/Dependencies.scala'), force: true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Transcriptic
|
2
|
+
class TranscripticError < StandardError
|
3
|
+
class << self
|
4
|
+
def status_code(code)
|
5
|
+
define_method(:status_code) { code }
|
6
|
+
define_singleton_method(:status_code) { code }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
alias_method :message, :to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
class LabfileReadError < TranscripticError
|
13
|
+
def initialize(original_error)
|
14
|
+
@original_error = original_error
|
15
|
+
end
|
16
|
+
|
17
|
+
status_code(113)
|
18
|
+
|
19
|
+
def status_code
|
20
|
+
@original_error.respond_to?(:status_code) ? @original_error.status_code : 113
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
[
|
25
|
+
"An error occurred while reading the Labfile:",
|
26
|
+
"",
|
27
|
+
" " + @original_error.to_s.split("\n").map(&:strip).join("\n "),
|
28
|
+
].join("\n")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
#require 'transcriptic/downloader'
|
2
|
+
|
3
|
+
module Transcriptic
|
4
|
+
class Labfile
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def from_file(file)
|
9
|
+
content = File.read(file)
|
10
|
+
object = new(file)
|
11
|
+
object.load(content)
|
12
|
+
rescue Errno::ENOENT => e
|
13
|
+
raise FileNotFound, "No Labfile found at: #{file}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(path)
|
18
|
+
@filepath = path
|
19
|
+
@options = Hash.new
|
20
|
+
@dependencies = []
|
21
|
+
end
|
22
|
+
|
23
|
+
def load(content)
|
24
|
+
begin
|
25
|
+
instance_eval(content)
|
26
|
+
rescue => e
|
27
|
+
puts e
|
28
|
+
raise LabfileReadError.new(e)
|
29
|
+
end
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def sha
|
34
|
+
@sha ||= Digest::SHA1.hexdigest File.read(filepath.to_s)
|
35
|
+
end
|
36
|
+
|
37
|
+
def options
|
38
|
+
@options
|
39
|
+
end
|
40
|
+
|
41
|
+
def name(name = nil)
|
42
|
+
@options[:name] = name
|
43
|
+
end
|
44
|
+
|
45
|
+
def author(name)
|
46
|
+
@options[:author] = name
|
47
|
+
end
|
48
|
+
|
49
|
+
def email(email)
|
50
|
+
@options[:email] = email
|
51
|
+
end
|
52
|
+
|
53
|
+
def version(arg)
|
54
|
+
@options[:version] = arg
|
55
|
+
end
|
56
|
+
|
57
|
+
def description(desc)
|
58
|
+
@options[:description] = desc
|
59
|
+
end
|
60
|
+
|
61
|
+
def dependency(group, name, version)
|
62
|
+
@dependencies << {
|
63
|
+
group: group,
|
64
|
+
name: name,
|
65
|
+
version: version
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def dependencies
|
70
|
+
@dependencies
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'transcriptic/base_generator'
|
2
|
+
|
3
|
+
module Transcriptic
|
4
|
+
class ProjectGenerator < BaseGenerator
|
5
|
+
|
6
|
+
argument :name
|
7
|
+
class_option :package,
|
8
|
+
type: :string,
|
9
|
+
default: "org.autoprotocol.unclaimed"
|
10
|
+
class_option :author,
|
11
|
+
type: :string,
|
12
|
+
default: "John Appleseed"
|
13
|
+
class_option :email,
|
14
|
+
type: :string,
|
15
|
+
default: "author@example.edu"
|
16
|
+
class_option :description,
|
17
|
+
type: :string,
|
18
|
+
default: false
|
19
|
+
|
20
|
+
def generate
|
21
|
+
empty_directory target.join('app')
|
22
|
+
empty_directory target.join('project')
|
23
|
+
empty_directory target.join('lib')
|
24
|
+
|
25
|
+
template 'app/Main.erb', target.join('app/Main.scala')
|
26
|
+
template 'project/Build.erb', target.join('project/Build.scala')
|
27
|
+
copy_file 'project/build.properties', target.join('project/build.properties')
|
28
|
+
copy_file 'project/plugins.sbt', target.join('project/plugins.sbt')
|
29
|
+
template 'LICENSE.erb', target.join('LICENSE')
|
30
|
+
template 'Labfile.erb', target.join('Labfile')
|
31
|
+
template 'README.erb', target.join('README.md')
|
32
|
+
|
33
|
+
Transcriptic::DependenciesGenerator.new([File.join(Dir.pwd, name), []], options).invoke_all
|
34
|
+
end
|
35
|
+
|
36
|
+
def description
|
37
|
+
options[:description]
|
38
|
+
end
|
39
|
+
|
40
|
+
def package
|
41
|
+
options[:package]
|
42
|
+
end
|
43
|
+
|
44
|
+
def author
|
45
|
+
options[:author]
|
46
|
+
end
|
47
|
+
|
48
|
+
def email
|
49
|
+
options[:email]
|
50
|
+
end
|
51
|
+
|
52
|
+
def copyright_year
|
53
|
+
Time.now.year
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Transcriptic
|
2
|
+
class SBT
|
3
|
+
class << self
|
4
|
+
include Transcriptic::UI
|
5
|
+
|
6
|
+
def compile
|
7
|
+
ensure_installed
|
8
|
+
sbt("package")
|
9
|
+
end
|
10
|
+
|
11
|
+
def stage
|
12
|
+
ensure_installed
|
13
|
+
sbt("stage")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def ensure_installed
|
18
|
+
stat = `which sbt`
|
19
|
+
if stat.empty?
|
20
|
+
output_with_arrow "Downloading sbt..."
|
21
|
+
Transcriptic::SBT::Installer.new(["/usr/local"], {}).invoke_all
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def sbt(action)
|
26
|
+
base = Transcriptic.find_labfile.dirname
|
27
|
+
output_with_arrow "Detected Scala sources in app..."
|
28
|
+
output_with_arrow "Compiling..."
|
29
|
+
display
|
30
|
+
|
31
|
+
code = IO.popen("sbt #{action}") do |stream|
|
32
|
+
stream.each do |line|
|
33
|
+
output_with_indent line
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
display
|
38
|
+
|
39
|
+
if 0 == $?
|
40
|
+
output_with_arrow "Compilation succeeded."
|
41
|
+
true
|
42
|
+
else
|
43
|
+
output_with_arrow "Errors occurred!"
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Installer < BaseGenerator
|
50
|
+
def install
|
51
|
+
get "http://repo.typesafe.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch/0.12.3/sbt-launch.jar",
|
52
|
+
target.join("sbt/sbt-launch.jar")
|
53
|
+
copy_file 'sbt', target.join('bin/sbt')
|
54
|
+
chmod target.join('bin/sbt'), 0755
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|