Merge branch '3052-crunch-log-stdout' into 3769-throttle-logs
[arvados.git] / apps / workbench / app / models / collection.rb
1 require "arvados/keep"
2
3 class Collection < ArvadosBase
4   MD5_EMPTY = 'd41d8cd98f00b204e9800998ecf8427e'
5
6   def default_name
7     if Collection.is_empty_blob_locator? self.uuid
8       "Empty Collection"
9     else
10       super
11     end
12   end
13
14   # Return true if the given string is the locator of a zero-length blob
15   def self.is_empty_blob_locator? locator
16     !!locator.to_s.match("^#{MD5_EMPTY}(\\+.*)?\$")
17   end
18
19   def self.goes_in_projects?
20     true
21   end
22
23   def manifest
24     if @manifest.nil? or manifest_text_changed?
25       @manifest = Keep::Manifest.new(manifest_text || "")
26     end
27     @manifest
28   end
29
30   def files
31     # This method provides backwards compatibility for code that relied on
32     # the old files field in API results.  New code should use manifest
33     # methods directly.
34     manifest.files
35   end
36
37   def content_summary
38     ApplicationController.helpers.human_readable_bytes_html(total_bytes) + " " + super
39   end
40
41   def total_bytes
42     manifest.files.inject(0) { |sum, filespec| sum + filespec.last }
43   end
44
45   def files_tree
46     tree = manifest.files.group_by do |file_spec|
47       File.split(file_spec.first)
48     end
49     return [] if tree.empty?
50     # Fill in entries for empty directories.
51     tree.keys.map { |basedir, _| File.split(basedir) }.each do |splitdir|
52       until tree.include?(splitdir)
53         tree[splitdir] = []
54         splitdir = File.split(splitdir.first)
55       end
56     end
57     dir_to_tree = lambda do |dirname|
58       # First list subdirectories, with their files inside.
59       subnodes = tree.keys.select { |bd, td| (bd == dirname) and (td != '.') }
60         .sort.flat_map do |parts|
61         [parts + [nil]] + dir_to_tree.call(File.join(parts))
62       end
63       # Then extend that list with files in this directory.
64       subnodes + tree[File.split(dirname)]
65     end
66     dir_to_tree.call('.')
67   end
68
69   def attribute_editable? attr, *args
70     if %w(name description manifest_text).include? attr.to_s
71       true
72     else
73       super
74     end
75   end
76
77   def self.creatable?
78     false
79   end
80
81   def provenance
82     arvados_api_client.api "collections/#{self.uuid}/", "provenance"
83   end
84
85   def used_by
86     arvados_api_client.api "collections/#{self.uuid}/", "used_by"
87   end
88
89   def uuid
90     if self[:uuid].nil?
91       return self[:portable_data_hash]
92     else
93       super
94     end
95   end
96
97   def portable_data_hash
98     if self[:portable_data_hash].nil?
99       return self[:uuid]
100     else
101       super
102     end
103   end
104
105   def friendly_link_name lookup=nil
106     if self.respond_to? :name
107       self.name
108     else
109       self.portable_data_hash
110     end
111   end
112
113   def textile_attributes
114     [ 'description' ]
115   end
116
117 end