2 # Copyright (C) The Arvados Authors. All rights reserved.
4 # SPDX-License-Identifier: Apache-2.0
7 # arv tag add tag1 [tag2 ...] --object obj_uuid1 [--object obj_uuid2 ...]
8 # arv tag remove tag1 [tag2 ...] --object obj_uuid1 [--object obj_uuid2 ...]
9 # arv tag remove tag1 [tag2 ...] --all
13 "arv tag add tag1 [tag2 ...] --object object_uuid1 [object_uuid2...]\n" +
14 "arv tag remove tag1 [tag2 ...] --object object_uuid1 [object_uuid2...]\n" +
15 "arv tag remove --all\n"
22 def api_call(method, parameters:{}, request_body:{})
23 result = $client.execute(:api_method => method,
24 :parameters => parameters,
25 :body_object => request_body,
26 :authenticated => false,
28 authorization: "OAuth2 #{ENV['ARVADOS_API_TOKEN']}",
32 results = JSON.parse result.body
33 rescue JSON::ParserError => e
34 abort "Failed to parse server response:\n" + e.to_s
38 abort "Error: #{results["errors"][0]}"
44 def tag_add(tag, obj_uuid)
45 return api_call($arvados.links.create,
50 :head_uuid => obj_uuid,
55 def tag_remove(tag, obj_uuids=nil)
56 # If we got a list of objects to untag, look up the uuids for the
57 # links that need to be deleted.
60 obj_uuids.each do |uuid|
61 link = api_call($arvados.links.list,
69 if link['items_available'] > 0
70 link_uuids.push link['items'][0]['uuid']
74 all_tag_links = api_call($arvados.links.list,
81 link_uuids = all_tag_links['items'].map { |obj| obj['uuid'] }
86 link_uuids.each do |uuid|
87 results.push api_call($arvados.links.delete, parameters:{ :uuid => uuid })
90 $stderr.puts "no tags found to remove"
96 if RUBY_VERSION < '1.9.3' then
98 #{$0.gsub(/^\.\//,'')} requires Ruby version 1.9.3 or higher.
102 $arvados_api_version = ENV['ARVADOS_API_VERSION'] || 'v1'
103 $arvados_api_host = ENV['ARVADOS_API_HOST'] or
104 abort "#{$0}: fatal: ARVADOS_API_HOST environment variable not set."
105 $arvados_api_token = ENV['ARVADOS_API_TOKEN'] or
106 abort "#{$0}: fatal: ARVADOS_API_TOKEN environment variable not set."
107 $arvados_api_host_insecure = %w(1 true yes).
108 include?((ENV['ARVADOS_API_HOST_INSECURE'] || "").downcase)
112 require 'google/api_client'
119 #{$0}: fatal: some runtime dependencies are missing.
120 Try: gem install pp google-api-client json trollop
124 def debuglog(message, verbosity=1)
125 $stderr.puts "#{File.split($0).last} #{$$}: #{message}" if $debuglevel >= verbosity
129 def suppress_warnings
130 original_verbosity = $VERBOSE
133 $VERBOSE = original_verbosity
138 if $arvados_api_host_insecure or $arvados_api_host.match /local/
139 # You probably don't care about SSL certificate checks if you're
140 # testing with a dev server.
141 suppress_warnings { OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE }
144 class Google::APIClient
145 def discovery_document(api, version)
147 return @discovery_documents["#{api}:#{version}"] ||=
149 response = self.execute!(
150 :http_method => :get,
151 :uri => self.discovery_uri(api, version),
152 :authenticated => false
154 response.body.class == String ? JSON.parse(response.body) : response.body
159 global_opts = Trollop::options do
162 opt :dry_run, "Don't actually do anything", :short => "-n"
163 opt :verbose, "Print some things on stderr", :short => "-v"
164 opt :uuid, "Return the UUIDs of the objects in the response, one per line (default)", :short => nil
165 opt :json, "Return the entire response received from the API server, as a JSON object", :short => "-j"
166 opt :human, "Return the response received from the API server, as a JSON object with whitespace added for human consumption", :short => "-h"
167 opt :pretty, "Synonym of --human", :short => nil
168 opt :yaml, "Return the response received from the API server, in YAML format", :short => "-y"
169 stop_on ['add', 'remove']
172 p = Trollop::Parser.new do
174 "Remove this tag from all objects under your ownership. Only valid with `tag remove'.",
177 "The UUID of an object to which this tag operation should be applied.",
183 $options = Trollop::with_standard_exception_handling p do
187 if $options[:all] and ARGV[0] != 'remove'
191 # Set up the API client.
193 $client ||= Google::APIClient.
194 new(:host => $arvados_api_host,
195 :application_name => File.split($0).last,
196 :application_version => $application_version.to_s)
197 $arvados = $client.discovered_api('arvados', $arvados_api_version)
209 $options[:object].each do |obj|
210 results.push(tag_add(tag, obj))
215 if $options[:all] then
216 results.concat tag_remove(tag)
218 results.concat tag_remove(tag, $options[:object])
225 if global_opts[:human] or global_opts[:pretty] then
226 puts Oj.dump(results, :indent => 1)
227 elsif global_opts[:yaml] then
229 elsif global_opts[:json] then
230 puts Oj.dump(results)
234 abort("Response did not include a uuid:\n" +
235 Oj.dump(r, :indent => 1) +