Put some code into collection model to do normalization but I don't think that is...
[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   def redundancy_status
12     if redundancy_confirmed_as.nil?
13       'unconfirmed'
14     elsif redundancy_confirmed_as < redundancy
15       'degraded'
16     else
17       if redundancy_confirmed_at.nil?
18         'unconfirmed'
19       elsif Time.now - redundancy_confirmed_at < 7.days
20         'OK'
21       else
22         'stale'
23       end
24     end
25   end
26
27   def assign_uuid
28     if self.manifest_text.nil? and self.uuid.nil?
29       super
30     elsif self.manifest_text and self.uuid
31       self.uuid.gsub! /\+.*/, ''
32       if self.uuid == Digest::MD5.hexdigest(self.manifest_text)
33         self.uuid.gsub! /$/, '+' + self.manifest_text.length.to_s
34         true
35       else
36         errors.add :uuid, 'uuid does not match checksum of manifest_text'
37         false
38       end
39     elsif self.manifest_text
40       errors.add :uuid, 'checksum for manifest_text not supplied in uuid'
41       false
42     else
43       errors.add :manifest_text, 'manifest_text not supplied'
44       false
45     end
46   end
47
48   def data_size
49     inspect_manifest_text if @data_size.nil? or manifest_text_changed?
50     @data_size
51   end
52
53   def files
54     inspect_manifest_text if @files.nil? or manifest_text_changed?
55     @files
56   end
57
58   def inspect_manifest_text
59     if !manifest_text
60       @data_size = false
61       @files = []
62       return
63     end
64
65     normalized_manifest = ""
66     IO.popen(['arv-normalize'], 'w+b') do |io|
67       io.write manifest_text
68       io.close_write
69       while buf = io.read(2**20)
70         normalized_manifest += buf
71       end
72     end
73
74     @data_size = 0
75     @files = []
76     normalized_manifest.split("\n").each do |stream|
77       toks = stream.split(" ")
78
79       stream = toks[0].gsub /\\(\\|[0-7]{3})/ do |escape_sequence|
80         case $1
81         when '\\' '\\'
82         else $1.to_i(8).chr
83         end
84       end
85
86       toks[1..-1].each do |tok|
87         if (re = tok.match /^[0-9a-f]{32}/)
88           blocksize = nil
89           tok.split('+')[1..-1].each do |hint|
90             if !blocksize and hint.match /^\d+$/
91               blocksize = hint.to_i
92             end
93             if (re = hint.match /^GS(\d+)$/)
94               blocksize = re[1].to_i
95             end
96           end
97           @data_size = false if !blocksize
98           @data_size += blocksize if @data_size
99         else
100           if (re = tok.match /^(\d+):(\d+):(\S+)$/)
101             filename = re[3].gsub /\\(\\|[0-7]{3})/ do |escape_sequence|
102               case $1
103               when '\\' '\\'
104               else $1.to_i(8).chr
105               end
106             end
107             if @files > 0 and @files[-1][0] == stream and @files[-1][1] == filename
108               @files[-1][2] += re[2].to_i
109             else
110               @files << [stream, filename, re[2].to_i]
111             end
112           end
113         end
114       end
115     end
116   end
117 end