include KindAndEtag
include CommonApiTemplate
+ before_validation :set_portable_data_hash
+ validate :ensure_hash_matches_manifest_text
+
api_accessible :user, extend: :common do |t|
t.add :data_size
t.add :files
+ t.add :name
+ t.add :description
+ t.add :properties
+ t.add :portable_data_hash
end
api_accessible :with_data, extend: :user do |t|
t.add :manifest_text
end
+ def set_portable_data_hash
+ if (self.portable_data_hash.nil? or (self.portable_data_hash == "") or (manifest_text_changed? and !portable_data_hash_changed?))
+ self.portable_data_hash = "#{Digest::MD5.hexdigest(manifest_text)}+#{manifest_text.length}"
+ elsif portable_data_hash_changed?
+ begin
+ loc = Locator.parse!(self.portable_data_hash)
+ loc.strip_hints!
+ self.portable_data_hash = loc.to_s
+ rescue ArgumentError => e
+ errors.add(:portable_data_hash, "#{e}")
+ return false
+ end
+ end
+ true
+ end
+
+ def ensure_hash_matches_manifest_text
+ if manifest_text_changed? or portable_data_hash_changed?
+ computed_hash = "#{Digest::MD5.hexdigest(manifest_text)}+#{manifest_text.length}"
+ unless computed_hash == portable_data_hash
+ logger.debug "(computed) '#{computed_hash}' != '#{portable_data_hash}' (provided)"
+ errors.add(:portable_data_hash, "does not match hash of manifest_text")
+ return false
+ end
+ end
+ true
+ end
+
def redundancy_status
if redundancy_confirmed_as.nil?
'unconfirmed'
end
end
- def assign_uuid
- if not self.manifest_text
- errors.add :manifest_text, 'not supplied'
- return false
- end
- expect_uuid = Digest::MD5.hexdigest(self.manifest_text)
- if self.uuid
- self.uuid.gsub! /\+.*/, ''
- if self.uuid != expect_uuid
- errors.add :uuid, 'must match checksum of manifest_text'
- return false
- end
- else
- self.uuid = expect_uuid
- end
- self.uuid.gsub! /$/, '+' + self.manifest_text.length.to_s
- true
- end
-
- # TODO (#3036/tom) replace above assign_uuid method with below assign_uuid and self.generate_uuid
- # def assign_uuid
- # # Even admins cannot assign collection uuids.
- # self.uuid = self.class.generate_uuid
- # end
- # def self.generate_uuid
- # # The last 10 characters of a collection uuid are the last 10
- # # characters of the base-36 SHA256 digest of manifest_text.
- # [Server::Application.config.uuid_prefix,
- # self.uuid_prefix,
- # rand(2**256).to_s(36)[-5..-1] + Digest::SHA256.hexdigest(self.manifest_text).to_i(16).to_s(36)[-10..-1],
- # ].join '-'
- # end
-
def data_size
inspect_manifest_text if @data_size.nil? or manifest_text_changed?
@data_size
end
end
- def self.uuid_like_pattern
- "________________________________+%"
- end
-
def self.normalize_uuid uuid
hash_part = nil
size_part = nil
joins("JOIN collections ON links.head_uuid = collections.uuid").
order("links.created_at DESC")
- # If the search term is a Collection locator with an associated
- # Docker image hash link, return that Collection.
- coll_matches = base_search.
- where(link_class: "docker_image_hash", collections: {uuid: search_term})
- if match = coll_matches.first
- return [match.head_uuid]
+ # If the search term is a Collection locator that contains one file
+ # that looks like a Docker image, return it.
+ if loc = Locator.parse(search_term)
+ loc.strip_hints!
+ coll_match = readable_by(*readers).where(portable_data_hash: loc.to_s).limit(1).first
+ if coll_match and (coll_match.files.size == 1) and
+ (coll_match.files[0][1] =~ /^[0-9A-Fa-f]{64}\.tar$/)
+ return [coll_match.uuid]
+ end
+ end
+
+ if search_tag.nil? and (n = search_term.index(":"))
+ search_tag = search_term[n+1..-1]
+ search_term = search_term[0..n-1]
end
# Find Collections with matching Docker image repository+tag pairs.
# If that didn't work, find Collections with matching Docker image hashes.
if matches.empty?
matches = base_search.
- where("link_class = ? and name LIKE ?",
+ where("link_class = ? and links.name LIKE ?",
"docker_image_hash", "#{search_term}%")
end
# anything without; then we use the link's created_at as a tiebreaker.
uuid_timestamps = {}
matches.find_each do |link|
- uuid_timestamps[link.head_uuid] =
+ c = Collection.find_by_uuid(link.head_uuid)
+ uuid_timestamps[c.uuid] =
[(-link.properties["image_timestamp"].to_datetime.to_i rescue 0),
-link.created_at.to_i]
end