Do a partial normalization of file list before sending to client.
[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     tmp = {}
76
77     manifest_text.split("\n").each do |stream|
78       toks = stream.split(" ")
79
80       stream = toks[0].gsub /\\(\\|[0-7]{3})/ do |escape_sequence|
81         case $1
82         when '\\' '\\'
83         else $1.to_i(8).chr
84         end
85       end
86
87       toks[1..-1].each do |tok|
88         if (re = tok.match /^[0-9a-f]{32}/)
89           blocksize = nil
90           tok.split('+')[1..-1].each do |hint|
91             if !blocksize and hint.match /^\d+$/
92               blocksize = hint.to_i
93             end
94             if (re = hint.match /^GS(\d+)$/)
95               blocksize = re[1].to_i
96             end
97           end
98           @data_size = false if !blocksize
99           @data_size += blocksize if @data_size
100         else
101           if (re = tok.match /^(\d+):(\d+):(\S+)$/)
102             filename = re[3].gsub /\\(\\|[0-7]{3})/ do |escape_sequence|
103               case $1
104               when '\\' '\\'
105               else $1.to_i(8).chr
106               end
107             end
108             fn = stream + '/' + filename
109             i = re[2].to_i
110             if tmp[fn]
111               tmp[fn] += i
112             else
113               tmp[fn] = i
114             end
115           end
116         end
117       end
118
119       @files = []
120       tmp.each do |k, v|
121         re = k.match(/^(.+)\/(.+)/)
122         @files << [re[1], re[2], v]
123       end
124     end
125   end
126 end