mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-22 12:54:53 -05:00
Add generic set type (#21408)
This PR adds a generic set type to get rid of maps used as sets. Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
e84558b093
commit
0e57ff7eee
41 changed files with 328 additions and 324 deletions
|
@ -18,13 +18,11 @@ import (
|
||||||
type ActionList []*Action
|
type ActionList []*Action
|
||||||
|
|
||||||
func (actions ActionList) getUserIDs() []int64 {
|
func (actions ActionList) getUserIDs() []int64 {
|
||||||
userIDs := make(map[int64]struct{}, len(actions))
|
userIDs := make(container.Set[int64], len(actions))
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
if _, ok := userIDs[action.ActUserID]; !ok {
|
userIDs.Add(action.ActUserID)
|
||||||
userIDs[action.ActUserID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(userIDs)
|
return userIDs.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (actions ActionList) loadUsers(ctx context.Context) (map[int64]*user_model.User, error) {
|
func (actions ActionList) loadUsers(ctx context.Context) (map[int64]*user_model.User, error) {
|
||||||
|
@ -48,13 +46,11 @@ func (actions ActionList) loadUsers(ctx context.Context) (map[int64]*user_model.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (actions ActionList) getRepoIDs() []int64 {
|
func (actions ActionList) getRepoIDs() []int64 {
|
||||||
repoIDs := make(map[int64]struct{}, len(actions))
|
repoIDs := make(container.Set[int64], len(actions))
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
if _, ok := repoIDs[action.RepoID]; !ok {
|
repoIDs.Add(action.RepoID)
|
||||||
repoIDs[action.RepoID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(repoIDs)
|
return repoIDs.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (actions ActionList) loadRepositories(ctx context.Context) error {
|
func (actions ActionList) loadRepositories(ctx context.Context) error {
|
||||||
|
|
|
@ -200,7 +200,7 @@ func CreateOrUpdateIssueNotifications(issueID, commentID, notificationAuthorID,
|
||||||
|
|
||||||
func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
|
func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
|
||||||
// init
|
// init
|
||||||
var toNotify map[int64]struct{}
|
var toNotify container.Set[int64]
|
||||||
notifications, err := getNotificationsByIssueID(ctx, issueID)
|
notifications, err := getNotificationsByIssueID(ctx, issueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -212,33 +212,27 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
|
||||||
}
|
}
|
||||||
|
|
||||||
if receiverID > 0 {
|
if receiverID > 0 {
|
||||||
toNotify = make(map[int64]struct{}, 1)
|
toNotify = make(container.Set[int64], 1)
|
||||||
toNotify[receiverID] = struct{}{}
|
toNotify.Add(receiverID)
|
||||||
} else {
|
} else {
|
||||||
toNotify = make(map[int64]struct{}, 32)
|
toNotify = make(container.Set[int64], 32)
|
||||||
issueWatches, err := issues_model.GetIssueWatchersIDs(ctx, issueID, true)
|
issueWatches, err := issues_model.GetIssueWatchersIDs(ctx, issueID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, id := range issueWatches {
|
toNotify.AddMultiple(issueWatches...)
|
||||||
toNotify[id] = struct{}{}
|
|
||||||
}
|
|
||||||
if !(issue.IsPull && issues_model.HasWorkInProgressPrefix(issue.Title)) {
|
if !(issue.IsPull && issues_model.HasWorkInProgressPrefix(issue.Title)) {
|
||||||
repoWatches, err := repo_model.GetRepoWatchersIDs(ctx, issue.RepoID)
|
repoWatches, err := repo_model.GetRepoWatchersIDs(ctx, issue.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, id := range repoWatches {
|
toNotify.AddMultiple(repoWatches...)
|
||||||
toNotify[id] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
issueParticipants, err := issue.GetParticipantIDsByIssue(ctx)
|
issueParticipants, err := issue.GetParticipantIDsByIssue(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, id := range issueParticipants {
|
toNotify.AddMultiple(issueParticipants...)
|
||||||
toNotify[id] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dont notify user who cause notification
|
// dont notify user who cause notification
|
||||||
delete(toNotify, notificationAuthorID)
|
delete(toNotify, notificationAuthorID)
|
||||||
|
@ -248,7 +242,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, id := range issueUnWatches {
|
for _, id := range issueUnWatches {
|
||||||
delete(toNotify, id)
|
toNotify.Remove(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,16 +493,14 @@ func (nl NotificationList) LoadAttributes() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nl NotificationList) getPendingRepoIDs() []int64 {
|
func (nl NotificationList) getPendingRepoIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(nl))
|
ids := make(container.Set[int64], len(nl))
|
||||||
for _, notification := range nl {
|
for _, notification := range nl {
|
||||||
if notification.Repository != nil {
|
if notification.Repository != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := ids[notification.RepoID]; !ok {
|
ids.Add(notification.RepoID)
|
||||||
ids[notification.RepoID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadRepos loads repositories from database
|
// LoadRepos loads repositories from database
|
||||||
|
@ -575,16 +567,14 @@ func (nl NotificationList) LoadRepos() (repo_model.RepositoryList, []int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nl NotificationList) getPendingIssueIDs() []int64 {
|
func (nl NotificationList) getPendingIssueIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(nl))
|
ids := make(container.Set[int64], len(nl))
|
||||||
for _, notification := range nl {
|
for _, notification := range nl {
|
||||||
if notification.Issue != nil {
|
if notification.Issue != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := ids[notification.IssueID]; !ok {
|
ids.Add(notification.IssueID)
|
||||||
ids[notification.IssueID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadIssues loads issues from database
|
// LoadIssues loads issues from database
|
||||||
|
@ -661,16 +651,14 @@ func (nl NotificationList) Without(failures []int) NotificationList {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nl NotificationList) getPendingCommentIDs() []int64 {
|
func (nl NotificationList) getPendingCommentIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(nl))
|
ids := make(container.Set[int64], len(nl))
|
||||||
for _, notification := range nl {
|
for _, notification := range nl {
|
||||||
if notification.CommentID == 0 || notification.Comment != nil {
|
if notification.CommentID == 0 || notification.Comment != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := ids[notification.CommentID]; !ok {
|
ids.Add(notification.CommentID)
|
||||||
ids[notification.CommentID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadComments loads comments from database
|
// LoadComments loads comments from database
|
||||||
|
|
|
@ -17,13 +17,11 @@ import (
|
||||||
type CommentList []*Comment
|
type CommentList []*Comment
|
||||||
|
|
||||||
func (comments CommentList) getPosterIDs() []int64 {
|
func (comments CommentList) getPosterIDs() []int64 {
|
||||||
posterIDs := make(map[int64]struct{}, len(comments))
|
posterIDs := make(container.Set[int64], len(comments))
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if _, ok := posterIDs[comment.PosterID]; !ok {
|
posterIDs.Add(comment.PosterID)
|
||||||
posterIDs[comment.PosterID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(posterIDs)
|
return posterIDs.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) loadPosters(ctx context.Context) error {
|
func (comments CommentList) loadPosters(ctx context.Context) error {
|
||||||
|
@ -70,13 +68,11 @@ func (comments CommentList) getCommentIDs() []int64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) getLabelIDs() []int64 {
|
func (comments CommentList) getLabelIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(comments))
|
ids := make(container.Set[int64], len(comments))
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if _, ok := ids[comment.LabelID]; !ok {
|
ids.Add(comment.LabelID)
|
||||||
ids[comment.LabelID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) loadLabels(ctx context.Context) error { //nolint
|
func (comments CommentList) loadLabels(ctx context.Context) error { //nolint
|
||||||
|
@ -120,13 +116,11 @@ func (comments CommentList) loadLabels(ctx context.Context) error { //nolint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) getMilestoneIDs() []int64 {
|
func (comments CommentList) getMilestoneIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(comments))
|
ids := make(container.Set[int64], len(comments))
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if _, ok := ids[comment.MilestoneID]; !ok {
|
ids.Add(comment.MilestoneID)
|
||||||
ids[comment.MilestoneID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) loadMilestones(ctx context.Context) error {
|
func (comments CommentList) loadMilestones(ctx context.Context) error {
|
||||||
|
@ -163,13 +157,11 @@ func (comments CommentList) loadMilestones(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) getOldMilestoneIDs() []int64 {
|
func (comments CommentList) getOldMilestoneIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(comments))
|
ids := make(container.Set[int64], len(comments))
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if _, ok := ids[comment.OldMilestoneID]; !ok {
|
ids.Add(comment.OldMilestoneID)
|
||||||
ids[comment.OldMilestoneID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) loadOldMilestones(ctx context.Context) error {
|
func (comments CommentList) loadOldMilestones(ctx context.Context) error {
|
||||||
|
@ -206,13 +198,11 @@ func (comments CommentList) loadOldMilestones(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) getAssigneeIDs() []int64 {
|
func (comments CommentList) getAssigneeIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(comments))
|
ids := make(container.Set[int64], len(comments))
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if _, ok := ids[comment.AssigneeID]; !ok {
|
ids.Add(comment.AssigneeID)
|
||||||
ids[comment.AssigneeID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) loadAssignees(ctx context.Context) error {
|
func (comments CommentList) loadAssignees(ctx context.Context) error {
|
||||||
|
@ -259,16 +249,14 @@ func (comments CommentList) loadAssignees(ctx context.Context) error {
|
||||||
|
|
||||||
// getIssueIDs returns all the issue ids on this comment list which issue hasn't been loaded
|
// getIssueIDs returns all the issue ids on this comment list which issue hasn't been loaded
|
||||||
func (comments CommentList) getIssueIDs() []int64 {
|
func (comments CommentList) getIssueIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(comments))
|
ids := make(container.Set[int64], len(comments))
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if comment.Issue != nil {
|
if comment.Issue != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := ids[comment.IssueID]; !ok {
|
ids.Add(comment.IssueID)
|
||||||
ids[comment.IssueID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issues returns all the issues of comments
|
// Issues returns all the issues of comments
|
||||||
|
@ -334,16 +322,14 @@ func (comments CommentList) loadIssues(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) getDependentIssueIDs() []int64 {
|
func (comments CommentList) getDependentIssueIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(comments))
|
ids := make(container.Set[int64], len(comments))
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if comment.DependentIssue != nil {
|
if comment.DependentIssue != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := ids[comment.DependentIssueID]; !ok {
|
ids.Add(comment.DependentIssueID)
|
||||||
ids[comment.DependentIssueID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) loadDependentIssues(ctx context.Context) error {
|
func (comments CommentList) loadDependentIssues(ctx context.Context) error {
|
||||||
|
@ -439,13 +425,11 @@ func (comments CommentList) loadAttachments(ctx context.Context) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) getReviewIDs() []int64 {
|
func (comments CommentList) getReviewIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(comments))
|
ids := make(container.Set[int64], len(comments))
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
if _, ok := ids[comment.ReviewID]; !ok {
|
ids.Add(comment.ReviewID)
|
||||||
ids[comment.ReviewID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (comments CommentList) loadReviews(ctx context.Context) error { //nolint
|
func (comments CommentList) loadReviews(ctx context.Context) error { //nolint
|
||||||
|
|
|
@ -22,16 +22,16 @@ type IssueList []*Issue
|
||||||
|
|
||||||
// get the repo IDs to be loaded later, these IDs are for issue.Repo and issue.PullRequest.HeadRepo
|
// get the repo IDs to be loaded later, these IDs are for issue.Repo and issue.PullRequest.HeadRepo
|
||||||
func (issues IssueList) getRepoIDs() []int64 {
|
func (issues IssueList) getRepoIDs() []int64 {
|
||||||
repoIDs := make(map[int64]struct{}, len(issues))
|
repoIDs := make(container.Set[int64], len(issues))
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
if issue.Repo == nil {
|
if issue.Repo == nil {
|
||||||
repoIDs[issue.RepoID] = struct{}{}
|
repoIDs.Add(issue.RepoID)
|
||||||
}
|
}
|
||||||
if issue.PullRequest != nil && issue.PullRequest.HeadRepo == nil {
|
if issue.PullRequest != nil && issue.PullRequest.HeadRepo == nil {
|
||||||
repoIDs[issue.PullRequest.HeadRepoID] = struct{}{}
|
repoIDs.Add(issue.PullRequest.HeadRepoID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return container.KeysInt64(repoIDs)
|
return repoIDs.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issues IssueList) loadRepositories(ctx context.Context) ([]*repo_model.Repository, error) {
|
func (issues IssueList) loadRepositories(ctx context.Context) ([]*repo_model.Repository, error) {
|
||||||
|
@ -79,13 +79,11 @@ func (issues IssueList) LoadRepositories() ([]*repo_model.Repository, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issues IssueList) getPosterIDs() []int64 {
|
func (issues IssueList) getPosterIDs() []int64 {
|
||||||
posterIDs := make(map[int64]struct{}, len(issues))
|
posterIDs := make(container.Set[int64], len(issues))
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
if _, ok := posterIDs[issue.PosterID]; !ok {
|
posterIDs.Add(issue.PosterID)
|
||||||
posterIDs[issue.PosterID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(posterIDs)
|
return posterIDs.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issues IssueList) loadPosters(ctx context.Context) error {
|
func (issues IssueList) loadPosters(ctx context.Context) error {
|
||||||
|
@ -185,13 +183,11 @@ func (issues IssueList) loadLabels(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issues IssueList) getMilestoneIDs() []int64 {
|
func (issues IssueList) getMilestoneIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(issues))
|
ids := make(container.Set[int64], len(issues))
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
if _, ok := ids[issue.MilestoneID]; !ok {
|
ids.Add(issue.MilestoneID)
|
||||||
ids[issue.MilestoneID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issues IssueList) loadMilestones(ctx context.Context) error {
|
func (issues IssueList) loadMilestones(ctx context.Context) error {
|
||||||
|
@ -224,14 +220,11 @@ func (issues IssueList) loadMilestones(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issues IssueList) getProjectIDs() []int64 {
|
func (issues IssueList) getProjectIDs() []int64 {
|
||||||
ids := make(map[int64]struct{}, len(issues))
|
ids := make(container.Set[int64], len(issues))
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
projectID := issue.ProjectID()
|
ids.Add(issue.ProjectID())
|
||||||
if _, ok := ids[projectID]; !ok {
|
|
||||||
ids[projectID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(ids)
|
return ids.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issues IssueList) loadProjects(ctx context.Context) error {
|
func (issues IssueList) loadProjects(ctx context.Context) error {
|
||||||
|
|
|
@ -211,7 +211,7 @@ type ReactionOptions struct {
|
||||||
|
|
||||||
// CreateReaction creates reaction for issue or comment.
|
// CreateReaction creates reaction for issue or comment.
|
||||||
func CreateReaction(opts *ReactionOptions) (*Reaction, error) {
|
func CreateReaction(opts *ReactionOptions) (*Reaction, error) {
|
||||||
if !setting.UI.ReactionsMap[opts.Type] {
|
if !setting.UI.ReactionsLookup.Contains(opts.Type) {
|
||||||
return nil, ErrForbiddenIssueReaction{opts.Type}
|
return nil, ErrForbiddenIssueReaction{opts.Type}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,16 +316,14 @@ func (list ReactionList) GroupByType() map[string]ReactionList {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list ReactionList) getUserIDs() []int64 {
|
func (list ReactionList) getUserIDs() []int64 {
|
||||||
userIDs := make(map[int64]struct{}, len(list))
|
userIDs := make(container.Set[int64], len(list))
|
||||||
for _, reaction := range list {
|
for _, reaction := range list {
|
||||||
if reaction.OriginalAuthor != "" {
|
if reaction.OriginalAuthor != "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := userIDs[reaction.UserID]; !ok {
|
userIDs.Add(reaction.UserID)
|
||||||
userIDs[reaction.UserID] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return container.KeysInt64(userIDs)
|
return userIDs.Values()
|
||||||
}
|
}
|
||||||
|
|
||||||
func valuesUser(m map[int64]*user_model.User) []*user_model.User {
|
func valuesUser(m map[int64]*user_model.User) []*user_model.User {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -99,9 +100,9 @@ func InsertIssueComments(comments []*issues_model.Comment) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
issueIDs := make(map[int64]bool)
|
issueIDs := make(container.Set[int64])
|
||||||
for _, comment := range comments {
|
for _, comment := range comments {
|
||||||
issueIDs[comment.IssueID] = true
|
issueIDs.Add(comment.IssueID)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext()
|
ctx, committer, err := db.TxContext()
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
@ -39,7 +40,7 @@ func renameExistingUserAvatarName(x *xorm.Engine) error {
|
||||||
}
|
}
|
||||||
log.Info("%d User Avatar(s) to migrate ...", count)
|
log.Info("%d User Avatar(s) to migrate ...", count)
|
||||||
|
|
||||||
deleteList := make(map[string]struct{})
|
deleteList := make(container.Set[string])
|
||||||
start := 0
|
start := 0
|
||||||
migrated := 0
|
migrated := 0
|
||||||
for {
|
for {
|
||||||
|
@ -86,7 +87,7 @@ func renameExistingUserAvatarName(x *xorm.Engine) error {
|
||||||
return fmt.Errorf("[user: %s] user table update: %v", user.LowerName, err)
|
return fmt.Errorf("[user: %s] user table update: %v", user.LowerName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteList[filepath.Join(setting.Avatar.Path, oldAvatar)] = struct{}{}
|
deleteList.Add(filepath.Join(setting.Avatar.Path, oldAvatar))
|
||||||
migrated++
|
migrated++
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/packages"
|
"code.gitea.io/gitea/models/packages"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
conan_module "code.gitea.io/gitea/modules/packages/conan"
|
conan_module "code.gitea.io/gitea/modules/packages/conan"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
|
@ -88,7 +89,7 @@ func SearchRecipes(ctx context.Context, opts *RecipeSearchOptions) ([]string, er
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
unique := make(map[string]bool)
|
unique := make(container.Set[string])
|
||||||
for _, info := range results {
|
for _, info := range results {
|
||||||
recipe := fmt.Sprintf("%s/%s", info.Name, info.Version)
|
recipe := fmt.Sprintf("%s/%s", info.Name, info.Version)
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ func SearchRecipes(ctx context.Context, opts *RecipeSearchOptions) ([]string, er
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unique[recipe] = true
|
unique.Add(recipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
recipes := make([]string, 0, len(unique))
|
recipes := make([]string, 0, len(unique))
|
||||||
|
|
|
@ -68,10 +68,10 @@ func (repos RepositoryList) loadAttributes(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
set := make(map[int64]struct{})
|
set := make(container.Set[int64])
|
||||||
repoIDs := make([]int64, len(repos))
|
repoIDs := make([]int64, len(repos))
|
||||||
for i := range repos {
|
for i := range repos {
|
||||||
set[repos[i].OwnerID] = struct{}{}
|
set.Add(repos[i].OwnerID)
|
||||||
repoIDs[i] = repos[i].ID
|
repoIDs[i] = repos[i].ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ func (repos RepositoryList) loadAttributes(ctx context.Context) error {
|
||||||
users := make(map[int64]*user_model.User, len(set))
|
users := make(map[int64]*user_model.User, len(set))
|
||||||
if err := db.GetEngine(ctx).
|
if err := db.GetEngine(ctx).
|
||||||
Where("id > 0").
|
Where("id > 0").
|
||||||
In("id", container.KeysInt64(set)).
|
In("id", set.Values()).
|
||||||
Find(&users); err != nil {
|
Find(&users); err != nil {
|
||||||
return fmt.Errorf("find users: %v", err)
|
return fmt.Errorf("find users: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
|
@ -62,7 +63,7 @@ func ValidateTopic(topic string) bool {
|
||||||
// SanitizeAndValidateTopics sanitizes and checks an array or topics
|
// SanitizeAndValidateTopics sanitizes and checks an array or topics
|
||||||
func SanitizeAndValidateTopics(topics []string) (validTopics, invalidTopics []string) {
|
func SanitizeAndValidateTopics(topics []string) (validTopics, invalidTopics []string) {
|
||||||
validTopics = make([]string, 0)
|
validTopics = make([]string, 0)
|
||||||
mValidTopics := make(map[string]struct{})
|
mValidTopics := make(container.Set[string])
|
||||||
invalidTopics = make([]string, 0)
|
invalidTopics = make([]string, 0)
|
||||||
|
|
||||||
for _, topic := range topics {
|
for _, topic := range topics {
|
||||||
|
@ -72,12 +73,12 @@ func SanitizeAndValidateTopics(topics []string) (validTopics, invalidTopics []st
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// ignore same topic twice
|
// ignore same topic twice
|
||||||
if _, ok := mValidTopics[topic]; ok {
|
if mValidTopics.Contains(topic) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ValidateTopic(topic) {
|
if ValidateTopic(topic) {
|
||||||
validTopics = append(validTopics, topic)
|
validTopics = append(validTopics, topic)
|
||||||
mValidTopics[topic] = struct{}{}
|
mValidTopics.Add(topic)
|
||||||
} else {
|
} else {
|
||||||
invalidTopics = append(invalidTopics, topic)
|
invalidTopics = append(invalidTopics, topic)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
|
@ -83,37 +84,19 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
uidMap := map[int64]bool{}
|
uniqueUserIDs := make(container.Set[int64])
|
||||||
i := 0
|
uniqueUserIDs.AddMultiple(userIDs...)
|
||||||
for _, uid := range userIDs {
|
uniqueUserIDs.AddMultiple(additionalUserIDs...)
|
||||||
if uidMap[uid] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
uidMap[uid] = true
|
|
||||||
userIDs[i] = uid
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
userIDs = userIDs[:i]
|
|
||||||
userIDs = append(userIDs, additionalUserIDs...)
|
|
||||||
|
|
||||||
for _, uid := range additionalUserIDs {
|
|
||||||
if uidMap[uid] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
userIDs[i] = uid
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
userIDs = userIDs[:i]
|
|
||||||
|
|
||||||
// Leave a seat for owner itself to append later, but if owner is an organization
|
// Leave a seat for owner itself to append later, but if owner is an organization
|
||||||
// and just waste 1 unit is cheaper than re-allocate memory once.
|
// and just waste 1 unit is cheaper than re-allocate memory once.
|
||||||
users := make([]*user_model.User, 0, len(userIDs)+1)
|
users := make([]*user_model.User, 0, len(uniqueUserIDs)+1)
|
||||||
if len(userIDs) > 0 {
|
if len(userIDs) > 0 {
|
||||||
if err = e.In("id", userIDs).OrderBy(user_model.GetOrderByName()).Find(&users); err != nil {
|
if err = e.In("id", uniqueUserIDs.Values()).OrderBy(user_model.GetOrderByName()).Find(&users); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !repo.Owner.IsOrganization() && !uidMap[repo.OwnerID] {
|
if !repo.Owner.IsOrganization() && !uniqueUserIDs.Contains(repo.OwnerID) {
|
||||||
users = append(users, repo.Owner)
|
users = append(users, repo.Owner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,15 +241,6 @@ func Int64sToStrings(ints []int64) []string {
|
||||||
return strs
|
return strs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int64sToMap converts a slice of int64 to a int64 map.
|
|
||||||
func Int64sToMap(ints []int64) map[int64]bool {
|
|
||||||
m := make(map[int64]bool)
|
|
||||||
for _, i := range ints {
|
|
||||||
m[i] = true
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int64sContains returns if a int64 in a slice of int64
|
// Int64sContains returns if a int64 in a slice of int64
|
||||||
func Int64sContains(intsSlice []int64, a int64) bool {
|
func Int64sContains(intsSlice []int64, a int64) bool {
|
||||||
for _, c := range intsSlice {
|
for _, c := range intsSlice {
|
||||||
|
|
|
@ -214,16 +214,7 @@ func TestInt64sToStrings(t *testing.T) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInt64sToMap(t *testing.T) {
|
|
||||||
assert.Equal(t, map[int64]bool{}, Int64sToMap([]int64{}))
|
|
||||||
assert.Equal(t,
|
|
||||||
map[int64]bool{1: true, 4: true, 16: true},
|
|
||||||
Int64sToMap([]int64{1, 4, 16}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInt64sContains(t *testing.T) {
|
func TestInt64sContains(t *testing.T) {
|
||||||
assert.Equal(t, map[int64]bool{}, Int64sToMap([]int64{}))
|
|
||||||
assert.True(t, Int64sContains([]int64{6, 44324, 4324, 32, 1, 2323}, 1))
|
assert.True(t, Int64sContains([]int64{6, 44324, 4324, 32, 1, 2323}, 1))
|
||||||
assert.True(t, Int64sContains([]int64{2323}, 2323))
|
assert.True(t, Int64sContains([]int64{2323}, 2323))
|
||||||
assert.False(t, Int64sContains([]int64{6, 44324, 4324, 32, 1, 2323}, 232))
|
assert.False(t, Int64sContains([]int64{6, 44324, 4324, 32, 1, 2323}, 232))
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright 2022 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 container
|
|
||||||
|
|
||||||
// KeysInt64 returns keys slice for a map with int64 key
|
|
||||||
func KeysInt64(m map[int64]struct{}) []int64 {
|
|
||||||
keys := make([]int64, 0, len(m))
|
|
||||||
for k := range m {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
return keys
|
|
||||||
}
|
|
57
modules/container/set.go
Normal file
57
modules/container/set.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright 2022 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 container
|
||||||
|
|
||||||
|
type Set[T comparable] map[T]struct{}
|
||||||
|
|
||||||
|
// SetOf creates a set and adds the specified elements to it.
|
||||||
|
func SetOf[T comparable](values ...T) Set[T] {
|
||||||
|
s := make(Set[T], len(values))
|
||||||
|
s.AddMultiple(values...)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds the specified element to a set.
|
||||||
|
// Returns true if the element is added; false if the element is already present.
|
||||||
|
func (s Set[T]) Add(value T) bool {
|
||||||
|
if _, has := s[value]; !has {
|
||||||
|
s[value] = struct{}{}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMultiple adds the specified elements to a set.
|
||||||
|
func (s Set[T]) AddMultiple(values ...T) {
|
||||||
|
for _, value := range values {
|
||||||
|
s.Add(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains determines whether a set contains the specified element.
|
||||||
|
// Returns true if the set contains the specified element; otherwise, false.
|
||||||
|
func (s Set[T]) Contains(value T) bool {
|
||||||
|
_, has := s[value]
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes the specified element.
|
||||||
|
// Returns true if the element is successfully found and removed; otherwise, false.
|
||||||
|
func (s Set[T]) Remove(value T) bool {
|
||||||
|
if _, has := s[value]; has {
|
||||||
|
delete(s, value)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values gets a list of all elements in the set.
|
||||||
|
func (s Set[T]) Values() []T {
|
||||||
|
keys := make([]T, 0, len(s))
|
||||||
|
for k := range s {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
37
modules/container/set_test.go
Normal file
37
modules/container/set_test.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2022 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 container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSet(t *testing.T) {
|
||||||
|
s := make(Set[string])
|
||||||
|
|
||||||
|
assert.True(t, s.Add("key1"))
|
||||||
|
assert.False(t, s.Add("key1"))
|
||||||
|
assert.True(t, s.Add("key2"))
|
||||||
|
|
||||||
|
assert.True(t, s.Contains("key1"))
|
||||||
|
assert.True(t, s.Contains("key2"))
|
||||||
|
assert.False(t, s.Contains("key3"))
|
||||||
|
|
||||||
|
assert.True(t, s.Remove("key2"))
|
||||||
|
assert.False(t, s.Contains("key2"))
|
||||||
|
|
||||||
|
assert.False(t, s.Remove("key3"))
|
||||||
|
|
||||||
|
s.AddMultiple("key4", "key5")
|
||||||
|
assert.True(t, s.Contains("key4"))
|
||||||
|
assert.True(t, s.Contains("key5"))
|
||||||
|
|
||||||
|
s = SetOf("key6", "key7")
|
||||||
|
assert.False(t, s.Contains("key1"))
|
||||||
|
assert.True(t, s.Contains("key6"))
|
||||||
|
assert.True(t, s.Contains("key7"))
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
@ -40,7 +41,7 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
linesInAuthorizedKeys := map[string]bool{}
|
linesInAuthorizedKeys := make(container.Set[string])
|
||||||
|
|
||||||
scanner := bufio.NewScanner(f)
|
scanner := bufio.NewScanner(f)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
|
@ -48,7 +49,7 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e
|
||||||
if strings.HasPrefix(line, tplCommentPrefix) {
|
if strings.HasPrefix(line, tplCommentPrefix) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
linesInAuthorizedKeys[line] = true
|
linesInAuthorizedKeys.Add(line)
|
||||||
}
|
}
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e
|
||||||
if strings.HasPrefix(line, tplCommentPrefix) {
|
if strings.HasPrefix(line, tplCommentPrefix) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ok := linesInAuthorizedKeys[line]; ok {
|
if linesInAuthorizedKeys.Contains(line) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !autofix {
|
if !autofix {
|
||||||
|
|
|
@ -14,6 +14,8 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
|
||||||
"github.com/djherbis/buffer"
|
"github.com/djherbis/buffer"
|
||||||
"github.com/djherbis/nio/v3"
|
"github.com/djherbis/nio/v3"
|
||||||
)
|
)
|
||||||
|
@ -339,7 +341,7 @@ func WalkGitLog(ctx context.Context, repo *Repository, head *Commit, treepath st
|
||||||
lastEmptyParent := head.ID.String()
|
lastEmptyParent := head.ID.String()
|
||||||
commitSinceLastEmptyParent := uint64(0)
|
commitSinceLastEmptyParent := uint64(0)
|
||||||
commitSinceNextRestart := uint64(0)
|
commitSinceNextRestart := uint64(0)
|
||||||
parentRemaining := map[string]bool{}
|
parentRemaining := make(container.Set[string])
|
||||||
|
|
||||||
changed := make([]bool, len(paths))
|
changed := make([]bool, len(paths))
|
||||||
|
|
||||||
|
@ -365,7 +367,7 @@ heaploop:
|
||||||
if current == nil {
|
if current == nil {
|
||||||
break heaploop
|
break heaploop
|
||||||
}
|
}
|
||||||
delete(parentRemaining, current.CommitID)
|
parentRemaining.Remove(current.CommitID)
|
||||||
if current.Paths != nil {
|
if current.Paths != nil {
|
||||||
for i, found := range current.Paths {
|
for i, found := range current.Paths {
|
||||||
if !found {
|
if !found {
|
||||||
|
@ -410,14 +412,12 @@ heaploop:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g = NewLogNameStatusRepoParser(ctx, repo.Path, lastEmptyParent, treepath, remainingPaths...)
|
g = NewLogNameStatusRepoParser(ctx, repo.Path, lastEmptyParent, treepath, remainingPaths...)
|
||||||
parentRemaining = map[string]bool{}
|
parentRemaining = make(container.Set[string])
|
||||||
nextRestart = (remaining * 3) / 4
|
nextRestart = (remaining * 3) / 4
|
||||||
continue heaploop
|
continue heaploop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, parent := range current.ParentIDs {
|
parentRemaining.AddMultiple(current.ParentIDs...)
|
||||||
parentRemaining[parent] = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g.Close()
|
g.Close()
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CodeActivityStats represents git statistics data
|
// CodeActivityStats represents git statistics data
|
||||||
|
@ -80,7 +82,7 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
||||||
stats.Additions = 0
|
stats.Additions = 0
|
||||||
stats.Deletions = 0
|
stats.Deletions = 0
|
||||||
authors := make(map[string]*CodeActivityAuthor)
|
authors := make(map[string]*CodeActivityAuthor)
|
||||||
files := make(map[string]bool)
|
files := make(container.Set[string])
|
||||||
var author string
|
var author string
|
||||||
p := 0
|
p := 0
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
|
@ -119,9 +121,7 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
||||||
stats.Deletions += c
|
stats.Deletions += c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, ok := files[parts[2]]; !ok {
|
files.Add(parts[2])
|
||||||
files[parts[2]] = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
"gitea.com/go-chi/binding"
|
"gitea.com/go-chi/binding"
|
||||||
|
@ -43,7 +44,7 @@ func validateYaml(template *api.IssueTemplate) error {
|
||||||
if len(template.Fields) == 0 {
|
if len(template.Fields) == 0 {
|
||||||
return fmt.Errorf("'body' is required")
|
return fmt.Errorf("'body' is required")
|
||||||
}
|
}
|
||||||
ids := map[string]struct{}{}
|
ids := make(container.Set[string])
|
||||||
for idx, field := range template.Fields {
|
for idx, field := range template.Fields {
|
||||||
if err := validateID(field, idx, ids); err != nil {
|
if err := validateID(field, idx, ids); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -125,7 +126,7 @@ func validateRequired(field *api.IssueFormField, idx int) error {
|
||||||
return validateBoolItem(newErrorPosition(idx, field.Type), field.Validations, "required")
|
return validateBoolItem(newErrorPosition(idx, field.Type), field.Validations, "required")
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateID(field *api.IssueFormField, idx int, ids map[string]struct{}) error {
|
func validateID(field *api.IssueFormField, idx int, ids container.Set[string]) error {
|
||||||
if field.Type == api.IssueFormFieldTypeMarkdown {
|
if field.Type == api.IssueFormFieldTypeMarkdown {
|
||||||
// The ID is not required for a markdown field
|
// The ID is not required for a markdown field
|
||||||
return nil
|
return nil
|
||||||
|
@ -139,10 +140,9 @@ func validateID(field *api.IssueFormField, idx int, ids map[string]struct{}) err
|
||||||
if binding.AlphaDashPattern.MatchString(field.ID) {
|
if binding.AlphaDashPattern.MatchString(field.ID) {
|
||||||
return position.Errorf("'id' should contain only alphanumeric, '-' and '_'")
|
return position.Errorf("'id' should contain only alphanumeric, '-' and '_'")
|
||||||
}
|
}
|
||||||
if _, ok := ids[field.ID]; ok {
|
if !ids.Add(field.ID) {
|
||||||
return position.Errorf("'id' should be unique")
|
return position.Errorf("'id' should be unique")
|
||||||
}
|
}
|
||||||
ids[field.ID] = struct{}{}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
"code.gitea.io/gitea/modules/markup/common"
|
"code.gitea.io/gitea/modules/markup/common"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -198,7 +199,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
|
||||||
}
|
}
|
||||||
|
|
||||||
type prefixedIDs struct {
|
type prefixedIDs struct {
|
||||||
values map[string]bool
|
values container.Set[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate generates a new element id.
|
// Generate generates a new element id.
|
||||||
|
@ -219,14 +220,12 @@ func (p *prefixedIDs) GenerateWithDefault(value, dft []byte) []byte {
|
||||||
if !bytes.HasPrefix(result, []byte("user-content-")) {
|
if !bytes.HasPrefix(result, []byte("user-content-")) {
|
||||||
result = append([]byte("user-content-"), result...)
|
result = append([]byte("user-content-"), result...)
|
||||||
}
|
}
|
||||||
if _, ok := p.values[util.BytesToReadOnlyString(result)]; !ok {
|
if p.values.Add(util.BytesToReadOnlyString(result)) {
|
||||||
p.values[util.BytesToReadOnlyString(result)] = true
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
for i := 1; ; i++ {
|
for i := 1; ; i++ {
|
||||||
newResult := fmt.Sprintf("%s-%d", result, i)
|
newResult := fmt.Sprintf("%s-%d", result, i)
|
||||||
if _, ok := p.values[newResult]; !ok {
|
if p.values.Add(newResult) {
|
||||||
p.values[newResult] = true
|
|
||||||
return []byte(newResult)
|
return []byte(newResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,12 +233,12 @@ func (p *prefixedIDs) GenerateWithDefault(value, dft []byte) []byte {
|
||||||
|
|
||||||
// Put puts a given element id to the used ids table.
|
// Put puts a given element id to the used ids table.
|
||||||
func (p *prefixedIDs) Put(value []byte) {
|
func (p *prefixedIDs) Put(value []byte) {
|
||||||
p.values[util.BytesToReadOnlyString(value)] = true
|
p.values.Add(util.BytesToReadOnlyString(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPrefixedIDs() *prefixedIDs {
|
func newPrefixedIDs() *prefixedIDs {
|
||||||
return &prefixedIDs{
|
return &prefixedIDs{
|
||||||
values: map[string]bool{},
|
values: make(container.Set[string]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/notification/base"
|
"code.gitea.io/gitea/modules/notification/base"
|
||||||
|
@ -123,14 +124,14 @@ func (ns *notificationService) NotifyNewPullRequest(pr *issues_model.PullRequest
|
||||||
log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err)
|
log.Error("Unable to load issue: %d for pr: %d: Error: %v", pr.IssueID, pr.ID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
toNotify := make(map[int64]struct{}, 32)
|
toNotify := make(container.Set[int64], 32)
|
||||||
repoWatchers, err := repo_model.GetRepoWatchersIDs(db.DefaultContext, pr.Issue.RepoID)
|
repoWatchers, err := repo_model.GetRepoWatchersIDs(db.DefaultContext, pr.Issue.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetRepoWatchersIDs: %v", err)
|
log.Error("GetRepoWatchersIDs: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, id := range repoWatchers {
|
for _, id := range repoWatchers {
|
||||||
toNotify[id] = struct{}{}
|
toNotify.Add(id)
|
||||||
}
|
}
|
||||||
issueParticipants, err := issues_model.GetParticipantsIDsByIssueID(pr.IssueID)
|
issueParticipants, err := issues_model.GetParticipantsIDsByIssueID(pr.IssueID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -138,11 +139,11 @@ func (ns *notificationService) NotifyNewPullRequest(pr *issues_model.PullRequest
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, id := range issueParticipants {
|
for _, id := range issueParticipants {
|
||||||
toNotify[id] = struct{}{}
|
toNotify.Add(id)
|
||||||
}
|
}
|
||||||
delete(toNotify, pr.Issue.PosterID)
|
delete(toNotify, pr.Issue.PosterID)
|
||||||
for _, mention := range mentions {
|
for _, mention := range mentions {
|
||||||
toNotify[mention.ID] = struct{}{}
|
toNotify.Add(mention.ID)
|
||||||
}
|
}
|
||||||
for receiverID := range toNotify {
|
for receiverID := range toNotify {
|
||||||
_ = ns.issueQueue.Push(issueNotificationOpts{
|
_ = ns.issueQueue.Push(issueNotificationOpts{
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/httpcache"
|
"code.gitea.io/gitea/modules/httpcache"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -83,11 +84,11 @@ func AssetsHandlerFunc(opts *Options) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseAcceptEncoding parse Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5 as compress methods
|
// parseAcceptEncoding parse Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5 as compress methods
|
||||||
func parseAcceptEncoding(val string) map[string]bool {
|
func parseAcceptEncoding(val string) container.Set[string] {
|
||||||
parts := strings.Split(val, ";")
|
parts := strings.Split(val, ";")
|
||||||
types := make(map[string]bool)
|
types := make(container.Set[string])
|
||||||
for _, v := range strings.Split(parts[0], ",") {
|
for _, v := range strings.Split(parts[0], ",") {
|
||||||
types[strings.TrimSpace(v)] = true
|
types.Add(strings.TrimSpace(v))
|
||||||
}
|
}
|
||||||
return types
|
return types
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,28 +7,23 @@ package public
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseAcceptEncoding(t *testing.T) {
|
func TestParseAcceptEncoding(t *testing.T) {
|
||||||
kases := []struct {
|
kases := []struct {
|
||||||
Header string
|
Header string
|
||||||
Expected map[string]bool
|
Expected container.Set[string]
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Header: "deflate, gzip;q=1.0, *;q=0.5",
|
Header: "deflate, gzip;q=1.0, *;q=0.5",
|
||||||
Expected: map[string]bool{
|
Expected: container.SetOf("deflate", "gzip"),
|
||||||
"deflate": true,
|
|
||||||
"gzip": true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: " gzip, deflate, br",
|
Header: " gzip, deflate, br",
|
||||||
Expected: map[string]bool{
|
Expected: container.SetOf("deflate", "gzip", "br"),
|
||||||
"deflate": true,
|
|
||||||
"gzip": true,
|
|
||||||
"br": true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ func AssetIsDir(name string) (bool, error) {
|
||||||
// serveContent serve http content
|
// serveContent serve http content
|
||||||
func serveContent(w http.ResponseWriter, req *http.Request, fi os.FileInfo, modtime time.Time, content io.ReadSeeker) {
|
func serveContent(w http.ResponseWriter, req *http.Request, fi os.FileInfo, modtime time.Time, content io.ReadSeeker) {
|
||||||
encodings := parseAcceptEncoding(req.Header.Get("Accept-Encoding"))
|
encodings := parseAcceptEncoding(req.Header.Get("Accept-Encoding"))
|
||||||
if encodings["gzip"] {
|
if encodings.Contains("gzip") {
|
||||||
if cf, ok := fi.(*vfsgen۰CompressedFileInfo); ok {
|
if cf, ok := fi.(*vfsgen۰CompressedFileInfo); ok {
|
||||||
rdGzip := bytes.NewReader(cf.GzipBytes())
|
rdGzip := bytes.NewReader(cf.GzipBytes())
|
||||||
// all static files are managed by Gitea, so we can make sure every file has the correct ext name
|
// all static files are managed by Gitea, so we can make sure every file has the correct ext name
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
@ -33,7 +34,7 @@ type ChannelUniqueQueueConfiguration ChannelQueueConfiguration
|
||||||
type ChannelUniqueQueue struct {
|
type ChannelUniqueQueue struct {
|
||||||
*WorkerPool
|
*WorkerPool
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
table map[string]bool
|
table container.Set[string]
|
||||||
shutdownCtx context.Context
|
shutdownCtx context.Context
|
||||||
shutdownCtxCancel context.CancelFunc
|
shutdownCtxCancel context.CancelFunc
|
||||||
terminateCtx context.Context
|
terminateCtx context.Context
|
||||||
|
@ -58,7 +59,7 @@ func NewChannelUniqueQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue
|
||||||
shutdownCtx, shutdownCtxCancel := context.WithCancel(terminateCtx)
|
shutdownCtx, shutdownCtxCancel := context.WithCancel(terminateCtx)
|
||||||
|
|
||||||
queue := &ChannelUniqueQueue{
|
queue := &ChannelUniqueQueue{
|
||||||
table: map[string]bool{},
|
table: make(container.Set[string]),
|
||||||
shutdownCtx: shutdownCtx,
|
shutdownCtx: shutdownCtx,
|
||||||
shutdownCtxCancel: shutdownCtxCancel,
|
shutdownCtxCancel: shutdownCtxCancel,
|
||||||
terminateCtx: terminateCtx,
|
terminateCtx: terminateCtx,
|
||||||
|
@ -73,7 +74,7 @@ func NewChannelUniqueQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue
|
||||||
bs, _ := json.Marshal(datum)
|
bs, _ := json.Marshal(datum)
|
||||||
|
|
||||||
queue.lock.Lock()
|
queue.lock.Lock()
|
||||||
delete(queue.table, string(bs))
|
queue.table.Remove(string(bs))
|
||||||
queue.lock.Unlock()
|
queue.lock.Unlock()
|
||||||
|
|
||||||
if u := handle(datum); u != nil {
|
if u := handle(datum); u != nil {
|
||||||
|
@ -127,16 +128,15 @@ func (q *ChannelUniqueQueue) PushFunc(data Data, fn func() error) error {
|
||||||
q.lock.Unlock()
|
q.lock.Unlock()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if _, ok := q.table[string(bs)]; ok {
|
if !q.table.Add(string(bs)) {
|
||||||
return ErrAlreadyInQueue
|
return ErrAlreadyInQueue
|
||||||
}
|
}
|
||||||
// FIXME: We probably need to implement some sort of limit here
|
// FIXME: We probably need to implement some sort of limit here
|
||||||
// If the downstream queue blocks this table will grow without limit
|
// If the downstream queue blocks this table will grow without limit
|
||||||
q.table[string(bs)] = true
|
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
err := fn()
|
err := fn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
delete(q.table, string(bs))
|
q.table.Remove(string(bs))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,8 +155,7 @@ func (q *ChannelUniqueQueue) Has(data Data) (bool, error) {
|
||||||
|
|
||||||
q.lock.Lock()
|
q.lock.Lock()
|
||||||
defer q.lock.Unlock()
|
defer q.lock.Unlock()
|
||||||
_, has := q.table[string(bs)]
|
return q.table.Contains(string(bs)), nil
|
||||||
return has, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush flushes the channel with a timeout - the Flush worker will be registered as a flush worker with the manager
|
// Flush flushes the channel with a timeout - the Flush worker will be registered as a flush worker with the manager
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/organization"
|
"code.gitea.io/gitea/models/organization"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/lfs"
|
"code.gitea.io/gitea/modules/lfs"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -275,7 +276,7 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
|
||||||
return pullMirrorReleaseSync(repo, gitRepo)
|
return pullMirrorReleaseSync(repo, gitRepo)
|
||||||
}
|
}
|
||||||
|
|
||||||
existingRelTags := make(map[string]struct{})
|
existingRelTags := make(container.Set[string])
|
||||||
opts := repo_model.FindReleasesOptions{
|
opts := repo_model.FindReleasesOptions{
|
||||||
IncludeDrafts: true,
|
IncludeDrafts: true,
|
||||||
IncludeTags: true,
|
IncludeTags: true,
|
||||||
|
@ -303,14 +304,14 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
|
||||||
return fmt.Errorf("unable to PushUpdateDeleteTag: %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err)
|
return fmt.Errorf("unable to PushUpdateDeleteTag: %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
existingRelTags[strings.ToLower(rel.TagName)] = struct{}{}
|
existingRelTags.Add(strings.ToLower(rel.TagName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := gitRepo.WalkReferences(git.ObjectTag, 0, 0, func(sha1, refname string) error {
|
_, err := gitRepo.WalkReferences(git.ObjectTag, 0, 0, func(sha1, refname string) error {
|
||||||
tagName := strings.TrimPrefix(refname, git.TagPrefix)
|
tagName := strings.TrimPrefix(refname, git.TagPrefix)
|
||||||
if _, ok := existingRelTags[strings.ToLower(tagName)]; ok {
|
if existingRelTags.Contains(strings.ToLower(tagName)) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
|
||||||
ini "gopkg.in/ini.v1"
|
ini "gopkg.in/ini.v1"
|
||||||
|
@ -109,8 +110,8 @@ func NewQueueService() {
|
||||||
// Now handle the old issue_indexer configuration
|
// Now handle the old issue_indexer configuration
|
||||||
// FIXME: DEPRECATED to be removed in v1.18.0
|
// FIXME: DEPRECATED to be removed in v1.18.0
|
||||||
section := Cfg.Section("queue.issue_indexer")
|
section := Cfg.Section("queue.issue_indexer")
|
||||||
directlySet := toDirectlySetKeysMap(section)
|
directlySet := toDirectlySetKeysSet(section)
|
||||||
if !directlySet["TYPE"] && defaultType == "" {
|
if !directlySet.Contains("TYPE") && defaultType == "" {
|
||||||
switch typ := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_TYPE").MustString(""); typ {
|
switch typ := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_TYPE").MustString(""); typ {
|
||||||
case "levelqueue":
|
case "levelqueue":
|
||||||
_, _ = section.NewKey("TYPE", "level")
|
_, _ = section.NewKey("TYPE", "level")
|
||||||
|
@ -124,25 +125,25 @@ func NewQueueService() {
|
||||||
log.Fatal("Unsupported indexer queue type: %v", typ)
|
log.Fatal("Unsupported indexer queue type: %v", typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !directlySet["LENGTH"] {
|
if !directlySet.Contains("LENGTH") {
|
||||||
length := Cfg.Section("indexer").Key("UPDATE_BUFFER_LEN").MustInt(0)
|
length := Cfg.Section("indexer").Key("UPDATE_BUFFER_LEN").MustInt(0)
|
||||||
if length != 0 {
|
if length != 0 {
|
||||||
_, _ = section.NewKey("LENGTH", strconv.Itoa(length))
|
_, _ = section.NewKey("LENGTH", strconv.Itoa(length))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !directlySet["BATCH_LENGTH"] {
|
if !directlySet.Contains("BATCH_LENGTH") {
|
||||||
fallback := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_BATCH_NUMBER").MustInt(0)
|
fallback := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_BATCH_NUMBER").MustInt(0)
|
||||||
if fallback != 0 {
|
if fallback != 0 {
|
||||||
_, _ = section.NewKey("BATCH_LENGTH", strconv.Itoa(fallback))
|
_, _ = section.NewKey("BATCH_LENGTH", strconv.Itoa(fallback))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !directlySet["DATADIR"] {
|
if !directlySet.Contains("DATADIR") {
|
||||||
queueDir := filepath.ToSlash(Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_DIR").MustString(""))
|
queueDir := filepath.ToSlash(Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_DIR").MustString(""))
|
||||||
if queueDir != "" {
|
if queueDir != "" {
|
||||||
_, _ = section.NewKey("DATADIR", queueDir)
|
_, _ = section.NewKey("DATADIR", queueDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !directlySet["CONN_STR"] {
|
if !directlySet.Contains("CONN_STR") {
|
||||||
connStr := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_CONN_STR").MustString("")
|
connStr := Cfg.Section("indexer").Key("ISSUE_INDEXER_QUEUE_CONN_STR").MustString("")
|
||||||
if connStr != "" {
|
if connStr != "" {
|
||||||
_, _ = section.NewKey("CONN_STR", connStr)
|
_, _ = section.NewKey("CONN_STR", connStr)
|
||||||
|
@ -178,19 +179,19 @@ func handleOldLengthConfiguration(queueName, oldSection, oldKey string, defaultV
|
||||||
}
|
}
|
||||||
|
|
||||||
section := Cfg.Section("queue." + queueName)
|
section := Cfg.Section("queue." + queueName)
|
||||||
directlySet := toDirectlySetKeysMap(section)
|
directlySet := toDirectlySetKeysSet(section)
|
||||||
if !directlySet["LENGTH"] {
|
if !directlySet.Contains("LENGTH") {
|
||||||
_, _ = section.NewKey("LENGTH", strconv.Itoa(value))
|
_, _ = section.NewKey("LENGTH", strconv.Itoa(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// toDirectlySetKeysMap returns a bool map of keys directly set by this section
|
// toDirectlySetKeysSet returns a set of keys directly set by this section
|
||||||
// Note: we cannot use section.HasKey(...) as that will immediately set the Key if a parent section has the Key
|
// Note: we cannot use section.HasKey(...) as that will immediately set the Key if a parent section has the Key
|
||||||
// but this section does not.
|
// but this section does not.
|
||||||
func toDirectlySetKeysMap(section *ini.Section) map[string]bool {
|
func toDirectlySetKeysSet(section *ini.Section) container.Set[string] {
|
||||||
sectionMap := map[string]bool{}
|
sections := make(container.Set[string])
|
||||||
for _, key := range section.Keys() {
|
for _, key := range section.Keys() {
|
||||||
sectionMap[key.Name()] = true
|
sections.Add(key.Name())
|
||||||
}
|
}
|
||||||
return sectionMap
|
return sections
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/user"
|
"code.gitea.io/gitea/modules/user"
|
||||||
|
@ -234,7 +235,7 @@ var (
|
||||||
DefaultTheme string
|
DefaultTheme string
|
||||||
Themes []string
|
Themes []string
|
||||||
Reactions []string
|
Reactions []string
|
||||||
ReactionsMap map[string]bool `ini:"-"`
|
ReactionsLookup container.Set[string] `ini:"-"`
|
||||||
CustomEmojis []string
|
CustomEmojis []string
|
||||||
CustomEmojisMap map[string]string `ini:"-"`
|
CustomEmojisMap map[string]string `ini:"-"`
|
||||||
SearchRepoDescription bool
|
SearchRepoDescription bool
|
||||||
|
@ -1100,9 +1101,9 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||||
|
|
||||||
newMarkup()
|
newMarkup()
|
||||||
|
|
||||||
UI.ReactionsMap = make(map[string]bool)
|
UI.ReactionsLookup = make(container.Set[string])
|
||||||
for _, reaction := range UI.Reactions {
|
for _, reaction := range UI.Reactions {
|
||||||
UI.ReactionsMap[reaction] = true
|
UI.ReactionsLookup.Add(reaction)
|
||||||
}
|
}
|
||||||
UI.CustomEmojisMap = make(map[string]string)
|
UI.CustomEmojisMap = make(map[string]string)
|
||||||
for _, emoji := range UI.CustomEmojis {
|
for _, emoji := range UI.CustomEmojis {
|
||||||
|
|
|
@ -6,6 +6,8 @@ package sync
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StatusTable is a table maintains true/false values.
|
// StatusTable is a table maintains true/false values.
|
||||||
|
@ -14,13 +16,13 @@ import (
|
||||||
// in different goroutines.
|
// in different goroutines.
|
||||||
type StatusTable struct {
|
type StatusTable struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
pool map[string]struct{}
|
pool container.Set[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStatusTable initializes and returns a new StatusTable object.
|
// NewStatusTable initializes and returns a new StatusTable object.
|
||||||
func NewStatusTable() *StatusTable {
|
func NewStatusTable() *StatusTable {
|
||||||
return &StatusTable{
|
return &StatusTable{
|
||||||
pool: make(map[string]struct{}),
|
pool: make(container.Set[string]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,32 +30,29 @@ func NewStatusTable() *StatusTable {
|
||||||
// Returns whether set value was set to true
|
// Returns whether set value was set to true
|
||||||
func (p *StatusTable) StartIfNotRunning(name string) bool {
|
func (p *StatusTable) StartIfNotRunning(name string) bool {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
_, ok := p.pool[name]
|
added := p.pool.Add(name)
|
||||||
if !ok {
|
|
||||||
p.pool[name] = struct{}{}
|
|
||||||
}
|
|
||||||
p.lock.Unlock()
|
p.lock.Unlock()
|
||||||
return !ok
|
return added
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start sets value of given name to true in the pool.
|
// Start sets value of given name to true in the pool.
|
||||||
func (p *StatusTable) Start(name string) {
|
func (p *StatusTable) Start(name string) {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
p.pool[name] = struct{}{}
|
p.pool.Add(name)
|
||||||
p.lock.Unlock()
|
p.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop sets value of given name to false in the pool.
|
// Stop sets value of given name to false in the pool.
|
||||||
func (p *StatusTable) Stop(name string) {
|
func (p *StatusTable) Stop(name string) {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
delete(p.pool, name)
|
p.pool.Remove(name)
|
||||||
p.lock.Unlock()
|
p.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsRunning checks if value of given name is set to true in the pool.
|
// IsRunning checks if value of given name is set to true in the pool.
|
||||||
func (p *StatusTable) IsRunning(name string) bool {
|
func (p *StatusTable) IsRunning(name string) bool {
|
||||||
p.lock.RLock()
|
p.lock.RLock()
|
||||||
_, ok := p.pool[name]
|
exists := p.pool.Contains(name)
|
||||||
p.lock.RUnlock()
|
p.lock.RUnlock()
|
||||||
return ok
|
return exists
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
conan_model "code.gitea.io/gitea/models/packages/conan"
|
conan_model "code.gitea.io/gitea/models/packages/conan"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -33,20 +34,18 @@ const (
|
||||||
packageReferenceKey = "PackageReference"
|
packageReferenceKey = "PackageReference"
|
||||||
)
|
)
|
||||||
|
|
||||||
type stringSet map[string]struct{}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
recipeFileList = stringSet{
|
recipeFileList = container.SetOf(
|
||||||
conanfileFile: struct{}{},
|
conanfileFile,
|
||||||
"conanmanifest.txt": struct{}{},
|
"conanmanifest.txt",
|
||||||
"conan_sources.tgz": struct{}{},
|
"conan_sources.tgz",
|
||||||
"conan_export.tgz": struct{}{},
|
"conan_export.tgz",
|
||||||
}
|
)
|
||||||
packageFileList = stringSet{
|
packageFileList = container.SetOf(
|
||||||
conaninfoFile: struct{}{},
|
conaninfoFile,
|
||||||
"conanmanifest.txt": struct{}{},
|
"conanmanifest.txt",
|
||||||
"conan_package.tgz": struct{}{},
|
"conan_package.tgz",
|
||||||
}
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
func jsonResponse(ctx *context.Context, status int, obj interface{}) {
|
func jsonResponse(ctx *context.Context, status int, obj interface{}) {
|
||||||
|
@ -268,7 +267,7 @@ func PackageUploadURLs(ctx *context.Context) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveUploadURLs(ctx *context.Context, fileFilter stringSet, uploadURL string) {
|
func serveUploadURLs(ctx *context.Context, fileFilter container.Set[string], uploadURL string) {
|
||||||
defer ctx.Req.Body.Close()
|
defer ctx.Req.Body.Close()
|
||||||
|
|
||||||
var files map[string]int64
|
var files map[string]int64
|
||||||
|
@ -279,7 +278,7 @@ func serveUploadURLs(ctx *context.Context, fileFilter stringSet, uploadURL strin
|
||||||
|
|
||||||
urls := make(map[string]string)
|
urls := make(map[string]string)
|
||||||
for file := range files {
|
for file := range files {
|
||||||
if _, ok := fileFilter[file]; ok {
|
if fileFilter.Contains(file) {
|
||||||
urls[file] = fmt.Sprintf("%s/%s", uploadURL, file)
|
urls[file] = fmt.Sprintf("%s/%s", uploadURL, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,12 +300,12 @@ func UploadPackageFile(ctx *context.Context) {
|
||||||
uploadFile(ctx, packageFileList, pref.AsKey())
|
uploadFile(ctx, packageFileList, pref.AsKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
func uploadFile(ctx *context.Context, fileFilter stringSet, fileKey string) {
|
func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey string) {
|
||||||
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
|
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
|
||||||
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
|
pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
|
||||||
|
|
||||||
filename := ctx.Params("filename")
|
filename := ctx.Params("filename")
|
||||||
if _, ok := fileFilter[filename]; !ok {
|
if !fileFilter.Contains(filename) {
|
||||||
apiError(ctx, http.StatusBadRequest, nil)
|
apiError(ctx, http.StatusBadRequest, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -442,11 +441,11 @@ func DownloadPackageFile(ctx *context.Context) {
|
||||||
downloadFile(ctx, packageFileList, pref.AsKey())
|
downloadFile(ctx, packageFileList, pref.AsKey())
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadFile(ctx *context.Context, fileFilter stringSet, fileKey string) {
|
func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKey string) {
|
||||||
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
|
rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
|
||||||
|
|
||||||
filename := ctx.Params("filename")
|
filename := ctx.Params("filename")
|
||||||
if _, ok := fileFilter[filename]; !ok {
|
if !fileFilter.Contains(filename) {
|
||||||
apiError(ctx, http.StatusBadRequest, nil)
|
apiError(ctx, http.StatusBadRequest, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -947,10 +948,11 @@ func ValidateRepoMetas(ctx *context.Context, form forms.CreateIssueForm, isPull
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, 0
|
return nil, nil, 0, 0
|
||||||
}
|
}
|
||||||
labelIDMark := base.Int64sToMap(labelIDs)
|
labelIDMark := make(container.Set[int64])
|
||||||
|
labelIDMark.AddMultiple(labelIDs...)
|
||||||
|
|
||||||
for i := range labels {
|
for i := range labels {
|
||||||
if labelIDMark[labels[i].ID] {
|
if labelIDMark.Contains(labels[i].ID) {
|
||||||
labels[i].IsChecked = true
|
labels[i].IsChecked = true
|
||||||
hasSelected = true
|
hasSelected = true
|
||||||
}
|
}
|
||||||
|
@ -1293,9 +1295,9 @@ func ViewIssue(ctx *context.Context) {
|
||||||
|
|
||||||
// Metas.
|
// Metas.
|
||||||
// Check labels.
|
// Check labels.
|
||||||
labelIDMark := make(map[int64]bool)
|
labelIDMark := make(container.Set[int64])
|
||||||
for i := range issue.Labels {
|
for _, label := range issue.Labels {
|
||||||
labelIDMark[issue.Labels[i].ID] = true
|
labelIDMark.Add(label.ID)
|
||||||
}
|
}
|
||||||
labels, err := issues_model.GetLabelsByRepoID(ctx, repo.ID, "", db.ListOptions{})
|
labels, err := issues_model.GetLabelsByRepoID(ctx, repo.ID, "", db.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1317,7 +1319,7 @@ func ViewIssue(ctx *context.Context) {
|
||||||
|
|
||||||
hasSelected := false
|
hasSelected := false
|
||||||
for i := range labels {
|
for i := range labels {
|
||||||
if labelIDMark[labels[i].ID] {
|
if labelIDMark.Contains(labels[i].ID) {
|
||||||
labels[i].IsChecked = true
|
labels[i].IsChecked = true
|
||||||
hasSelected = true
|
hasSelected = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/charset"
|
"code.gitea.io/gitea/modules/charset"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/git/pipeline"
|
"code.gitea.io/gitea/modules/git/pipeline"
|
||||||
|
@ -176,14 +177,12 @@ func LFSLocks(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
filemap := make(map[string]bool, len(filelist))
|
fileset := make(container.Set[string], len(filelist))
|
||||||
for _, name := range filelist {
|
fileset.AddMultiple(filelist...)
|
||||||
filemap[name] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
linkable := make([]bool, len(lfsLocks))
|
linkable := make([]bool, len(lfsLocks))
|
||||||
for i, lock := range lfsLocks {
|
for i, lock := range lfsLocks {
|
||||||
linkable[i] = filemap[lock.Path]
|
linkable[i] = fileset.Contains(lock.Path)
|
||||||
}
|
}
|
||||||
ctx.Data["Linkable"] = linkable
|
ctx.Data["Linkable"] = linkable
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/charset"
|
"code.gitea.io/gitea/modules/charset"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/highlight"
|
"code.gitea.io/gitea/modules/highlight"
|
||||||
|
@ -811,16 +812,14 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
|
||||||
defer cancel()
|
defer cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
selected := map[string]bool{}
|
selected := make(container.Set[string])
|
||||||
for _, pth := range ctx.FormStrings("f[]") {
|
selected.AddMultiple(ctx.FormStrings("f[]")...)
|
||||||
selected[pth] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
entries := allEntries
|
entries := allEntries
|
||||||
if len(selected) > 0 {
|
if len(selected) > 0 {
|
||||||
entries = make(git.Entries, 0, len(selected))
|
entries = make(git.Entries, 0, len(selected))
|
||||||
for _, entry := range allEntries {
|
for _, entry := range allEntries {
|
||||||
if selected[entry.Name()] {
|
if selected.Contains(entry.Name()) {
|
||||||
entries = append(entries, entry)
|
entries = append(entries, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/references"
|
"code.gitea.io/gitea/modules/references"
|
||||||
"code.gitea.io/gitea/modules/repository"
|
"code.gitea.io/gitea/modules/repository"
|
||||||
|
@ -111,7 +112,7 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm
|
||||||
Action references.XRefAction
|
Action references.XRefAction
|
||||||
}
|
}
|
||||||
|
|
||||||
refMarked := make(map[markKey]bool)
|
refMarked := make(container.Set[markKey])
|
||||||
var refRepo *repo_model.Repository
|
var refRepo *repo_model.Repository
|
||||||
var refIssue *issues_model.Issue
|
var refIssue *issues_model.Issue
|
||||||
var err error
|
var err error
|
||||||
|
@ -144,10 +145,9 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm
|
||||||
}
|
}
|
||||||
|
|
||||||
key := markKey{ID: refIssue.ID, Action: ref.Action}
|
key := markKey{ID: refIssue.ID, Action: ref.Action}
|
||||||
if refMarked[key] {
|
if !refMarked.Add(key) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
refMarked[key] = true
|
|
||||||
|
|
||||||
// FIXME: this kind of condition is all over the code, it should be consolidated in a single place
|
// FIXME: this kind of condition is all over the code, it should be consolidated in a single place
|
||||||
canclose := perm.IsAdmin() || perm.IsOwner() || perm.CanWriteIssuesOrPulls(refIssue.IsPull) || refIssue.PosterID == doer.ID
|
canclose := perm.IsAdmin() || perm.IsOwner() || perm.CanWriteIssuesOrPulls(refIssue.IsPull) || refIssue.PosterID == doer.ID
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
activities_model "code.gitea.io/gitea/models/activities"
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
@ -46,8 +47,8 @@ func MailMentionsComment(ctx context.Context, pr *issues_model.PullRequest, c *i
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
visited := make(map[int64]bool, len(mentions)+1)
|
visited := make(container.Set[int64], len(mentions)+1)
|
||||||
visited[c.Poster.ID] = true
|
visited.Add(c.Poster.ID)
|
||||||
if err = mailIssueCommentBatch(
|
if err = mailIssueCommentBatch(
|
||||||
&mailCommentContext{
|
&mailCommentContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
@ -89,11 +90,11 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_mo
|
||||||
unfiltered = append(ids, unfiltered...)
|
unfiltered = append(ids, unfiltered...)
|
||||||
}
|
}
|
||||||
|
|
||||||
visited := make(map[int64]bool, len(unfiltered)+len(mentions)+1)
|
visited := make(container.Set[int64], len(unfiltered)+len(mentions)+1)
|
||||||
|
|
||||||
// Avoid mailing the doer
|
// Avoid mailing the doer
|
||||||
if ctx.Doer.EmailNotificationsPreference != user_model.EmailNotificationsAndYourOwn {
|
if ctx.Doer.EmailNotificationsPreference != user_model.EmailNotificationsAndYourOwn {
|
||||||
visited[ctx.Doer.ID] = true
|
visited.Add(ctx.Doer.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========== Mentions ===========
|
// =========== Mentions ===========
|
||||||
|
@ -106,9 +107,7 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_mo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetIssueWatchersIDs(%d): %v", ctx.Issue.ID, err)
|
return fmt.Errorf("GetIssueWatchersIDs(%d): %v", ctx.Issue.ID, err)
|
||||||
}
|
}
|
||||||
for _, i := range ids {
|
visited.AddMultiple(ids...)
|
||||||
visited[i] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
unfilteredUsers, err := user_model.GetMaileableUsersByIDs(unfiltered, false)
|
unfilteredUsers, err := user_model.GetMaileableUsersByIDs(unfiltered, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -121,7 +120,7 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_mo
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mailIssueCommentBatch(ctx *mailCommentContext, users []*user_model.User, visited map[int64]bool, fromMention bool) error {
|
func mailIssueCommentBatch(ctx *mailCommentContext, users []*user_model.User, visited container.Set[int64], fromMention bool) error {
|
||||||
checkUnit := unit.TypeIssues
|
checkUnit := unit.TypeIssues
|
||||||
if ctx.Issue.IsPull {
|
if ctx.Issue.IsPull {
|
||||||
checkUnit = unit.TypePullRequests
|
checkUnit = unit.TypePullRequests
|
||||||
|
@ -142,13 +141,10 @@ func mailIssueCommentBatch(ctx *mailCommentContext, users []*user_model.User, vi
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have already visited this user we exclude them
|
// if we have already visited this user we exclude them
|
||||||
if _, ok := visited[user.ID]; ok {
|
if !visited.Add(user.ID) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// now mark them as visited
|
|
||||||
visited[user.ID] = true
|
|
||||||
|
|
||||||
// test if this user is allowed to see the issue/pull
|
// test if this user is allowed to see the issue/pull
|
||||||
if !access_model.CheckRepoUnitUser(ctx, ctx.Issue.Repo, user, checkUnit) {
|
if !access_model.CheckRepoUnitUser(ctx, ctx.Issue.Repo, user, checkUnit) {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -409,7 +410,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
|
||||||
const appliedPatchPrefix = "Applied patch to '"
|
const appliedPatchPrefix = "Applied patch to '"
|
||||||
const withConflicts = "' with conflicts."
|
const withConflicts = "' with conflicts."
|
||||||
|
|
||||||
conflictMap := map[string]bool{}
|
conflicts := make(container.Set[string])
|
||||||
|
|
||||||
// Now scan the output from the command
|
// Now scan the output from the command
|
||||||
scanner := bufio.NewScanner(stderrReader)
|
scanner := bufio.NewScanner(stderrReader)
|
||||||
|
@ -418,7 +419,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
|
||||||
if strings.HasPrefix(line, prefix) {
|
if strings.HasPrefix(line, prefix) {
|
||||||
conflict = true
|
conflict = true
|
||||||
filepath := strings.TrimSpace(strings.Split(line[len(prefix):], ":")[0])
|
filepath := strings.TrimSpace(strings.Split(line[len(prefix):], ":")[0])
|
||||||
conflictMap[filepath] = true
|
conflicts.Add(filepath)
|
||||||
} else if is3way && line == threewayFailed {
|
} else if is3way && line == threewayFailed {
|
||||||
conflict = true
|
conflict = true
|
||||||
} else if strings.HasPrefix(line, errorPrefix) {
|
} else if strings.HasPrefix(line, errorPrefix) {
|
||||||
|
@ -427,7 +428,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
|
||||||
if strings.HasSuffix(line, suffix) {
|
if strings.HasSuffix(line, suffix) {
|
||||||
filepath := strings.TrimSpace(strings.TrimSuffix(line[len(errorPrefix):], suffix))
|
filepath := strings.TrimSpace(strings.TrimSuffix(line[len(errorPrefix):], suffix))
|
||||||
if filepath != "" {
|
if filepath != "" {
|
||||||
conflictMap[filepath] = true
|
conflicts.Add(filepath)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -436,18 +437,18 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo *
|
||||||
conflict = true
|
conflict = true
|
||||||
filepath := strings.TrimPrefix(strings.TrimSuffix(line, withConflicts), appliedPatchPrefix)
|
filepath := strings.TrimPrefix(strings.TrimSuffix(line, withConflicts), appliedPatchPrefix)
|
||||||
if filepath != "" {
|
if filepath != "" {
|
||||||
conflictMap[filepath] = true
|
conflicts.Add(filepath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// only list 10 conflicted files
|
// only list 10 conflicted files
|
||||||
if len(conflictMap) >= 10 {
|
if len(conflicts) >= 10 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(conflictMap) > 0 {
|
if len(conflicts) > 0 {
|
||||||
pr.ConflictedFiles = make([]string, 0, len(conflictMap))
|
pr.ConflictedFiles = make([]string, 0, len(conflicts))
|
||||||
for key := range conflictMap {
|
for key := range conflicts {
|
||||||
pr.ConflictedFiles = append(pr.ConflictedFiles, key)
|
pr.ConflictedFiles = append(pr.ConflictedFiles, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
|
@ -640,7 +641,7 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
|
||||||
|
|
||||||
posterSig := pr.Issue.Poster.NewGitSig().String()
|
posterSig := pr.Issue.Poster.NewGitSig().String()
|
||||||
|
|
||||||
authorsMap := map[string]bool{}
|
uniqueAuthors := make(container.Set[string])
|
||||||
authors := make([]string, 0, len(commits))
|
authors := make([]string, 0, len(commits))
|
||||||
stringBuilder := strings.Builder{}
|
stringBuilder := strings.Builder{}
|
||||||
|
|
||||||
|
@ -687,9 +688,8 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
|
||||||
}
|
}
|
||||||
|
|
||||||
authorString := commit.Author.String()
|
authorString := commit.Author.String()
|
||||||
if !authorsMap[authorString] && authorString != posterSig {
|
if uniqueAuthors.Add(authorString) && authorString != posterSig {
|
||||||
authors = append(authors, authorString)
|
authors = append(authors, authorString)
|
||||||
authorsMap[authorString] = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,9 +709,8 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
|
||||||
}
|
}
|
||||||
for _, commit := range commits {
|
for _, commit := range commits {
|
||||||
authorString := commit.Author.String()
|
authorString := commit.Author.String()
|
||||||
if !authorsMap[authorString] && authorString != posterSig {
|
if uniqueAuthors.Add(authorString) && authorString != posterSig {
|
||||||
authors = append(authors, authorString)
|
authors = append(authors, authorString)
|
||||||
authorsMap[authorString] = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
skip += limit
|
skip += limit
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/notification"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
|
@ -209,7 +210,7 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod
|
||||||
return fmt.Errorf("AddReleaseAttachments: %v", err)
|
return fmt.Errorf("AddReleaseAttachments: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
deletedUUIDsMap := make(map[string]bool)
|
deletedUUIDs := make(container.Set[string])
|
||||||
if len(delAttachmentUUIDs) > 0 {
|
if len(delAttachmentUUIDs) > 0 {
|
||||||
// Check attachments
|
// Check attachments
|
||||||
attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, delAttachmentUUIDs)
|
attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, delAttachmentUUIDs)
|
||||||
|
@ -220,7 +221,7 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod
|
||||||
if attach.ReleaseID != rel.ID {
|
if attach.ReleaseID != rel.ID {
|
||||||
return errors.New("delete attachement of release permission denied")
|
return errors.New("delete attachement of release permission denied")
|
||||||
}
|
}
|
||||||
deletedUUIDsMap[attach.UUID] = true
|
deletedUUIDs.Add(attach.UUID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := repo_model.DeleteAttachments(ctx, attachments, false); err != nil {
|
if _, err := repo_model.DeleteAttachments(ctx, attachments, false); err != nil {
|
||||||
|
@ -245,7 +246,7 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod
|
||||||
}
|
}
|
||||||
|
|
||||||
for uuid, newName := range editAttachments {
|
for uuid, newName := range editAttachments {
|
||||||
if !deletedUUIDsMap[uuid] {
|
if !deletedUUIDs.Contains(uuid) {
|
||||||
if err = repo_model.UpdateAttachmentByUUID(ctx, &repo_model.Attachment{
|
if err = repo_model.UpdateAttachmentByUUID(ctx, &repo_model.Attachment{
|
||||||
UUID: uuid,
|
UUID: uuid,
|
||||||
Name: newName,
|
Name: newName,
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/notification"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
|
@ -257,12 +258,12 @@ func checkUnadoptedRepositories(userName string, repoNamesToCheck []string, unad
|
||||||
if len(repos) == len(repoNamesToCheck) {
|
if len(repos) == len(repoNamesToCheck) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
repoNames := make(map[string]bool, len(repos))
|
repoNames := make(container.Set[string], len(repos))
|
||||||
for _, repo := range repos {
|
for _, repo := range repos {
|
||||||
repoNames[repo.LowerName] = true
|
repoNames.Add(repo.LowerName)
|
||||||
}
|
}
|
||||||
for _, repoName := range repoNamesToCheck {
|
for _, repoName := range repoNamesToCheck {
|
||||||
if _, ok := repoNames[repoName]; !ok {
|
if !repoNames.Contains(repoName) {
|
||||||
unadopted.add(filepath.Join(userName, repoName))
|
unadopted.add(filepath.Join(userName, repoName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue