transcriptic 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/bin/transcriptic +2 -4
  3. data/lib/thor/monkies.rb +3 -0
  4. data/lib/thor/monkies/shell.rb +3 -0
  5. data/lib/transcriptic.rb +86 -2
  6. data/lib/transcriptic/auth.rb +2 -63
  7. data/lib/transcriptic/base_generator.rb +25 -0
  8. data/lib/transcriptic/cli.rb +199 -8
  9. data/lib/transcriptic/client.rb +45 -38
  10. data/lib/transcriptic/commands/project.rb +37 -0
  11. data/lib/transcriptic/core_ext.rb +3 -0
  12. data/lib/transcriptic/core_ext/file.rb +7 -0
  13. data/lib/transcriptic/core_ext/file_utils.rb +15 -0
  14. data/lib/transcriptic/core_ext/pathname.rb +13 -0
  15. data/lib/transcriptic/core_ext/string.rb +8 -0
  16. data/lib/transcriptic/dependencies_generator.rb +13 -0
  17. data/lib/transcriptic/errors.rb +32 -0
  18. data/lib/transcriptic/labfile.rb +73 -0
  19. data/lib/transcriptic/project_generator.rb +56 -0
  20. data/lib/transcriptic/sbt.rb +58 -0
  21. data/lib/transcriptic/templates/LICENSE.erb +20 -0
  22. data/lib/transcriptic/templates/Labfile.erb +12 -0
  23. data/lib/transcriptic/templates/README.erb +3 -0
  24. data/lib/transcriptic/templates/app/Main.erb +11 -0
  25. data/lib/transcriptic/templates/project/Build.erb +59 -0
  26. data/lib/transcriptic/templates/project/Dependencies.erb +10 -0
  27. data/lib/transcriptic/templates/project/build.properties +1 -0
  28. data/lib/transcriptic/templates/project/plugins.sbt +5 -0
  29. data/lib/transcriptic/templates/sbt +1 -0
  30. data/lib/transcriptic/{helpers.rb → ui.rb} +124 -109
  31. data/lib/transcriptic/version.rb +2 -1
  32. data/lib/vendor/{transcriptic/okjson.rb → okjson.rb} +0 -0
  33. metadata +203 -46
  34. data/lib/transcriptic/command.rb +0 -233
  35. data/lib/transcriptic/command/base.rb +0 -157
  36. data/lib/transcriptic/command/console.rb +0 -10
  37. data/lib/transcriptic/command/data.rb +0 -29
  38. data/lib/transcriptic/command/help.rb +0 -124
  39. data/lib/transcriptic/command/login.rb +0 -35
  40. data/lib/transcriptic/command/run.rb +0 -108
@@ -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
- # Get a list of stacks available to the app, with the current one marked.
45
- def list_stacks(app_name, options={})
46
- include_deprecated = options.delete(:include_deprecated) || false
34
+ def list_projects
35
+ json_decode get("/api/projects.json").to_s
36
+ end
47
37
 
48
- json_decode resource("/apps/#{app_name}/stack").get(
49
- :params => { :include_deprecated => include_deprecated },
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}/services",
79
+ "/api/runs/#{@app}/confirm",
84
80
  command,
85
- :content_type => 'text/plain'
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
- json_decode post("/api/runs", File.open(fd).read, { 'Content-Type' => 'application/zip; charset=UTF-8' }).to_s
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,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/core_ext/*.rb"].sort.each do |path|
2
+ require_relative "core_ext/#{File.basename(path, '.rb')}"
3
+ end
@@ -0,0 +1,7 @@
1
+ class File
2
+ class << self
3
+ def transcriptic_project?(path)
4
+ File.exists?(File.join(path, 'Labfile'))
5
+ end
6
+ end
7
+ 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
+ class Pathname
2
+ def transcriptic_project?
3
+ self.join('Labfile').exist?
4
+ end
5
+
6
+ def transcriptic_project_root
7
+ self.ascend do |potential_root|
8
+ if potential_root.transcriptic_project?
9
+ return potential_root
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ class String
2
+ def prepend_each(separator, value)
3
+ lines(separator).collect { |x| value + x }.join
4
+ end
5
+ def shellescape
6
+ empty? ? "''" : gsub(/([^A-Za-z0-9_\-.,:\/@\n])/n, '\\\\\\1').gsub(/\n/, "'\n'")
7
+ end
8
+ 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