Improve headings in Python SDK installation section.
[arvados.git] / services / api / app / models / collection.rb
1 class Collection < ArvadosModel
2   include AssignUuid
3   include KindAndEtag
4   include CommonApiTemplate
5
6   api_accessible :user, extend: :common do |t|
7     t.add :data_size
8     t.add :files
9   end
10
11   api_accessible :with_data, extend: :user do |t|
12     t.add :manifest_text
13   end
14
15   def redundancy_status
16     if redundancy_confirmed_as.nil?
17       'unconfirmed'
18     elsif redundancy_confirmed_as < redundancy
19       'degraded'
20     else
21       if redundancy_confirmed_at.nil?
22         'unconfirmed'
23       elsif Time.now - redundancy_confirmed_at < 7.days
24         'OK'
25       else
26         'stale'
27       end
28     end
29   end
30
31   def assign_uuid
32     if self.manifest_text.nil? and self.uuid.nil?
33       super
34     elsif self.manifest_text and self.uuid
35       self.uuid.gsub! /\+.*/, ''
36       if self.uuid == Digest::MD5.hexdigest(self.manifest_text)
37         self.uuid.gsub! /$/, '+' + self.manifest_text.length.to_s
38         true
39       else
40         errors.add :uuid, 'does not match checksum of manifest_text'
41         false
42       end
43     elsif self.manifest_text
44       errors.add :uuid, 'not supplied (must match checksum of manifest_text)'
45       false
46     else
47       errors.add :manifest_text, 'not supplied'
48       false
49     end
50   end
51
52   def data_size
53     inspect_manifest_text if @data_size.nil? or manifest_text_changed?
54     @data_size
55   end
56
57   def files
58     inspect_manifest_text if @files.nil? or manifest_text_changed?
59     @files
60   end
61
62   def inspect_manifest_text
63     if !manifest_text
64       @data_size = false
65       @files = []
66       return
67     end
68     @data_size = 0
69     @files = []
70     manifest_text.split("\n").each do |stream|
71       toks = stream.split(" ")
72
73       stream = toks[0].gsub /\\(\\|[0-7]{3})/ do |escape_sequence|
74         case $1
75         when '\\' '\\'
76         else $1.to_i(8).chr
77         end
78       end
79
80       toks[1..-1].each do |tok|
81         if (re = tok.match /^[0-9a-f]{32}/)
82           blocksize = nil
83           tok.split('+')[1..-1].each do |hint|
84             if !blocksize and hint.match /^\d+$/
85               blocksize = hint.to_i
86             end
87             if (re = hint.match /^GS(\d+)$/)
88               blocksize = re[1].to_i
89             end
90           end
91           @data_size = false if !blocksize
92           @data_size += blocksize if @data_size
93         else
94           if (re = tok.match /^(\d+):(\d+):(\S+)$/)
95             filename = re[3].gsub /\\(\\|[0-7]{3})/ do |escape_sequence|
96               case $1
97               when '\\' '\\'
98               else $1.to_i(8).chr
99               end
100             end
101             @files << [stream, filename, re[2].to_i]
102           end
103         end
104       end
105     end
106   end
107
108   def self.normalize_uuid uuid
109     hash_part = nil
110     size_part = nil
111     uuid.split('+').each do |token|
112       if token.match /^[0-9a-f]{32,}$/
113         raise "uuid #{uuid} has multiple hash parts" if hash_part
114         hash_part = token
115       elsif token.match /^\d+$/
116         raise "uuid #{uuid} has multiple size parts" if size_part
117         size_part = token
118       end
119     end
120     raise "uuid #{uuid} has no hash part" if !hash_part
121     [hash_part, size_part].compact.join '+'
122   end
123 end