Skip to content

Commit 818dc53

Browse files
committed
feat(search): support code search by zoekt
Signed-off-by: ZheNing Hu <[email protected]>
1 parent 1e777f9 commit 818dc53

File tree

13 files changed

+756
-6
lines changed

13 files changed

+756
-6
lines changed

assets/go-licenses.json

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

custom/conf/app.example.ini

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,10 +1527,10 @@ LEVEL = Info
15271527
;; If empty then it defaults to `sources` only, as if you'd like to disable fully please see REPO_INDEXER_ENABLED.
15281528
;REPO_INDEXER_REPO_TYPES = sources,forks,mirrors,templates
15291529
;;
1530-
;; Code search engine type, could be `bleve` or `elasticsearch`.
1530+
;; Code search engine type, could be `bleve`, `zoekt` or `elasticsearch`.
15311531
;REPO_INDEXER_TYPE = bleve
15321532
;;
1533-
;; Index file used for code search. available when `REPO_INDEXER_TYPE` is bleve
1533+
;; Index file used for code search. available when `REPO_INDEXER_TYPE` is bleve or zoekt
15341534
;REPO_INDEXER_PATH = indexers/repos.bleve
15351535
;;
15361536
;; Code indexer connection string, available when `REPO_INDEXER_TYPE` is elasticsearch. i.e. http://elastic:changeme@localhost:9200
@@ -1540,10 +1540,10 @@ LEVEL = Info
15401540
;REPO_INDEXER_NAME = gitea_codes
15411541
;;
15421542
;; A comma separated list of glob patterns (see https://github.com/gobwas/glob) to include
1543-
;; in the index; default is empty
1543+
;; in the index; it's not compatible with the `zoekt` indexer type; default is empty
15441544
;REPO_INDEXER_INCLUDE =
15451545
;;
1546-
;; A comma separated list of glob patterns to exclude from the index; ; default is empty
1546+
;; A comma separated list of glob patterns to exclude from the index; it's not compatible with the `zoekt` indexer type; default is empty
15471547
;REPO_INDEXER_EXCLUDE =
15481548
;;
15491549
;MAX_FILE_SIZE = 1048576

go.mod

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ require (
104104
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
105105
github.com/sassoftware/go-rpmutils v0.4.0
106106
github.com/sergi/go-diff v1.4.0
107+
github.com/sourcegraph/zoekt v0.0.0-20251202141441-886b229dcd5e
107108
github.com/stretchr/testify v1.11.1
108109
github.com/syndtr/goleveldb v1.0.0
109110
github.com/tstranex/u2f v1.0.0
@@ -143,6 +144,7 @@ require (
143144
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
144145
github.com/DataDog/zstd v1.5.7 // indirect
145146
github.com/Microsoft/go-winio v0.6.2 // indirect
147+
github.com/RoaringBitmap/roaring v1.9.4 // indirect
146148
github.com/RoaringBitmap/roaring/v2 v2.10.0 // indirect
147149
github.com/STARRY-S/zip v0.2.3 // indirect
148150
github.com/andybalholm/brotli v1.2.0 // indirect
@@ -172,6 +174,7 @@ require (
172174
github.com/blevesearch/zapx/v14 v14.4.2 // indirect
173175
github.com/blevesearch/zapx/v15 v15.4.2 // indirect
174176
github.com/blevesearch/zapx/v16 v16.2.4 // indirect
177+
github.com/bmatcuk/doublestar v1.3.4 // indirect
175178
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
176179
github.com/bodgit/plumbing v1.3.0 // indirect
177180
github.com/bodgit/sevenzip v1.6.1 // indirect
@@ -215,6 +218,8 @@ require (
215218
github.com/gorilla/css v1.0.1 // indirect
216219
github.com/gorilla/mux v1.8.1 // indirect
217220
github.com/gorilla/securecookie v1.1.2 // indirect
221+
github.com/grafana/regexp v0.0.0-20240607082908-2cb410fa05da // indirect
222+
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
218223
github.com/hashicorp/errwrap v1.1.0 // indirect
219224
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
220225
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -248,6 +253,7 @@ require (
248253
github.com/olekukonko/ll v0.1.0 // indirect
249254
github.com/olekukonko/tablewriter v1.0.9 // indirect
250255
github.com/onsi/ginkgo v1.16.5 // indirect
256+
github.com/opentracing/opentracing-go v1.2.0 // indirect
251257
github.com/philhofer/fwd v1.2.0 // indirect
252258
github.com/pierrec/lz4/v4 v4.1.22 // indirect
253259
github.com/pjbgf/sha1cd v0.4.0 // indirect
@@ -262,6 +268,7 @@ require (
262268
github.com/sirupsen/logrus v1.9.3 // indirect
263269
github.com/skeema/knownhosts v1.3.1 // indirect
264270
github.com/sorairolake/lzip-go v0.3.8 // indirect
271+
github.com/sourcegraph/go-ctags v0.0.0-20250729094530-349a251d78d8 // indirect
265272
github.com/spf13/afero v1.15.0 // indirect
266273
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
267274
github.com/tinylib/msgp v1.4.0 // indirect

go.sum

Lines changed: 97 additions & 1 deletion
Large diffs are not rendered by default.

modules/indexer/code/git.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ func getRepoChanges(ctx context.Context, repo *repo_model.Repository, revision s
3939
needGenesis = len(stdout) == 0
4040
}
4141

42+
// TODO: check if zoekt index file meta status is not sync with db index status, if not, get genesis changes
43+
//if setting.Indexer.RepoType == "zoekt" {
44+
//}
45+
4246
if needGenesis {
4347
return genesisChanges(ctx, repo, revision)
4448
}

modules/indexer/code/indexer.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"code.gitea.io/gitea/modules/indexer/code/bleve"
1919
"code.gitea.io/gitea/modules/indexer/code/elasticsearch"
2020
"code.gitea.io/gitea/modules/indexer/code/internal"
21+
"code.gitea.io/gitea/modules/indexer/code/zoekt"
2122
"code.gitea.io/gitea/modules/log"
2223
"code.gitea.io/gitea/modules/process"
2324
"code.gitea.io/gitea/modules/queue"
@@ -117,7 +118,7 @@ func Init() {
117118

118119
// Create the Queue
119120
switch setting.Indexer.RepoType {
120-
case "bleve", "elasticsearch":
121+
case "bleve", "elasticsearch", "zoekt":
121122
handler := func(items ...*internal.IndexerData) (unhandled []*internal.IndexerData) {
122123
indexer := *globalIndexer.Load()
123124
for _, indexerData := range items {
@@ -184,6 +185,25 @@ func Init() {
184185
close(waitChannel)
185186
log.Fatal("PID: %d Unable to initialize the elasticsearch Repository Indexer connstr: %s Error: %v", os.Getpid(), util.SanitizeCredentialURLs(setting.Indexer.RepoConnStr), err)
186187
}
188+
case "zoekt":
189+
log.Info("PID: %d Initializing Repository Indexer at: %s", os.Getpid(), setting.Indexer.RepoPath)
190+
defer func() {
191+
if err := recover(); err != nil {
192+
log.Error("PANIC whilst initializing repository indexer: %v\nStacktrace: %s", err, log.Stack(2))
193+
log.Error("The indexer files are likely corrupted and may need to be deleted")
194+
log.Error("You can completely remove the \"%s\" directory to make Gitea recreate the indexes", setting.Indexer.RepoPath)
195+
}
196+
}()
197+
198+
rIndexer = zoekt.NewIndexer(setting.Indexer.RepoPath)
199+
existed, err = rIndexer.Init(ctx)
200+
if err != nil {
201+
cancel()
202+
(*globalIndexer.Load()).Close()
203+
close(waitChannel)
204+
205+
log.Fatal("PID: %d Unable to initialize the zoekt Repository Indexer at path: %s Error: %v", os.Getpid(), setting.Indexer.RepoPath, err)
206+
}
187207

188208
default:
189209
log.Fatal("PID: %d Unknown Indexer type: %s", os.Getpid(), setting.Indexer.RepoType)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package zoekt
5+
6+
import "unicode/utf8"
7+
8+
// Bitmap used by func special to check whether a character needs to be escaped.
9+
var specialBytes [16]byte
10+
11+
// special reports whether byte b needs to be escaped by QuoteMeta.
12+
func special(b byte) bool {
13+
return b < utf8.RuneSelf && specialBytes[b%16]&(1<<(b/16)) != 0
14+
}
15+
16+
func init() {
17+
for _, b := range []byte(`-:\.+*?()|[]{}^$`) {
18+
specialBytes[b%16] |= 1 << (b / 16)
19+
}
20+
}
21+
22+
func QuoteMeta(s string) string {
23+
// A byte loop is correct because all metacharacters are ASCII.
24+
var i int
25+
for i = 0; i < len(s); i++ {
26+
if special(s[i]) {
27+
break
28+
}
29+
}
30+
// No meta characters found, so return original string.
31+
if i >= len(s) {
32+
return s
33+
}
34+
35+
b := make([]byte, 3*len(s)-2*i)
36+
copy(b, s[:i])
37+
j := i
38+
for ; i < len(s); i++ {
39+
if special(s[i]) {
40+
b[j] = '\\'
41+
j++
42+
b[j] = '\\'
43+
j++
44+
}
45+
b[j] = s[i]
46+
j++
47+
}
48+
return string(b[:j])
49+
}

0 commit comments

Comments
 (0)