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
raw_repository.search_files_by_name(query, ref)
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)
actual_ref = ref || root_ref
begin
......
......@@ -1017,6 +1017,10 @@ module Gitlab
gitaly_repository_client.search_files_by_name(ref, safe_query)
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)
wrapped_gitaly_errors do
gitaly_commit_client
......
......@@ -339,6 +339,11 @@ module Gitlab
search_results_from_response(response, options)
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
request = Gitaly::DisconnectGitAlternatesRequest.new(
repository: @gitaly_repo
......
......@@ -564,6 +564,41 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
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
it 'gets the remote root ref from GitalyClient' do
expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
......
......@@ -246,6 +246,21 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do
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
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
......
......@@ -977,6 +977,57 @@ RSpec.describe Repository do
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
before do
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