Merge branch 'master' into 3699-arv-copy
[arvados.git] / sdk / cli / bin / arv
index 259b38ac83ce393e8962e1889b465152565015c3..ec3d8061b52a82f98b5dfe9163b4a74c20030b35 100755 (executable)
@@ -2,7 +2,7 @@
 
 # Arvados cli client
 #
-# Ward Vandewege <ward@clinicalfuture.com>
+# Ward Vandewege <ward@curoverse.com>
 
 require 'fileutils'
 
@@ -53,17 +53,25 @@ end
 class Google::APIClient
  def discovery_document(api, version)
    api = api.to_s
-   return @discovery_documents["#{api}:#{version}"] ||=
+   discovery_uri = self.discovery_uri(api, version)
+   discovery_uri_hash = Digest::MD5.hexdigest(discovery_uri)
+   return @discovery_documents[discovery_uri_hash] ||=
      begin
        # fetch new API discovery doc if stale
-       cached_doc = File.expand_path '~/.cache/arvados/discovery_uri.json'
-       if not File.exist?(cached_doc) or (Time.now - File.mtime(cached_doc)) > 86400
+       cached_doc = File.expand_path "~/.cache/arvados/discovery-#{discovery_uri_hash}.json" rescue nil
+
+       if cached_doc.nil? or not File.exist?(cached_doc) or (Time.now - File.mtime(cached_doc)) > 86400
          response = self.execute!(:http_method => :get,
-                                  :uri => self.discovery_uri(api, version),
+                                  :uri => discovery_uri,
                                   :authenticated => false)
-         FileUtils.makedirs(File.dirname cached_doc)
-         File.open(cached_doc, 'w') do |f|
-           f.puts response.body
+
+         begin
+           FileUtils.makedirs(File.dirname cached_doc)
+           File.open(cached_doc, 'w') do |f|
+             f.puts response.body
+           end
+         rescue
+           return JSON.load response.body
          end
        end
 
@@ -85,8 +93,8 @@ end
 def init_config
   # read authentication data from arvados configuration file if present
   lineno = 0
-  config_file = File.expand_path('~/.config/arvados/settings.conf')
-  if File.exist? config_file then
+  config_file = File.expand_path('~/.config/arvados/settings.conf') rescue nil
+  if not config_file.nil? and File.exist? config_file then
     File.open(config_file, 'r').each do |line|
       lineno = lineno + 1
       # skip comments
@@ -110,7 +118,7 @@ def check_subcommands client, arvados, subcommand, global_opts, remaining_opts
   case subcommand
   when 'keep'
     @sub = remaining_opts.shift
-    if ['get', 'put', 'ls', 'normalize'].index @sub then
+    if ['get', 'put', 'ls', 'normalize', 'copy'].index @sub then
       # Native Arvados
       exec `which arv-#{@sub}`.strip, *remaining_opts
     elsif ['less', 'check'].index @sub then
@@ -143,9 +151,14 @@ def check_subcommands client, arvados, subcommand, global_opts, remaining_opts
   end
 end
 
+def arv_edit_save_tmp tmp
+  FileUtils::cp tmp.path, tmp.path + ".saved"
+  puts "Saved contents to " + tmp.path + ".saved"
+end
+
 def arv_edit client, arvados, global_opts, remaining_opts
-  n = remaining_opts.shift
-  if n.nil? or n == "-h" or n == "--help"
+  uuid = remaining_opts.shift
+  if uuid.nil? or uuid == "-h" or uuid == "--help"
     puts head_banner
     puts "Usage: arv edit [uuid] [fields...]\n\n"
     puts "Fetch the specified Arvados object, select the specified fields, \n"
@@ -162,9 +175,9 @@ def arv_edit client, arvados, global_opts, remaining_opts
 
   # determine controller
 
-  m = /([a-z0-9]{5})-([a-z0-9]{5})-([a-z0-9]{15})/.match n
+  m = /([a-z0-9]{5})-([a-z0-9]{5})-([a-z0-9]{15})/.match uuid
   if !m
-    if /^[a-f0-9]{32}/.match n
+    if /^[a-f0-9]{32}/.match uuid
       abort "Arvados collections are not editable."
     else
       abort "#{n} does not appear to be an Arvados uuid"
@@ -184,12 +197,10 @@ def arv_edit client, arvados, global_opts, remaining_opts
     abort "Could not determine resource type #{m[2]}"
   end
 
-  require 'fileutils'
-
   api_method = 'arvados.' + rsc + '.get'
 
   result = client.execute(:api_method => eval(api_method),
-                          :parameters => {"uuid" => n},
+                          :parameters => {"uuid" => uuid},
                           :authenticated => false,
                           :headers => {
                             authorization: 'OAuth2 '+ENV['ARVADOS_API_TOKEN']
@@ -215,7 +226,7 @@ def arv_edit client, arvados, global_opts, remaining_opts
 
   require 'tempfile'
 
-  tmp = Tempfile.new([n, "." + global_opts[:format]])
+  tmp = Tempfile.new([uuid, "." + global_opts[:format]])
   tmp.write(content)
   tmp.close
 
@@ -258,9 +269,8 @@ def arv_edit client, arvados, global_opts, remaining_opts
           yn = $stdin.read 1
         end
         if yn == 'n' or yn == 'N'
-          FileUtils::cp tmp.path, tmp.path + ".saved"
-          puts "Saved contents to " + tmp.path + ".saved"
-          exit 1
+          arv_edit_save_tmp tmp
+          abort
         end
       end
     else
@@ -276,18 +286,17 @@ def arv_edit client, arvados, global_opts, remaining_opts
 
       begin
         result = client.execute(:api_method => eval(api_method),
-                                :parameters => {"uuid" => n},
+                                :parameters => {"uuid" => uuid},
                                 :body => { rsc.singularize => dumped },
                                 :authenticated => false,
                                 :headers => {
                                   authorization: 'OAuth2 '+ENV['ARVADOS_API_TOKEN']
                                 })
       rescue Exception => e
-        FileUtils::cp tmp.path, tmp.path + ".saved"
         puts "Error communicating with server, error was #{e}"
         puts "Update body was:"
         puts dumped
-        puts "Saved contents to " + tmp.path + ".saved"
+        arv_edit_save_tmp tmp
         abort
       end
 
@@ -298,11 +307,10 @@ def arv_edit client, arvados, global_opts, remaining_opts
       end
 
       if result.response.status != 200
-        FileUtils::cp tmp.path, tmp.path + ".saved"
         puts "Update failed.  Server responded #{result.response.status}: #{results['errors']} "
         puts "Update body was:"
         puts dumped
-        puts "Saved contents to " + tmp.path + ".saved"
+        arv_edit_save_tmp tmp
         abort
       end
     else
@@ -350,10 +358,6 @@ end
 
 def help_resources(option_parser, discovery_document, resource)
   option_parser.educate
-
-  if not resource.nil? and resource != '--help' then
-    Trollop::die "Unknown resource type #{resource.inspect}"
-  end
   exit 255
 end