[FEAT] add fallback repo search using git grep

This commit is contained in:
Shiny Nematoda 2024-02-20 11:05:42 +00:00
parent 0533022d63
commit 51fb6f3983
6 changed files with 246 additions and 63 deletions

View file

@ -0,0 +1,90 @@
package files
import (
"context"
"html/template"
"strconv"
"strings"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/timeutil"
"github.com/go-enry/go-enry/v2"
)
type Result struct {
RepoID int64 // ignored
Filename string
CommitID string // branch
UpdatedUnix timeutil.TimeStamp // ignored
Language string
Color string
LineNumbers []int64
FormattedLines template.HTML
}
const pHEAD = "HEAD:"
func NewRepoGrep(ctx context.Context, repo *repo_model.Repository, keyword string) ([]*Result, error) {
t, _, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo)
if err != nil {
return nil, err
}
data := []*Result{}
stdout, _, err := git.NewCommand(ctx,
"grep",
"-1", // n before and after lines
"-z",
"--heading",
"--break", // easier parsing
"--fixed-strings", // disallow regex for now
"-n", // line nums
"-i", // ignore case
"--full-name", // full file path, rel to repo
//"--column", // for adding better highlighting support
).
AddDynamicArguments(keyword).
AddArguments("HEAD").
RunStdString(&git.RunOpts{Dir: t.Path})
if err != nil {
return data, nil // non zero exit code when there are no results
}
for _, block := range strings.Split(stdout, "\n\n") {
res := Result{CommitID: repo.DefaultBranch}
code := []string{}
for _, line := range strings.Split(block, "\n") {
if strings.HasPrefix(line, pHEAD) {
res.Filename = strings.TrimPrefix(line, pHEAD)
continue
}
if ln, after, ok := strings.Cut(line, "\x00"); ok {
i, err := strconv.ParseInt(ln, 10, 64)
if err != nil {
continue
}
res.LineNumbers = append(res.LineNumbers, i)
code = append(code, after)
}
}
if res.Filename == "" || len(code) == 0 || len(res.LineNumbers) == 0 {
continue
}
res.FormattedLines, res.Language = highlight.Code(res.Filename, "", strings.Join(code, "\n"))
res.Color = enry.GetColor(res.Language)
data = append(data, &res)
}
return data, nil
}

View file

@ -0,0 +1,48 @@
package files
import (
"testing"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/contexttest"
"github.com/stretchr/testify/assert"
)
func TestNewRepoGrep(t *testing.T) {
unittest.PrepareTestEnv(t)
ctx, _ := contexttest.MockContext(t, "user2/repo1")
ctx.SetParams(":id", "1")
contexttest.LoadRepo(t, ctx, 1)
contexttest.LoadRepoCommit(t, ctx)
contexttest.LoadUser(t, ctx, 2)
contexttest.LoadGitRepo(t, ctx)
defer ctx.Repo.GitRepo.Close()
t.Run("with result", func(t *testing.T) {
res, err := NewRepoGrep(ctx, ctx.Repo.Repository, "Description")
assert.NoError(t, err)
expected := []*Result{
{
RepoID: 0,
Filename: "README.md",
CommitID: "master",
UpdatedUnix: 0,
Language: "Markdown",
Color: "#083fa1",
LineNumbers: []int64{2, 3},
FormattedLines: "\nDescription for repo1",
},
}
assert.EqualValues(t, res, expected)
})
t.Run("empty result", func(t *testing.T) {
res, err := NewRepoGrep(ctx, ctx.Repo.Repository, "keyword that does not match in the repo")
assert.NoError(t, err)
assert.EqualValues(t, res, []*Result{})
})
}