2018-12-13 13:39:08 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-01-19 16:12:03 +05:30
|
|
|
module Gitlab
|
2018-03-17 18:26:18 +05:30
|
|
|
module Ci
|
|
|
|
module Build
|
|
|
|
module Artifacts
|
|
|
|
class Metadata
|
|
|
|
##
|
|
|
|
# Class that represents an entry (path and metadata) to a file or
|
|
|
|
# directory in GitLab CI Build Artifacts binary file / archive
|
|
|
|
#
|
|
|
|
# This is IO-operations safe class, that does similar job to
|
|
|
|
# Ruby's Pathname but without the risk of accessing filesystem.
|
|
|
|
#
|
|
|
|
# This class is working only with UTF-8 encoded paths.
|
|
|
|
#
|
|
|
|
class Entry
|
|
|
|
attr_reader :entries
|
|
|
|
attr_accessor :name
|
|
|
|
|
|
|
|
def initialize(path, entries)
|
|
|
|
@entries = entries
|
|
|
|
@path = Artifacts::Path.new(path)
|
|
|
|
end
|
|
|
|
|
|
|
|
delegate :empty?, to: :children
|
|
|
|
|
|
|
|
def directory?
|
|
|
|
blank_node? || @path.directory?
|
|
|
|
end
|
|
|
|
|
|
|
|
def file?
|
|
|
|
!directory?
|
|
|
|
end
|
|
|
|
|
|
|
|
def blob
|
|
|
|
return unless file?
|
|
|
|
|
|
|
|
@blob ||= Blob.decorate(::Ci::ArtifactBlob.new(self), nil)
|
|
|
|
end
|
|
|
|
|
|
|
|
def has_parent?
|
|
|
|
nodes > 0
|
|
|
|
end
|
|
|
|
|
|
|
|
def parent
|
2019-05-18 00:54:41 +05:30
|
|
|
return unless has_parent?
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
self.class.new(@path.to_s.chomp(basename), @entries)
|
|
|
|
end
|
|
|
|
|
|
|
|
def basename
|
2020-05-24 23:13:21 +05:30
|
|
|
directory? && !blank_node? ? name + '/' : name
|
2018-03-17 18:26:18 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def name
|
|
|
|
@name || @path.name
|
|
|
|
end
|
|
|
|
|
|
|
|
def children
|
|
|
|
return [] unless directory?
|
|
|
|
return @children if @children
|
|
|
|
|
|
|
|
child_pattern = %r{^#{Regexp.escape(@path.to_s)}[^/]+/?$}
|
|
|
|
@children = select_entries { |path| path =~ child_pattern }
|
|
|
|
end
|
|
|
|
|
|
|
|
def directories(opts = {})
|
|
|
|
return [] unless directory?
|
|
|
|
|
|
|
|
dirs = children.select(&:directory?)
|
|
|
|
return dirs unless has_parent? && opts[:parent]
|
|
|
|
|
|
|
|
dotted_parent = parent
|
|
|
|
dotted_parent.name = '..'
|
|
|
|
dirs.prepend(dotted_parent)
|
|
|
|
end
|
|
|
|
|
|
|
|
def files
|
|
|
|
return [] unless directory?
|
|
|
|
|
|
|
|
children.select(&:file?)
|
|
|
|
end
|
|
|
|
|
|
|
|
def metadata
|
|
|
|
@entries[@path.to_s] || {}
|
|
|
|
end
|
|
|
|
|
|
|
|
def nodes
|
|
|
|
@path.nodes + (file? ? 1 : 0)
|
|
|
|
end
|
|
|
|
|
|
|
|
def blank_node?
|
|
|
|
@path.to_s.empty? # "" is considered to be './'
|
|
|
|
end
|
|
|
|
|
|
|
|
def exists?
|
|
|
|
blank_node? || @entries.include?(@path.to_s)
|
|
|
|
end
|
|
|
|
|
2018-12-05 23:21:45 +05:30
|
|
|
# rubocop: disable CodeReuse/ActiveRecord
|
2018-03-17 18:26:18 +05:30
|
|
|
def total_size
|
|
|
|
descendant_pattern = /^#{Regexp.escape(@path.to_s)}/
|
|
|
|
entries.sum do |path, entry|
|
|
|
|
(entry[:size] if path =~ descendant_pattern).to_i
|
|
|
|
end
|
|
|
|
end
|
2018-12-05 23:21:45 +05:30
|
|
|
# rubocop: enable CodeReuse/ActiveRecord
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
def path
|
|
|
|
@path.to_s
|
|
|
|
end
|
2016-01-19 16:12:03 +05:30
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
def to_s
|
|
|
|
@path.to_s
|
|
|
|
end
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
def ==(other)
|
|
|
|
path == other.path && @entries == other.entries
|
|
|
|
end
|
2016-01-19 16:12:03 +05:30
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
def inspect
|
|
|
|
"#{self.class.name}: #{self}"
|
|
|
|
end
|
2016-01-19 16:12:03 +05:30
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
private
|
2017-08-17 22:00:37 +05:30
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
def select_entries
|
|
|
|
selected = @entries.select { |path, _metadata| yield path }
|
|
|
|
selected.map { |path, _metadata| self.class.new(path, @entries) }
|
|
|
|
end
|
2016-01-29 22:53:50 +05:30
|
|
|
end
|
|
|
|
end
|
2016-01-19 16:12:03 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|