Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
4.5 KiB
194 lines
4.5 KiB
// Copyright 2018 The Gitea Authors. All rights reserved. |
|
// Use of this source code is governed by a MIT-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package issues |
|
|
|
import ( |
|
"fmt" |
|
|
|
"code.gitea.io/gitea/models" |
|
"code.gitea.io/gitea/modules/log" |
|
"code.gitea.io/gitea/modules/setting" |
|
"code.gitea.io/gitea/modules/util" |
|
) |
|
|
|
// IndexerData data stored in the issue indexer |
|
type IndexerData struct { |
|
ID int64 |
|
RepoID int64 |
|
Title string |
|
Content string |
|
Comments []string |
|
IsDelete bool |
|
IDs []int64 |
|
} |
|
|
|
// Match represents on search result |
|
type Match struct { |
|
ID int64 `json:"id"` |
|
RepoID int64 `json:"repo_id"` |
|
Score float64 `json:"score"` |
|
} |
|
|
|
// SearchResult represents search results |
|
type SearchResult struct { |
|
Total int64 |
|
Hits []Match |
|
} |
|
|
|
// Indexer defines an inteface to indexer issues contents |
|
type Indexer interface { |
|
Init() (bool, error) |
|
Index(issue []*IndexerData) error |
|
Delete(ids ...int64) error |
|
Search(kw string, repoID int64, limit, start int) (*SearchResult, error) |
|
} |
|
|
|
var ( |
|
// issueIndexerUpdateQueue queue of issue ids to be updated |
|
issueIndexerUpdateQueue Queue |
|
issueIndexer Indexer |
|
) |
|
|
|
// InitIssueIndexer initialize issue indexer, syncReindex is true then reindex until |
|
// all issue index done. |
|
func InitIssueIndexer(syncReindex bool) error { |
|
var populate bool |
|
var dummyQueue bool |
|
switch setting.Indexer.IssueType { |
|
case "bleve": |
|
issueIndexer = NewBleveIndexer(setting.Indexer.IssuePath) |
|
exist, err := issueIndexer.Init() |
|
if err != nil { |
|
return err |
|
} |
|
populate = !exist |
|
case "db": |
|
issueIndexer = &DBIndexer{} |
|
dummyQueue = true |
|
default: |
|
return fmt.Errorf("unknow issue indexer type: %s", setting.Indexer.IssueType) |
|
} |
|
|
|
if dummyQueue { |
|
issueIndexerUpdateQueue = &DummyQueue{} |
|
return nil |
|
} |
|
|
|
var err error |
|
switch setting.Indexer.IssueIndexerQueueType { |
|
case setting.LevelQueueType: |
|
issueIndexerUpdateQueue, err = NewLevelQueue( |
|
issueIndexer, |
|
setting.Indexer.IssueIndexerQueueDir, |
|
setting.Indexer.IssueIndexerQueueBatchNumber) |
|
if err != nil { |
|
return err |
|
} |
|
case setting.ChannelQueueType: |
|
issueIndexerUpdateQueue = NewChannelQueue(issueIndexer, setting.Indexer.IssueIndexerQueueBatchNumber) |
|
default: |
|
return fmt.Errorf("Unsupported indexer queue type: %v", setting.Indexer.IssueIndexerQueueType) |
|
} |
|
|
|
go issueIndexerUpdateQueue.Run() |
|
|
|
if populate { |
|
if syncReindex { |
|
populateIssueIndexer() |
|
} else { |
|
go populateIssueIndexer() |
|
} |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// populateIssueIndexer populate the issue indexer with issue data |
|
func populateIssueIndexer() { |
|
for page := 1; ; page++ { |
|
repos, _, err := models.SearchRepositoryByName(&models.SearchRepoOptions{ |
|
Page: page, |
|
PageSize: models.RepositoryListDefaultPageSize, |
|
OrderBy: models.SearchOrderByID, |
|
Private: true, |
|
Collaborate: util.OptionalBoolFalse, |
|
}) |
|
if err != nil { |
|
log.Error(4, "SearchRepositoryByName: %v", err) |
|
continue |
|
} |
|
if len(repos) == 0 { |
|
return |
|
} |
|
|
|
for _, repo := range repos { |
|
is, err := models.Issues(&models.IssuesOptions{ |
|
RepoIDs: []int64{repo.ID}, |
|
IsClosed: util.OptionalBoolNone, |
|
IsPull: util.OptionalBoolNone, |
|
}) |
|
if err != nil { |
|
log.Error(4, "Issues: %v", err) |
|
continue |
|
} |
|
if err = models.IssueList(is).LoadDiscussComments(); err != nil { |
|
log.Error(4, "LoadComments: %v", err) |
|
continue |
|
} |
|
for _, issue := range is { |
|
UpdateIssueIndexer(issue) |
|
} |
|
} |
|
} |
|
} |
|
|
|
// UpdateIssueIndexer add/update an issue to the issue indexer |
|
func UpdateIssueIndexer(issue *models.Issue) { |
|
var comments []string |
|
for _, comment := range issue.Comments { |
|
if comment.Type == models.CommentTypeComment { |
|
comments = append(comments, comment.Content) |
|
} |
|
} |
|
issueIndexerUpdateQueue.Push(&IndexerData{ |
|
ID: issue.ID, |
|
RepoID: issue.RepoID, |
|
Title: issue.Title, |
|
Content: issue.Content, |
|
Comments: comments, |
|
}) |
|
} |
|
|
|
// DeleteRepoIssueIndexer deletes repo's all issues indexes |
|
func DeleteRepoIssueIndexer(repo *models.Repository) { |
|
var ids []int64 |
|
ids, err := models.GetIssueIDsByRepoID(repo.ID) |
|
if err != nil { |
|
log.Error(4, "getIssueIDsByRepoID failed: %v", err) |
|
return |
|
} |
|
|
|
if len(ids) <= 0 { |
|
return |
|
} |
|
|
|
issueIndexerUpdateQueue.Push(&IndexerData{ |
|
IDs: ids, |
|
IsDelete: true, |
|
}) |
|
} |
|
|
|
// SearchIssuesByKeyword search issue ids by keywords and repo id |
|
func SearchIssuesByKeyword(repoID int64, keyword string) ([]int64, error) { |
|
var issueIDs []int64 |
|
res, err := issueIndexer.Search(keyword, repoID, 1000, 0) |
|
if err != nil { |
|
return nil, err |
|
} |
|
for _, r := range res.Hits { |
|
issueIDs = append(issueIDs, r.ID) |
|
} |
|
return issueIDs, nil |
|
}
|
|
|