Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve utils of slices #22379

Merged
merged 25 commits into from
Jan 11, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
if c.IsSet("auth-type") {
conf.Auth = c.String("auth-type")
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
if !contains(validAuthTypes, strings.ToUpper(c.String("auth-type"))) {
if !util.IsStringInSlice(strings.ToUpper(c.String("auth-type")), validAuthTypes) {
return errors.New("Auth must be one of PLAIN/LOGIN/CRAM-MD5")
}
conf.Auth = c.String("auth-type")
Expand Down
11 changes: 1 addition & 10 deletions cmd/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,15 +409,6 @@ func runDump(ctx *cli.Context) error {
return nil
}

func contains(slice []string, s string) bool {
for _, v := range slice {
if v == s {
return true
}
}
return false
}

// addRecursiveExclude zips absPath to specified insidePath inside writer excluding excludeAbsPath
func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeAbsPath []string, verbose bool) error {
absPath, err := filepath.Abs(absPath)
Expand All @@ -438,7 +429,7 @@ func addRecursiveExclude(w archiver.Writer, insidePath, absPath string, excludeA
currentAbsPath := path.Join(absPath, file.Name())
currentInsidePath := path.Join(insidePath, file.Name())
if file.IsDir() {
if !contains(excludeAbsPath, currentAbsPath) {
if !util.IsStringInSlice(currentAbsPath, excludeAbsPath) {
if err := addFile(w, currentInsidePath, currentAbsPath, false); err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions models/asymkey/ssh_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ func SynchronizePublicKeys(usr *user_model.User, s *auth.Source, sshPublicKeys [
sshKeySplit := strings.Split(v, " ")
if len(sshKeySplit) > 1 {
key := strings.Join(sshKeySplit[:2], " ")
if !util.ExistsInSlice(key, providedKeys) {
if !util.IsStringInSlice(key, providedKeys) {
providedKeys = append(providedKeys, key)
}
}
Expand All @@ -425,7 +425,7 @@ func SynchronizePublicKeys(usr *user_model.User, s *auth.Source, sshPublicKeys [
// Add new Public SSH Keys that doesn't already exist in DB
var newKeys []string
for _, key := range providedKeys {
if !util.ExistsInSlice(key, giteaKeys) {
if !util.IsStringInSlice(key, giteaKeys) {
newKeys = append(newKeys, key)
}
}
Expand All @@ -436,7 +436,7 @@ func SynchronizePublicKeys(usr *user_model.User, s *auth.Source, sshPublicKeys [
// Mark keys from DB that no longer exist in the source for deletion
var giteaKeysToDelete []string
for _, giteaKey := range giteaKeys {
if !util.ExistsInSlice(giteaKey, providedKeys) {
if !util.IsStringInSlice(giteaKey, providedKeys) {
log.Trace("synchronizePublicKeys[%s]: Marking Public SSH Key for deletion for user %s: %v", s.Name, usr.Name, giteaKey)
giteaKeysToDelete = append(giteaKeysToDelete, giteaKey)
}
Expand Down
8 changes: 4 additions & 4 deletions models/git/branches.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ func IsProtectedBranch(ctx context.Context, repoID int64, branchName string) (bo
// updateApprovalWhitelist checks whether the user whitelist changed and returns a whitelist with
// the users from newWhitelist which have explicit read or write access to the repo.
func updateApprovalWhitelist(ctx context.Context, repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) {
hasUsersChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist)
hasUsersChanged := !util.IsEqualSlice(currentWhitelist, newWhitelist)
if !hasUsersChanged {
return currentWhitelist, nil
}
Expand All @@ -363,7 +363,7 @@ func updateApprovalWhitelist(ctx context.Context, repo *repo_model.Repository, c
// updateUserWhitelist checks whether the user whitelist changed and returns a whitelist with
// the users from newWhitelist which have write access to the repo.
func updateUserWhitelist(ctx context.Context, repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) {
hasUsersChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist)
hasUsersChanged := !util.IsEqualSlice(currentWhitelist, newWhitelist)
if !hasUsersChanged {
return currentWhitelist, nil
}
Expand Down Expand Up @@ -392,7 +392,7 @@ func updateUserWhitelist(ctx context.Context, repo *repo_model.Repository, curre
// updateTeamWhitelist checks whether the team whitelist changed and returns a whitelist with
// the teams from newWhitelist which have write access to the repo.
func updateTeamWhitelist(ctx context.Context, repo *repo_model.Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) {
hasTeamsChanged := !util.IsSliceInt64Eq(currentWhitelist, newWhitelist)
hasTeamsChanged := !util.IsEqualSlice(currentWhitelist, newWhitelist)
if !hasTeamsChanged {
return currentWhitelist, nil
}
Expand All @@ -404,7 +404,7 @@ func updateTeamWhitelist(ctx context.Context, repo *repo_model.Repository, curre

whitelist = make([]int64, 0, len(teams))
for i := range teams {
if util.IsInt64InSlice(teams[i].ID, newWhitelist) {
if util.IsInSlice(teams[i].ID, newWhitelist) {
whitelist = append(whitelist, teams[i].ID)
}
}
Expand Down
4 changes: 2 additions & 2 deletions models/issues/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -1529,7 +1529,7 @@ func IsUserParticipantsOfIssue(user *user_model.User, issue *Issue) bool {
log.Error(err.Error())
return false
}
return util.IsInt64InSlice(user.ID, userIDs)
return util.IsInSlice(user.ID, userIDs)
}

// UpdateIssueMentions updates issue-user relations for mentioned users.
Expand Down Expand Up @@ -2023,7 +2023,7 @@ func (issue *Issue) GetParticipantIDsByIssue(ctx context.Context) ([]int64, erro
Find(&userIDs); err != nil {
return nil, fmt.Errorf("get poster IDs: %w", err)
}
if !util.IsInt64InSlice(issue.PosterID, userIDs) {
if !util.IsInSlice(issue.PosterID, userIDs) {
return append(userIDs, issue.PosterID), nil
}
return userIDs, nil
Expand Down
21 changes: 7 additions & 14 deletions models/org_team.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,20 +398,13 @@ func DeleteTeam(t *organization.Team) error {
return fmt.Errorf("findProtectedBranches: %w", err)
}
for _, p := range protections {
var matched1, matched2, matched3 bool
if len(p.WhitelistTeamIDs) != 0 {
p.WhitelistTeamIDs, matched1 = util.RemoveIDFromList(
p.WhitelistTeamIDs, t.ID)
}
if len(p.ApprovalsWhitelistTeamIDs) != 0 {
p.ApprovalsWhitelistTeamIDs, matched2 = util.RemoveIDFromList(
p.ApprovalsWhitelistTeamIDs, t.ID)
}
if len(p.MergeWhitelistTeamIDs) != 0 {
p.MergeWhitelistTeamIDs, matched3 = util.RemoveIDFromList(
p.MergeWhitelistTeamIDs, t.ID)
}
if matched1 || matched2 || matched3 {
lenIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistTeamIDs), len(p.ApprovalsWhitelistTeamIDs), len(p.MergeWhitelistTeamIDs)
p.WhitelistTeamIDs = util.RemoveFromSlice(t.ID, p.WhitelistTeamIDs)
p.ApprovalsWhitelistTeamIDs = util.RemoveFromSlice(t.ID, p.ApprovalsWhitelistTeamIDs)
p.MergeWhitelistTeamIDs = util.RemoveFromSlice(t.ID, p.MergeWhitelistTeamIDs)
if lenIDs != len(p.WhitelistTeamIDs) ||
lenApprovalIDs != len(p.ApprovalsWhitelistTeamIDs) ||
lenMergeIDs != len(p.MergeWhitelistTeamIDs) {
if _, err = sess.ID(p.ID).Cols(
"whitelist_team_i_ds",
"merge_whitelist_team_i_ds",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have this loop (at least) twice: Once here, and once in models/user.go#143-157.
Time for a common function?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, they are different: WhitelistTeamIDs/ApprovalsWhitelistTeamIDs/MergeWhitelistTeamIDs vs WhitelistUserIDs/ApprovalsWhitelistUserIDs/MergeWhitelistUserIDs, I have no idea how to write a common function which has less lines.

Anyway, I think it's out of scope to improve this logic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also prefer to keep the code:

  • from a refactoring view, keep the old code structure
  • from a business view, some business related code could/should be written separately, because merging code aggressively sometimes affect readability, sometimes you may not even find a suitable name for the "new" function.

Expand Down
21 changes: 7 additions & 14 deletions models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,20 +141,13 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
break
}
for _, p := range protections {
var matched1, matched2, matched3 bool
if len(p.WhitelistUserIDs) != 0 {
p.WhitelistUserIDs, matched1 = util.RemoveIDFromList(
p.WhitelistUserIDs, u.ID)
}
if len(p.ApprovalsWhitelistUserIDs) != 0 {
p.ApprovalsWhitelistUserIDs, matched2 = util.RemoveIDFromList(
p.ApprovalsWhitelistUserIDs, u.ID)
}
if len(p.MergeWhitelistUserIDs) != 0 {
p.MergeWhitelistUserIDs, matched3 = util.RemoveIDFromList(
p.MergeWhitelistUserIDs, u.ID)
}
if matched1 || matched2 || matched3 {
lenIDs, lenApprovalIDs, lenMergeIDs := len(p.WhitelistUserIDs), len(p.ApprovalsWhitelistUserIDs), len(p.MergeWhitelistUserIDs)
p.WhitelistUserIDs = util.RemoveFromSlice(u.ID, p.WhitelistUserIDs)
p.ApprovalsWhitelistUserIDs = util.RemoveFromSlice(u.ID, p.ApprovalsWhitelistUserIDs)
p.MergeWhitelistUserIDs = util.RemoveFromSlice(u.ID, p.MergeWhitelistUserIDs)
if lenIDs != len(p.WhitelistUserIDs) ||
lenApprovalIDs != len(p.ApprovalsWhitelistUserIDs) ||
lenMergeIDs != len(p.MergeWhitelistUserIDs) {
if _, err = e.ID(p.ID).Cols(
"whitelist_user_i_ds",
"merge_whitelist_user_i_ds",
Expand Down
92 changes: 0 additions & 92 deletions modules/util/compare.go

This file was deleted.

77 changes: 68 additions & 9 deletions modules/util/slice.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,76 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

// Most of the functions in this file can have better implementations with "golang.org/x/exp/slices".
// However, "golang.org/x/exp" is experimental and unreliable, we shouldn't use it.
// So lets waiting for the "slices" has be promoted to the main repository one day.

package util

// RemoveIDFromList removes the given ID from the slice, if found.
// It does not preserve order, and assumes the ID is unique.
func RemoveIDFromList(list []int64, id int64) ([]int64, bool) {
n := len(list) - 1
for i, item := range list {
if item == id {
list[i] = list[n]
return list[:n], true
import "strings"

// IsInSlice returns true if the target exists in the slice.
func IsInSlice[T comparable](target T, slice []T) bool {
return IsInSliceFunc(func(t T) bool { return t == target }, slice)
}

// IsInSliceFunc returns true if any element in the slice satisfies the targetFunc.
func IsInSliceFunc[T comparable](targetFunc func(T) bool, slice []T) bool {
for _, v := range slice {
if targetFunc(v) {
return true
}
}
return false
}

// IsStringInSlice sequential searches if string exists in slice.
func IsStringInSlice(target string, slice []string, insensitive ...bool) bool {
if len(insensitive) != 0 && insensitive[0] {
target = strings.ToLower(target)
return IsInSliceFunc(func(t string) bool { return strings.ToLower(t) == target }, slice)
}

return IsInSlice(target, slice)
}

// IsEqualSlice returns true if slices are equal.
// Be careful, two slice which have the same elements but different order are considered equal here.
func IsEqualSlice[T comparable](target, source []T) bool {
if len(target) != len(source) {
return false
}

counts := make(map[T]int, len(target))
for _, v := range target {
counts[v]++
}
for _, v := range source {
counts[v]--
}

for _, v := range counts {
if v != 0 {
return false
}
}
return true
}

// RemoveFromSlice removes all the target elements from the slice.
func RemoveFromSlice[T comparable](target T, slice []T) []T {
return RemoveFromSliceFunc(func(t T) bool { return t == target }, slice)
}

// RemoveFromSliceFunc removes all elements which satisfy the targetFunc from the slice.
func RemoveFromSliceFunc[T comparable](targetFunc func(T) bool, slice []T) []T {
idx := 0
for _, v := range slice {
if targetFunc(v) {
continue
}
slice[idx] = v
idx++
}
return list, false
return slice[:idx]
}
Loading