Skip to content

Commit

Permalink
Make every not exist error unwrappable to a fs.ErrNotExist
Browse files Browse the repository at this point in the history
A lot of our code is repeatedly testing if individual errors are
specific types of Not Exist errors. This is repetitative and unnecesary.
`Unwrap() error` provides a common way of labelling an error as a
NotExist error and we can/should use this.

This PR has chosen to use the common `io/fs` errors e.g.
`fs.ErrNotExist` for our errors. This is in some ways not completely
correct as these are not filesystem errors but it seems like a
reasonable thing to do and would allow us to simplify a lot of our code
to `errors.Is(err, fs.ErrNotExist)` instead of
`package.IsErr...NotExist(err)`

I am open to suggestions to use a different base error - perhaps
`models/db.ErrNotExist` if that would be felt to be better.

Signed-off-by: Andrew Thornton <art27@cantab.net>
  • Loading branch information
zeripath committed Aug 21, 2022
1 parent 6d31814 commit a86d070
Show file tree
Hide file tree
Showing 41 changed files with 527 additions and 16 deletions.
53 changes: 52 additions & 1 deletion models/asymkey/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

package asymkey

import "fmt"
import (
"fmt"
"io/fs"
)

// ErrKeyUnableVerify represents a "KeyUnableVerify" kind of error.
type ErrKeyUnableVerify struct {
Expand Down Expand Up @@ -36,6 +39,10 @@ func (err ErrKeyNotExist) Error() string {
return fmt.Sprintf("public key does not exist [id: %d]", err.ID)
}

func (err ErrKeyNotExist) Unwrap() error {
return fs.ErrNotExist
}

// ErrKeyAlreadyExist represents a "KeyAlreadyExist" kind of error.
type ErrKeyAlreadyExist struct {
OwnerID int64
Expand All @@ -54,6 +61,10 @@ func (err ErrKeyAlreadyExist) Error() string {
err.OwnerID, err.Fingerprint, err.Content)
}

func (err ErrKeyAlreadyExist) Unwrap() error {
return fs.ErrExist
}

// ErrKeyNameAlreadyUsed represents a "KeyNameAlreadyUsed" kind of error.
type ErrKeyNameAlreadyUsed struct {
OwnerID int64
Expand All @@ -70,6 +81,10 @@ func (err ErrKeyNameAlreadyUsed) Error() string {
return fmt.Sprintf("public key already exists [owner_id: %d, name: %s]", err.OwnerID, err.Name)
}

func (err ErrKeyNameAlreadyUsed) Unwrap() error {
return fs.ErrExist
}

// ErrGPGNoEmailFound represents a "ErrGPGNoEmailFound" kind of error.
type ErrGPGNoEmailFound struct {
FailedEmails []string
Expand Down Expand Up @@ -132,6 +147,10 @@ func (err ErrGPGKeyNotExist) Error() string {
return fmt.Sprintf("public gpg key does not exist [id: %d]", err.ID)
}

func (err ErrGPGKeyNotExist) Unwrap() error {
return fs.ErrNotExist
}

// ErrGPGKeyImportNotExist represents a "GPGKeyImportNotExist" kind of error.
type ErrGPGKeyImportNotExist struct {
ID string
Expand All @@ -147,6 +166,10 @@ func (err ErrGPGKeyImportNotExist) Error() string {
return fmt.Sprintf("public gpg key import does not exist [id: %s]", err.ID)
}

func (err ErrGPGKeyImportNotExist) Unwrap() error {
return fs.ErrNotExist
}

// ErrGPGKeyIDAlreadyUsed represents a "GPGKeyIDAlreadyUsed" kind of error.
type ErrGPGKeyIDAlreadyUsed struct {
KeyID string
Expand All @@ -162,6 +185,10 @@ func (err ErrGPGKeyIDAlreadyUsed) Error() string {
return fmt.Sprintf("public key already exists [key_id: %s]", err.KeyID)
}

func (err ErrGPGKeyIDAlreadyUsed) Unwrap() error {
return fs.ErrExist
}

// ErrGPGKeyAccessDenied represents a "GPGKeyAccessDenied" kind of Error.
type ErrGPGKeyAccessDenied struct {
UserID int64
Expand All @@ -180,6 +207,10 @@ func (err ErrGPGKeyAccessDenied) Error() string {
err.UserID, err.KeyID)
}

func (err ErrGPGKeyAccessDenied) Unwrap() error {
return fs.ErrPermission
}

// ErrKeyAccessDenied represents a "KeyAccessDenied" kind of error.
type ErrKeyAccessDenied struct {
UserID int64
Expand All @@ -198,6 +229,10 @@ func (err ErrKeyAccessDenied) Error() string {
err.UserID, err.KeyID, err.Note)
}

func (err ErrKeyAccessDenied) Unwrap() error {
return fs.ErrPermission
}

// ErrDeployKeyNotExist represents a "DeployKeyNotExist" kind of error.
type ErrDeployKeyNotExist struct {
ID int64
Expand All @@ -215,6 +250,10 @@ func (err ErrDeployKeyNotExist) Error() string {
return fmt.Sprintf("Deploy key does not exist [id: %d, key_id: %d, repo_id: %d]", err.ID, err.KeyID, err.RepoID)
}

func (err ErrDeployKeyNotExist) Unwrap() error {
return fs.ErrNotExist
}

// ErrDeployKeyAlreadyExist represents a "DeployKeyAlreadyExist" kind of error.
type ErrDeployKeyAlreadyExist struct {
KeyID int64
Expand All @@ -231,6 +270,10 @@ func (err ErrDeployKeyAlreadyExist) Error() string {
return fmt.Sprintf("public key already exists [key_id: %d, repo_id: %d]", err.KeyID, err.RepoID)
}

func (err ErrDeployKeyAlreadyExist) Unwrap() error {
return fs.ErrExist
}

// ErrDeployKeyNameAlreadyUsed represents a "DeployKeyNameAlreadyUsed" kind of error.
type ErrDeployKeyNameAlreadyUsed struct {
RepoID int64
Expand All @@ -247,6 +290,10 @@ func (err ErrDeployKeyNameAlreadyUsed) Error() string {
return fmt.Sprintf("public key with name already exists [repo_id: %d, name: %s]", err.RepoID, err.Name)
}

func (err ErrDeployKeyNameAlreadyUsed) Unwrap() error {
return fs.ErrNotExist
}

// ErrSSHInvalidTokenSignature represents a "ErrSSHInvalidTokenSignature" kind of error.
type ErrSSHInvalidTokenSignature struct {
Wrapped error
Expand All @@ -262,3 +309,7 @@ func IsErrSSHInvalidTokenSignature(err error) bool {
func (err ErrSSHInvalidTokenSignature) Error() string {
return "the provided signature does not sign the token with the provided key"
}

func (err ErrSSHInvalidTokenSignature) Unwrap() error {
return fs.ErrInvalid
}
11 changes: 11 additions & 0 deletions models/auth/oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"encoding/base32"
"encoding/base64"
"fmt"
"io/fs"
"net/url"
"strings"

Expand Down Expand Up @@ -483,6 +484,11 @@ func (err ErrOAuthClientIDInvalid) Error() string {
return fmt.Sprintf("Client ID invalid [Client ID: %s]", err.ClientID)
}

// Unwrap unwraps this as a ErrNotExist err
func (err ErrOAuthClientIDInvalid) Unwrap() error {
return fs.ErrNotExist
}

// ErrOAuthApplicationNotFound will be thrown if id cannot be found
type ErrOAuthApplicationNotFound struct {
ID int64
Expand All @@ -499,6 +505,11 @@ func (err ErrOAuthApplicationNotFound) Error() string {
return fmt.Sprintf("OAuth application not found [ID: %d]", err.ID)
}

// Unwrap unwraps this as a ErrNotExist err
func (err ErrOAuthApplicationNotFound) Unwrap() error {
return fs.ErrNotExist
}

// GetActiveOAuth2ProviderSources returns all actived LoginOAuth2 sources
func GetActiveOAuth2ProviderSources() ([]*Source, error) {
sources := make([]*Source, 0, 1)
Expand Down
11 changes: 11 additions & 0 deletions models/auth/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package auth

import (
"fmt"
"io/fs"
"reflect"

"code.gitea.io/gitea/models/db"
Expand Down Expand Up @@ -366,6 +367,11 @@ func (err ErrSourceNotExist) Error() string {
return fmt.Sprintf("login source does not exist [id: %d]", err.ID)
}

// Unwrap unwraps this as a ErrNotExist err
func (err ErrSourceNotExist) Unwrap() error {
return fs.ErrNotExist
}

// ErrSourceAlreadyExist represents a "SourceAlreadyExist" kind of error.
type ErrSourceAlreadyExist struct {
Name string
Expand All @@ -381,6 +387,11 @@ func (err ErrSourceAlreadyExist) Error() string {
return fmt.Sprintf("login source already exists [name: %s]", err.Name)
}

// Unwrap unwraps this as a ErrExist err
func (err ErrSourceAlreadyExist) Unwrap() error {
return fs.ErrExist
}

// ErrSourceInUse represents a "SourceInUse" kind of error.
type ErrSourceInUse struct {
ID int64
Expand Down
6 changes: 6 additions & 0 deletions models/auth/twofactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"encoding/base32"
"encoding/base64"
"fmt"
"io/fs"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/secret"
Expand Down Expand Up @@ -41,6 +42,11 @@ func (err ErrTwoFactorNotEnrolled) Error() string {
return fmt.Sprintf("user not enrolled in 2FA [uid: %d]", err.UID)
}

// Unwrap unwraps this as a ErrNotExist err
func (err ErrTwoFactorNotEnrolled) Unwrap() error {
return fs.ErrNotExist
}

// TwoFactor represents a two-factor authentication token.
type TwoFactor struct {
ID int64 `xorm:"pk autoincr"`
Expand Down
6 changes: 6 additions & 0 deletions models/auth/webauthn.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package auth
import (
"context"
"fmt"
"io/fs"
"strings"

"code.gitea.io/gitea/models/db"
Expand All @@ -29,6 +30,11 @@ func (err ErrWebAuthnCredentialNotExist) Error() string {
return fmt.Sprintf("WebAuthn credential does not exist [credential_id: %x]", err.CredentialID)
}

// Unwrap unwraps this as a ErrNotExist err
func (err ErrWebAuthnCredentialNotExist) Unwrap() error {
return fs.ErrNotExist
}

// IsErrWebAuthnCredentialNotExist checks if an error is a ErrWebAuthnCredentialNotExist.
func IsErrWebAuthnCredentialNotExist(err error) bool {
_, ok := err.(ErrWebAuthnCredentialNotExist)
Expand Down
2 changes: 1 addition & 1 deletion models/db/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ func NamesToBean(names ...string) ([]interface{}, error) {
for _, name := range names {
bean, ok := beanMap[strings.ToLower(strings.TrimSpace(name))]
if !ok {
return nil, fmt.Errorf("No table found that matches: %s", name)
return nil, fmt.Errorf("no table found that matches: %s", name)
}
if !gotBean[bean] {
beans = append(beans, bean)
Expand Down
19 changes: 17 additions & 2 deletions models/db/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package db

import (
"fmt"
"io/fs"
)

// ErrCancelled represents an error due to context cancellation
Expand Down Expand Up @@ -45,7 +46,8 @@ func (err ErrSSHDisabled) Error() string {

// ErrNotExist represents a non-exist error.
type ErrNotExist struct {
ID int64
Resource string
ID int64
}

// IsErrNotExist checks if an error is an ErrNotExist
Expand All @@ -55,5 +57,18 @@ func IsErrNotExist(err error) bool {
}

func (err ErrNotExist) Error() string {
return fmt.Sprintf("record does not exist [id: %d]", err.ID)
name := "record"
if err.Resource != "" {
name = err.Resource
}

if err.ID != 0 {
return fmt.Sprintf("%s does not exist [id: %d]", name, err.ID)
}
return fmt.Sprintf("%s does not exist", name)
}

// Unwrap unwraps this as a ErrNotExist err
func (err ErrNotExist) Unwrap() error {
return fs.ErrNotExist
}
31 changes: 28 additions & 3 deletions models/db/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,31 @@
package db

import (
"errors"
"fmt"
"io/fs"
"regexp"
"strings"
"unicode/utf8"
)

var (
// ErrNameEmpty name is empty error
ErrNameEmpty = errors.New("Name is empty")
ErrNameEmpty = errNameEmpty{}

// AlphaDashDotPattern characters prohibited in a user name (anything except A-Za-z0-9_.-)
AlphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)

type errNameEmpty struct{}

func (err errNameEmpty) Error() string {
return "name is empty"
}

func (err errNameEmpty) Unwrap() error {
return fs.ErrInvalid
}

// ErrNameReserved represents a "reserved name" error.
type ErrNameReserved struct {
Name string
Expand All @@ -35,6 +45,11 @@ func (err ErrNameReserved) Error() string {
return fmt.Sprintf("name is reserved [name: %s]", err.Name)
}

// Unwrap unwraps this as a ErrInvalid err
func (err ErrNameReserved) Unwrap() error {
return fs.ErrInvalid
}

// ErrNamePatternNotAllowed represents a "pattern not allowed" error.
type ErrNamePatternNotAllowed struct {
Pattern string
Expand All @@ -50,6 +65,11 @@ func (err ErrNamePatternNotAllowed) Error() string {
return fmt.Sprintf("name pattern is not allowed [pattern: %s]", err.Pattern)
}

// Unwrap unwraps this as a ErrInvalid err
func (err ErrNamePatternNotAllowed) Unwrap() error {
return fs.ErrInvalid
}

// ErrNameCharsNotAllowed represents a "character not allowed in name" error.
type ErrNameCharsNotAllowed struct {
Name string
Expand All @@ -62,7 +82,12 @@ func IsErrNameCharsNotAllowed(err error) bool {
}

func (err ErrNameCharsNotAllowed) Error() string {
return fmt.Sprintf("User name is invalid [%s]: must be valid alpha or numeric or dash(-_) or dot characters", err.Name)
return fmt.Sprintf("name is invalid [%s]: must be valid alpha or numeric or dash(-_) or dot characters", err.Name)
}

// Unwrap unwraps this as a ErrInvalid err
func (err ErrNameCharsNotAllowed) Unwrap() error {
return fs.ErrInvalid
}

// IsUsableName checks if name is reserved or pattern of name is not allowed
Expand Down
Loading

0 comments on commit a86d070

Please sign in to comment.