Merge branch 'master' into 3016-pipeline-template-search-string
[arvados.git] / apps / workbench / app / controllers / actions_controller.rb
index 06775fc924521bdfa6a7796098bbed1cabaaa8c0..9f2cfb09f3da31ecb6953b5e5a3e915b212d757f 100644 (file)
@@ -10,6 +10,17 @@ class ActionsController < ApplicationController
     ArvadosBase::resource_class_for_uuid(params[:uuid])
   end
 
+  def show
+    @object = model_class.find(params[:uuid])
+    if @object.is_a? Link and
+        @object.link_class == 'name' and
+        ArvadosBase::resource_class_for_uuid(@object.head_uuid) == Collection
+      redirect_to collection_path(id: @object.uuid)
+    else
+      redirect_to @object
+    end
+  end
+
   def post
     params.keys.collect(&:to_sym).each do |param|
       if @@exposed_actions[param]
@@ -20,53 +31,83 @@ class ActionsController < ApplicationController
   end
 
   expose_action :copy_selections_into_project do
-    link_selections = Link.filter([['uuid','in',params["selection"]]])
-    link_uuids = link_selections.collect(&:uuid)
-
-    # Given a link uuid, we'll add the link's head_uuid. Given another
-    # type, we'll add the object itself.
-    uuids_to_add = params["selection"] - link_uuids
-    uuids_to_add += link_selections.collect(&:head_uuid)
-
-    # Skip anything that's already here.
-    already_named = Link.
-      filter([['tail_uuid','=',@object.uuid],
-              ['head_uuid','in',uuids_to_add],
-              ['link_class','=','name']]).
-      collect(&:head_uuid)
-    uuids_to_add -= already_named
-
-    # Given a name link, we'll try to add the linked object using the
-    # same name.
-    name_for = {}
-    link_selections.
-      select { |x| x.link_class == 'name' }.
-      each do |link|
-      name_for[link.head_uuid] = link.name
-    end
+    move_or_copy :copy
+  end
+
+  expose_action :move_selections_into_project do
+    move_or_copy :move
+  end
 
-    uuids_to_add.each do |s|
-      name = name_for[s] || s
-      begin
-        Link.create(tail_uuid: @object.uuid,
-                    head_uuid: s,
-                    link_class: 'name',
-                    name: name)
-      rescue
-        Link.create(tail_uuid: @object.uuid,
-                    head_uuid: s,
-                    link_class: 'name',
-                    name: name + " (#{Time.now.localtime})")
+  def move_or_copy action
+    uuids_to_add = params["selection"]
+    uuids_to_add.
+      collect { |x| ArvadosBase::resource_class_for_uuid(x) }.
+      uniq.
+      each do |resource_class|
+      resource_class.filter([['uuid','in',uuids_to_add]]).each do |src|
+        if resource_class == Collection
+          dst = Link.new(owner_uuid: @object.uuid,
+                         tail_uuid: @object.uuid,
+                         head_uuid: src.uuid,
+                         link_class: 'name',
+                         name: src.uuid)
+        else
+          case action
+          when :copy
+            dst = src.dup
+            if dst.respond_to? :'name='
+              if dst.name
+                dst.name = "Copy of #{dst.name}"
+              else
+                dst.name = "Copy of unnamed #{dst.class_for_display.downcase}"
+              end
+            end
+          when :move
+            dst = src
+          else
+            raise ArgumentError.new "Unsupported action #{action}"
+          end
+          dst.owner_uuid = @object.uuid
+          dst.tail_uuid = @object.uuid if dst.class == Link
+        end
+        begin
+          dst.save!
+        rescue
+          dst.name += " (#{Time.now.localtime})" if dst.respond_to? :name=
+          dst.save!
+        end
       end
     end
     redirect_to @object
   end
 
+  def arv_normalize mt, *opts
+    r = ""
+    IO.popen(['arv-normalize'] + opts, 'w+b') do |io|
+      io.write mt
+      io.close_write
+      while buf = io.read(2**16)
+        r += buf
+      end
+    end
+    r
+  end
+
   expose_action :combine_selected_files_into_collection do
     lst = []
     files = []
     params["selection"].each do |s|
-      m = CollectionsHelper.match(s)
+      a = ArvadosBase::resource_class_for_uuid s
+      m = nil
+      if a == Link
+        begin
+          m = CollectionsHelper.match(Link.find(s).head_uuid)
+        rescue
+        end
+      else
+        m = CollectionsHelper.match(s)
+      end
+
       if m and m[1] and m[2]
         lst.append(m[1] + m[2])
         files.append(m)
@@ -85,32 +126,20 @@ class ActionsController < ApplicationController
     files.each do |m|
       mt = chash[m[1]+m[2]].manifest_text
       if m[4]
-        IO.popen(['arv-normalize', '--extract', m[4][1..-1]], 'w+b') do |io|
-          io.write mt
-          io.close_write
-          while buf = io.read(2**20)
-            combined += buf
-          end
-        end
+        combined += arv_normalize mt, '--extract', m[4][1..-1]
       else
         combined += chash[m[1]+m[2]].manifest_text
       end
     end
 
-    normalized = ''
-    IO.popen(['arv-normalize'], 'w+b') do |io|
-      io.write combined
-      io.close_write
-      while buf = io.read(2**20)
-        normalized += buf
-      end
-    end
+    normalized = arv_normalize combined
+    normalized_stripped = arv_normalize combined, '--strip'
 
     require 'digest/md5'
 
     d = Digest::MD5.new()
-    d << normalized
-    newuuid = "#{d.hexdigest}+#{normalized.length}"
+    d << normalized_stripped
+    newuuid = "#{d.hexdigest}+#{normalized_stripped.length}"
 
     env = Hash[ENV].
       merge({
@@ -124,10 +153,9 @@ class ActionsController < ApplicationController
             })
 
     IO.popen([env, 'arv-put', '--raw'], 'w+b') do |io|
-      io.write normalized
+      io.write normalized_stripped
       io.close_write
-      while buf = io.read(2**20)
-
+      while buf = io.read(2**16)
       end
     end