module Transcriptic module CLI class Base < Thor include Transcriptic::UI class << self def dispatch(meth, given_args, given_opts, config) unless (given_args & ['-h', '--help']).empty? if given_args.length == 1 # transcriptic --help super else command = given_args.first super(meth, ['help', command].compact, nil, config) end else super end end end def initialize(*args) super(*args) Transcriptic.logger.level = ::Logger::INFO if @options[:debug] Transcriptic.logger.level = ::Logger::DEBUG end if @options[:quiet] Transcriptic.ui.mute! end @options = options.dup # unfreeze frozen options Hash from Thor end desc "login", "Log in with your Transcriptic account" def login Transcriptic::Auth.login say "Authentication successful." end desc "logout", "Clear local authentication credentials" def logout Transcriptic::Auth.logout say "Local credentials cleared." end desc "token", "Display your API token" def token say Transcriptic::Auth.api_key end desc "new NAME", "Generate a new project" method_option :package, type: :string, desc: "Package name (example: edu.stanford.professorname.projectname)" method_option :email, type: :string, desc: 'Email address of project author' method_option :author, type: :string, desc: 'Name of project author' method_option :description, type: :string, desc: 'Brief one-line description of the project' def new(name) Transcriptic::ProjectGenerator.new([File.join(Dir.pwd, name), name], options).invoke_all end desc "logs RUNID", "Get log data from a run" def logs(run_id) transcriptic.read_logs(run_id) end desc "status RUNID", "Show status for a given run ID" def status(run_id) ret = transcriptic.status(run_id) if ret.nil? error "#{run_id} not found for #{transcriptic.user}" end say(ret.inspect) end desc "list", "List your in-flight run IDs" def list ret = transcriptic.list if ret.empty? say "No runs for #{transcriptic.user}" return end say("Runs:") ret.each do |run| say " #{run.name}" end end desc "lookup QUERY", "Search for resources" long_desc <<-LONGDESC Search your organization's resource library as well as all public resources (i.e., commercial reagents). Useful \x5 for looking up resource IDs of the format VENDOR/SKU as required for use in protocols. Example: transcriptic lookup phusion \x5===> NEB/M0530 Phusion High-Fidelity DNA Polymerase \x5===> NEB/M0535 Phusion Hot Start Flex DNA Polymerase \x5===> NEB/B0519 Phusion GC Buffer \x5===> NEB/B0518 Phusion HF Buffer LONGDESC method_option :limit, type: :numeric, desc: "Maximum number of results to return" def lookup(term) ret = transcriptic.search_resources(term) ret["results"].each do |result| output_with_arrow "#{result[:resource_id]}: #{result[:name]}" end end desc "update", "Update the project's dependencies" def update require_labfile! output_with_arrow "Updating dependencies..." labfile = Transcriptic::Labfile.from_file(Transcriptic.find_labfile) Transcriptic::DependenciesGenerator.new([Dir.pwd, labfile.dependencies], options).invoke_all end desc "compile", "Compile the project" def compile require_labfile! update Transcriptic::SBT.compile end desc "analyze OBJECTPATH", "Analyze a protocol. Object path is of the form edu.foo.bar where bar is the name of your Protocol object." method_options :raw => :boolean, :iterations => :numeric, :linearize => :boolean def analyze(object_path, *params) raw = options.raw ? "--raw" : "" linearize = options.linearize ? "--linearize" : "" iterations = options.iterations ? options.iterations : 5 require_labfile! update Transcriptic::SBT.stage data = `target/start #{object_path} --verify #{raw} #{linearize} --iterations #{iterations} #{params.join(" ")}` if not options.raw File.open("logs/#{object_path}", 'w') { |file| file.write(data) } data = data.split("\n")[-1] json = json_decode(data) output_with_arrow "Verification successful for #{object_path}" output_with_arrow "Logged output during verification to logs/#{object_path}" output_with_indent "Expected cost: $#{json["price_avg"]}, maximum observed cost: $#{json["price_max"]}" else say data end end desc "publish", "Packages up the current project and uploads it to the Autoprotocol Central Repository" def publish labfile = require_labfile! if compile dependencies = labfile.dependencies.map {|d| "#{d[:group]}.#{d[:name]}/#{d[:version]}" }.join(", ") output_with_arrow "Preparing to publish..." output_with_arrow "Project name: #{labfile.options[:name]}, Author: #{labfile.options[:author]}, Email: #{labfile.options[:email]}" if labfile.options[:description] output_with_arrow "Description: #{labfile.options[:description]}" else display format_with_bang("Warning: No description provided.") end if labfile.dependencies.length > 0 output_with_arrow "Dependencies: #{dependencies}}" end confirm(format_with_bang("Are you sure you want to publish version #{labfile.options[:version]} of this project? (y/N)")) output_with_arrow "Not yet available!" end end desc "launch OBJECTPATH", "Packages up the current project, uploads it to Transcriptic, and starts the protocol object at OBJECTPATH running." def launch(object_path) require_labfile! output_with_arrow "Not yet available!" return fd = create_protocol_fd_for_path(path) if 1 == fd Transcriptic.ui.error_with_failure "Couldn't packaged protocol filename or directory!" end if args.empty? project_id = "default" else project_id = args.shift end run = action("Uploading `#{path}`") { transcriptic.create_run(fd, project_id) } if run["success"] Transcriptic.ui.output_with_arrow "Protocol received: #{run["protocol_format"]} detected" Transcriptic.ui.output_with_arrow "Protocol received: #{run["nsteps"]} steps, expected cost: #{run["exp_cost"]}, total possible cost: #{run["max_cost"]}" Transcriptic.ui.output_with_arrow "Protocol received: expected runtime: #{run["exp_time"]}, total possible runtime: #{run["max_time"]}" if Transcriptic.ui.confirm_quote Transcriptic.ui.display Transcriptic.ui.action("Launching") { transcriptic.launch_run(run["run_id"]) } Transcriptic.ui.output_with_arrow "Protocol run launched. ID: #{run["run_id"]}" Transcriptic.ui.output_with_arrow "Monitor at: https://secure.transcriptic.com/#{run["organization_id"]}/#{run["project_id"]}/runs/#{run["run_id"]}" end else Transcriptic.ui.error_with_failure "Error creating protocol run." end end private def transcriptic Transcriptic::Auth.client end def require_labfile! labfile = Transcriptic.find_labfile if labfile.nil? error("Can't find Labfile! You must run this command from within an autoprotocol project directory.") end Transcriptic::Labfile.from_file(labfile) end end end end