diff options
-rw-r--r-- | app/controllers/projects/artifacts_controller.rb | 5 | ||||
-rw-r--r-- | app/models/ci/build.rb | 20 | ||||
-rw-r--r-- | lib/gitlab/ci/build/artifacts/metadata.rb | 57 | ||||
-rw-r--r-- | lib/gitlab/string_path.rb | 4 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb | 76 |
5 files changed, 139 insertions, 23 deletions
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index 5bd0c8cd780..ee1b1f375dc 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -16,10 +16,7 @@ class Projects::ArtifactsController < Projects::ApplicationController def browse return render_404 unless build.artifacts? - - current_path = params[:path] ? "./#{params[:path]}/" : './' - paths, metadata = build.artifacts_metadata_for_path(current_path) - @path = Gitlab::StringPath.new(current_path, paths, metadata) + @path = build.artifacts_metadata_string_path(params[:path] || './') end private diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index df51a5ce079..7983ce0e88e 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -349,24 +349,10 @@ module Ci artifacts? && artifacts_file.path.end_with?('zip') && artifacts_metadata.exists? end - def artifacts_metadata_for_path(path) - return [] unless artifacts_metadata.exists? - paths, metadata = [], [] - - metadata_path = path.sub(/^\.\//, '') - File.open(artifacts_metadata.path) do |file| - gzip = Zlib::GzipReader.new(file) - gzip.each_line do |line| - if line =~ %r{^#{Regexp.escape(metadata_path)}[^/\s]+/?\s} - matched_path, matched_meta = line.split(' ') - paths << matched_path - metadata << JSON.parse(matched_meta) - end - end - gzip.close - end - [paths, metadata] + def artifacts_metadata_string_path(path) + file = artifacts_metadata.path + Gitlab::Ci::Build::Artifacts::Metadata.new(file, path).to_string_path end private diff --git a/lib/gitlab/ci/build/artifacts/metadata.rb b/lib/gitlab/ci/build/artifacts/metadata.rb new file mode 100644 index 00000000000..5313182d55f --- /dev/null +++ b/lib/gitlab/ci/build/artifacts/metadata.rb @@ -0,0 +1,57 @@ +require 'zlib' +require 'json' + +module Gitlab + module Ci + module Build + module Artifacts + class Metadata + def initialize(file, path) + @file = file + + @path = path.sub(/^\.\//, '') + @path << '/' unless path.end_with?('/') + end + + def exists? + File.exists?(@file) + end + + def match! + raise StandardError, 'Metadata file not found !' unless exists? + paths, metadata = [], [] + + each do |line| + next unless line =~ %r{^#{Regexp.escape(@path)}[^/\s]+/?\s} + + path, meta = line.split(' ') + paths.push(path) + metadata.push(meta) + end + + [paths, metadata.map { |meta| JSON.parse(meta) }] + end + + def to_string_path + universe, metadata = match! + ::Gitlab::StringPath.new(@path, universe, metadata) + end + + private + + def each + open do |file| + gzip = Zlib::GzipReader.new(file) + gzip.each_line { |line| yield line } + gzip.close + end + end + + def open + File.open(@file) { |file| yield file } + end + end + end + end + end +end diff --git a/lib/gitlab/string_path.rb b/lib/gitlab/string_path.rb index e7d99a35869..9948502e8ea 100644 --- a/lib/gitlab/string_path.rb +++ b/lib/gitlab/string_path.rb @@ -75,7 +75,7 @@ module Gitlab end def directories! - has_parent? ? directories.prepend(parent) : directories + @path =~ %r{^\./[^/]/} ? directories.prepend(parent) : directories end def files @@ -119,7 +119,7 @@ module Gitlab raise ArgumentError, 'Invalid path' if clean_path.start_with?('../') prefix = './' unless clean_path =~ %r{^[\.|/]} - suffix = '/' if path.end_with?('/') || clean_path =~ /^[\.|\.\.]$/ + suffix = '/' if path.end_with?('/') || ['.', '..'].include?(clean_path) prefix.to_s + clean_path + suffix.to_s end end diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb new file mode 100644 index 00000000000..8c648be5f02 --- /dev/null +++ b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' + +describe Gitlab::Ci::Build::Artifacts::Metadata do + def metadata(path = '') + described_class.new(metadata_file_path, path) + end + + let(:metadata_file_path) do + Rails.root + 'spec/fixtures/ci_build_artifacts_metadata.gz' + end + + context 'metadata file exists' do + describe '#exists?' do + subject { metadata.exists? } + it { is_expected.to be true } + end + + describe '#match! ./' do + subject { metadata('./').match! } + + it 'matches correct paths' do + expect(subject.first).to contain_exactly 'ci_artifacts.txt', + 'other_artifacts_0.1.2/', + 'rails_sample.jpg' + end + + it 'matches metadata for every path' do + expect(subject.last.count).to eq 3 + end + + it 'return Hashes for each metadata' do + expect(subject.last).to all(be_kind_of(Hash)) + end + end + + describe '#match! other_artifacts_0.1.2' do + subject { metadata('other_artifacts_0.1.2').match! } + + it 'matches correct paths' do + expect(subject.first). + to contain_exactly 'other_artifacts_0.1.2/doc_sample.txt', + 'other_artifacts_0.1.2/another-subdirectory/' + end + end + + describe '#match! other_artifacts_0.1.2/another-subdirectory' do + subject { metadata('other_artifacts_0.1.2/another-subdirectory/').match! } + + it 'matches correct paths' do + expect(subject.first). + to contain_exactly 'other_artifacts_0.1.2/another-subdirectory/empty_directory/', + 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif' + end + end + + describe '#to_string_path' do + subject { metadata('').to_string_path } + it { is_expected.to be_an_instance_of(Gitlab::StringPath) } + end + end + + context 'metadata file does not exist' do + let(:metadata_file_path) { '' } + + describe '#exists?' do + subject { metadata.exists? } + it { is_expected.to be false } + end + + describe '#match!' do + it 'raises error' do + expect { metadata.match! }.to raise_error(StandardError, /Metadata file not found/) + end + end + end +end |