Commit d3d1e9ef authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'search-git-grep' into 'master'

Implement faster search of code (via git grep)

Much faster than iterating over each file using rugged.

Performance compare for Linux repository using keyword `sha`:

```
OLD: 250 seconds
NEW: 9 seconds
```

See merge request !957
parents f94587ec ed97b057
......@@ -43,6 +43,7 @@ v 7.13.0 (unreleased)
- Redesign project page. Show README as default instead of activity. Move project activity to separate page
- Make left menu more hierarchical and less contextual by adding back item at top
- A fork can’t have a visibility level that is greater than the original project.
- Faster code search in repository and wiki. Fixes search page timeout for big repositories
v 7.12.2
- Correctly show anonymous authorized applications under Profile > Applications.
......
......@@ -431,6 +431,40 @@ class Repository
end
end
def search_files(query, ref)
offset = 2
args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref})
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end
def parse_search_result(result)
ref = nil
filename = nil
startline = 0
lines = result.lines
lines.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
startline = startline.to_i - index
break
end
end
data = lines.map do |line|
line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
end
data = data.join("")
OpenStruct.new(
filename: filename,
ref: ref,
startline: startline,
data: data
)
end
private
def cache
......
- blob = @project.repository.parse_search_result(blob)
.blob-result
.file-holder
.file-title
......
- wiki_blob = @project.repository.parse_search_result(wiki_blob)
.blob-result
.file-holder
.file-title
......
......@@ -47,4 +47,28 @@ describe Repository do
it { is_expected.to be_falsey }
end
end
describe "search_files" do
let(:results) { repository.search_files('feature', 'master') }
subject { results }
it { is_expected.to be_an Array }
describe 'result' do
subject { results.first }
it { is_expected.to be_an String }
it { expect(subject.lines[2]).to eq("master:CHANGELOG:188: - Feature: Replace teams with group membership\n") }
end
describe 'parsing result' do
subject { repository.parse_search_result(results.first) }
it { is_expected.to be_an OpenStruct }
it { expect(subject.filename).to eq('CHANGELOG') }
it { expect(subject.ref).to eq('master') }
it { expect(subject.startline).to eq(186) }
it { expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") }
end
end
end
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