Commit d634a988 authored by Furkan Ayhan's avatar Furkan Ayhan Committed by Peter Leitzen

Implement wildcard support for file searching in repository

Gitaly client and Git repository now support regexp searching.
However, Repository model now supports wildcard searching.
parent 65a0a021
...@@ -995,6 +995,12 @@ class Repository ...@@ -995,6 +995,12 @@ class Repository
raw_repository.search_files_by_name(query, ref) raw_repository.search_files_by_name(query, ref)
end end
def search_files_by_wildcard_path(path, ref = 'HEAD')
# We need to use RE2 to match Gitaly's regexp engine
regexp_string = RE2::Regexp.escape(path).gsub('\*', '.*?')
raw_repository.search_files_by_regexp("^#{regexp_string}$", ref)
end
def copy_gitattributes(ref) def copy_gitattributes(ref)
actual_ref = ref || root_ref actual_ref = ref || root_ref
begin begin
......
...@@ -1017,6 +1017,10 @@ module Gitlab ...@@ -1017,6 +1017,10 @@ module Gitlab
gitaly_repository_client.search_files_by_name(ref, safe_query) gitaly_repository_client.search_files_by_name(ref, safe_query)
end end
def search_files_by_regexp(filter, ref = 'HEAD')
gitaly_repository_client.search_files_by_regexp(ref, filter)
end
def find_commits_by_message(query, ref, path, limit, offset) def find_commits_by_message(query, ref, path, limit, offset)
wrapped_gitaly_errors do wrapped_gitaly_errors do
gitaly_commit_client gitaly_commit_client
......
...@@ -339,6 +339,11 @@ module Gitlab ...@@ -339,6 +339,11 @@ module Gitlab
search_results_from_response(response, options) search_results_from_response(response, options)
end end
def search_files_by_regexp(ref, filter)
request = Gitaly::SearchFilesByNameRequest.new(repository: @gitaly_repo, ref: ref, query: '.', filter: filter)
GitalyClient.call(@storage, :repository_service, :search_files_by_name, request, timeout: GitalyClient.fast_timeout).flat_map(&:files)
end
def disconnect_alternates def disconnect_alternates
request = Gitaly::DisconnectGitAlternatesRequest.new( request = Gitaly::DisconnectGitAlternatesRequest.new(
repository: @gitaly_repo repository: @gitaly_repo
......
...@@ -564,6 +564,41 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do ...@@ -564,6 +564,41 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
end end
end end
describe '#search_files_by_regexp' do
let(:ref) { 'master' }
subject(:result) { mutable_repository.search_files_by_regexp(filter, ref) }
context 'when sending a valid regexp' do
let(:filter) { 'files\/.*\/.*\.rb' }
it 'returns matched files' do
expect(result).to contain_exactly('files/links/regex.rb',
'files/ruby/popen.rb',
'files/ruby/regex.rb',
'files/ruby/version_info.rb')
end
end
context 'when sending an ivalid regexp' do
let(:filter) { '*.rb' }
it 'raises error' do
expect { result }.to raise_error(GRPC::InvalidArgument,
/missing argument to repetition operator: `*`/)
end
end
context "when the ref doesn't exist" do
let(:filter) { 'files\/.*\/.*\.rb' }
let(:ref) { 'non-existing-branch' }
it 'returns an empty array' do
expect(result).to eq([])
end
end
end
describe '#find_remote_root_ref' do describe '#find_remote_root_ref' do
it 'gets the remote root ref from GitalyClient' do it 'gets the remote root ref from GitalyClient' do
expect_any_instance_of(Gitlab::GitalyClient::RemoteService) expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
......
...@@ -246,6 +246,21 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do ...@@ -246,6 +246,21 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
end end
end end
describe '#search_files_by_regexp' do
subject(:result) { client.search_files_by_regexp('master', '.*') }
before do
expect_any_instance_of(Gitaly::RepositoryService::Stub)
.to receive(:search_files_by_name)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_return([double(files: ['file1.txt']), double(files: ['file2.txt'])])
end
it 'sends a search_files_by_name message and returns a flatten array' do
expect(result).to contain_exactly('file1.txt', 'file2.txt')
end
end
describe '#disconnect_alternates' do describe '#disconnect_alternates' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:repository) { project.repository } let(:repository) { project.repository }
......
...@@ -977,6 +977,57 @@ RSpec.describe Repository do ...@@ -977,6 +977,57 @@ RSpec.describe Repository do
end end
end end
describe '#search_files_by_wildcard_path' do
let(:ref) { 'master' }
subject(:result) { repository.search_files_by_wildcard_path(path, ref) }
context 'when specifying a normal path' do
let(:path) { 'files/images/logo-black.png' }
it 'returns the path' do
expect(result).to eq(['files/images/logo-black.png'])
end
end
context 'when specifying a path with wildcard' do
let(:path) { 'files/*/*.png' }
it 'returns all files matching the path' do
expect(result).to contain_exactly('files/images/logo-black.png',
'files/images/logo-white.png')
end
end
context 'when specifying an extension with wildcard' do
let(:path) { '*.rb' }
it 'returns all files matching the extension' do
expect(result).to contain_exactly('encoding/russian.rb',
'files/ruby/popen.rb',
'files/ruby/regex.rb',
'files/ruby/version_info.rb')
end
end
context 'when sending regexp' do
let(:path) { '.*\.rb' }
it 'ignores the regexp and returns an empty array' do
expect(result).to eq([])
end
end
context 'when sending another ref' do
let(:path) { 'files' }
let(:ref) { 'other-branch' }
it 'returns an empty array' do
expect(result).to eq([])
end
end
end
describe '#async_remove_remote' do describe '#async_remove_remote' do
before do before do
masterrev = repository.find_branch('master').dereferenced_target masterrev = repository.find_branch('master').dereferenced_target
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment