Skip to content

Commit

Permalink
chore: Remove dependency on go.uber.org/multierr
Browse files Browse the repository at this point in the history
  • Loading branch information
twpayne committed Aug 13, 2023
1 parent 424189b commit 3c72387
Show file tree
Hide file tree
Showing 15 changed files with 118 additions and 83 deletions.
1 change: 0 additions & 1 deletion go.mod
Expand Up @@ -43,7 +43,6 @@ require (
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1
github.com/zalando/go-keyring v0.2.3
go.etcd.io/bbolt v1.3.7
go.uber.org/multierr v1.11.0
golang.org/x/crypto v0.12.0
golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb
golang.org/x/oauth2 v0.11.0
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Expand Up @@ -364,8 +364,6 @@ go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
go.etcd.io/gofail v0.1.0 h1:XItAMIhOojXFQMgrxjnd2EIIHun/d5qL0Pf7FzVTkFg=
go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
Expand Down
6 changes: 3 additions & 3 deletions internal/chezmoi/ageencryption.go
Expand Up @@ -11,8 +11,8 @@ import (

"filippo.io/age"
"filippo.io/age/armor"
"go.uber.org/multierr"

"github.com/twpayne/chezmoi/v2/internal/chezmoierrors"
"github.com/twpayne/chezmoi/v2/internal/chezmoilog"
)

Expand Down Expand Up @@ -251,7 +251,7 @@ func parseIdentityFile(identityFile AbsPath) (identities []age.Identity, err err
if file, err = os.Open(identityFile.String()); err != nil {
return
}
defer multierr.AppendInvoke(&err, multierr.Close(file))
defer chezmoierrors.CombineFunc(&err, file.Close)
identities, err = age.ParseIdentities(file)
return
}
Expand All @@ -263,7 +263,7 @@ func parseRecipientsFile(recipientsFile AbsPath) (recipients []age.Recipient, er
if file, err = os.Open(recipientsFile.String()); err != nil {
return
}
defer multierr.AppendInvoke(&err, multierr.Close(file))
defer chezmoierrors.CombineFunc(&err, file.Close)
recipients, err = age.ParseRecipients(file)
return
}
5 changes: 2 additions & 3 deletions internal/chezmoi/externaldiffsystem.go
Expand Up @@ -12,7 +12,6 @@ import (
"time"

vfs "github.com/twpayne/go-vfs/v4"
"go.uber.org/multierr"

"github.com/twpayne/chezmoi/v2/internal/chezmoilog"
)
Expand Down Expand Up @@ -351,14 +350,14 @@ func (s *ExternalDiffSystem) runDiffCommand(destAbsPath, targetAbsPath AbsPath)
case errors.Is(err2, fs.ErrNotExist):
// Do nothing.
case err2 != nil:
return multierr.Append(err, err2)
return errors.Join(err, err2)
}
targetData, err2 := s.ReadFile(targetAbsPath)
switch {
case errors.Is(err2, fs.ErrNotExist):
// Do nothing.
case err2 != nil:
return multierr.Append(err, err2)
return errors.Join(err, err2)
}
if !bytes.Equal(destData, targetData) {
return nil
Expand Down
9 changes: 4 additions & 5 deletions internal/chezmoi/gpgencryption.go
Expand Up @@ -5,8 +5,7 @@ import (
"os/exec"
"runtime"

"go.uber.org/multierr"

"github.com/twpayne/chezmoi/v2/internal/chezmoierrors"
"github.com/twpayne/chezmoi/v2/internal/chezmoilog"
)

Expand Down Expand Up @@ -152,9 +151,9 @@ func withPrivateTempDir(f func(tempDirAbsPath AbsPath) error) (err error) {
if tempDir, err = os.MkdirTemp("", "chezmoi-encryption"); err != nil {
return
}
defer func() {
err = multierr.Append(err, os.RemoveAll(tempDir))
}()
defer chezmoierrors.CombineFunc(&err, func() error {
return os.RemoveAll(tempDir)
})
if runtime.GOOS != "windows" {
if err = os.Chmod(tempDir, 0o700); err != nil {
return
Expand Down
10 changes: 5 additions & 5 deletions internal/chezmoi/realsystem.go
Expand Up @@ -10,8 +10,8 @@ import (
"time"

vfs "github.com/twpayne/go-vfs/v4"
"go.uber.org/multierr"

"github.com/twpayne/chezmoi/v2/internal/chezmoierrors"
"github.com/twpayne/chezmoi/v2/internal/chezmoilog"
)

Expand Down Expand Up @@ -106,9 +106,9 @@ func (s *RealSystem) RunScript(
if err != nil {
return
}
defer func() {
err = multierr.Append(err, os.RemoveAll(f.Name()))
}()
defer chezmoierrors.CombineFunc(&err, func() error {
return os.RemoveAll(f.Name())
})

// Make the script private before writing it in case it contains any
// secrets.
Expand All @@ -118,7 +118,7 @@ func (s *RealSystem) RunScript(
}
}
_, err = f.Write(data)
err = multierr.Append(err, f.Close())
err = chezmoierrors.Combine(err, f.Close())
if err != nil {
return
}
Expand Down
11 changes: 4 additions & 7 deletions internal/chezmoi/realsystem_unix.go
Expand Up @@ -11,7 +11,8 @@ import (

"github.com/google/renameio/v2"
vfs "github.com/twpayne/go-vfs/v4"
"go.uber.org/multierr"

"github.com/twpayne/chezmoi/v2/internal/chezmoierrors"
)

// An RealSystem is a System that writes to a filesystem and executes scripts.
Expand Down Expand Up @@ -93,9 +94,7 @@ func (s *RealSystem) WriteFile(filename AbsPath, data []byte, perm fs.FileMode)
if t, err = renameio.TempFile(tempDir, filename.String()); err != nil {
return
}
defer func() {
err = multierr.Append(err, t.Cleanup())
}()
defer chezmoierrors.CombineFunc(&err, t.Cleanup)
if err = t.Chmod(perm); err != nil {
return
}
Expand Down Expand Up @@ -132,9 +131,7 @@ func writeFile(fileSystem vfs.FS, filename AbsPath, data []byte, perm fs.FileMod
if f, err = fileSystem.OpenFile(filename.String(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm); err != nil {
return
}
defer func() {
err = multierr.Append(err, f.Close())
}()
defer chezmoierrors.CombineFunc(&err, f.Close)

// Set permissions after truncation but before writing any data, in case the
// file contained private data before, but before writing the new contents,
Expand Down
38 changes: 20 additions & 18 deletions internal/chezmoi/sourcestate.go
Expand Up @@ -30,10 +30,10 @@ import (
"github.com/mitchellh/copystructure"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"go.uber.org/multierr"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"

"github.com/twpayne/chezmoi/v2/internal/chezmoierrors"
"github.com/twpayne/chezmoi/v2/internal/chezmoilog"
)

Expand Down Expand Up @@ -1223,6 +1223,7 @@ func (s *SourceState) Read(ctx context.Context, options *ReadOptions) error {
targetRelPaths = append(targetRelPaths, targetRelPath)
}
sort.Sort(targetRelPaths)
errs := make([]error, 0, len(targetRelPaths))
for _, targetRelPath := range targetRelPaths {
sourceStateEntries := allSourceStateEntries[targetRelPath]
if len(sourceStateEntries) == 1 {
Expand All @@ -1239,13 +1240,13 @@ func (s *SourceState) Read(ctx context.Context, options *ReadOptions) error {
origins = append(origins, sourceStateEntry.Origin().OriginString())
}
sort.Strings(origins)
err = multierr.Append(err, &inconsistentStateError{
errs = append(errs, &inconsistentStateError{
targetRelPath: targetRelPath,
origins: origins,
})
}
if err != nil {
return err
if len(errs) != 0 {
return errors.Join(errs...)
}

// Populate s.Entries with the unique source entry for each target.
Expand Down Expand Up @@ -1611,16 +1612,18 @@ func (s *SourceState) getExternalData(
return nil, err
}

var errs []error

if external.Checksum.Size != 0 {
if len(data) != external.Checksum.Size {
err = multierr.Append(err, fmt.Errorf("size mismatch: expected %d, got %d",
errs = append(errs, fmt.Errorf("size mismatch: expected %d, got %d",
external.Checksum.Size, len(data)))
}
}

if external.Checksum.MD5 != nil {
if gotMD5Sum := md5Sum(data); !bytes.Equal(gotMD5Sum, external.Checksum.MD5) {
err = multierr.Append(err, fmt.Errorf("MD5 mismatch: expected %s, got %s",
errs = append(errs, fmt.Errorf("MD5 mismatch: expected %s, got %s",
external.Checksum.MD5, hex.EncodeToString(gotMD5Sum)))
}
}
Expand All @@ -1630,41 +1633,41 @@ func (s *SourceState) getExternalData(
gotRIPEMD160Sum,
external.Checksum.RIPEMD160,
) {
err = multierr.Append(err, fmt.Errorf("RIPEMD-160 mismatch: expected %s, got %s",
errs = append(errs, fmt.Errorf("RIPEMD-160 mismatch: expected %s, got %s",
external.Checksum.RIPEMD160, hex.EncodeToString(gotRIPEMD160Sum)))
}
}

if external.Checksum.SHA1 != nil {
if gotSHA1Sum := sha1Sum(data); !bytes.Equal(gotSHA1Sum, external.Checksum.SHA1) {
err = multierr.Append(err, fmt.Errorf("SHA1 mismatch: expected %s, got %s",
errs = append(errs, fmt.Errorf("SHA1 mismatch: expected %s, got %s",
external.Checksum.SHA1, hex.EncodeToString(gotSHA1Sum)))
}
}

if external.Checksum.SHA256 != nil {
if gotSHA256Sum := SHA256Sum(data); !bytes.Equal(gotSHA256Sum, external.Checksum.SHA256) {
err = multierr.Append(err, fmt.Errorf("SHA256 mismatch: expected %s, got %s",
errs = append(errs, fmt.Errorf("SHA256 mismatch: expected %s, got %s",
external.Checksum.SHA256, hex.EncodeToString(gotSHA256Sum)))
}
}

if external.Checksum.SHA384 != nil {
if gotSHA384Sum := sha384Sum(data); !bytes.Equal(gotSHA384Sum, external.Checksum.SHA384) {
err = multierr.Append(err, fmt.Errorf("SHA384 mismatch: expected %s, got %s",
errs = append(errs, fmt.Errorf("SHA384 mismatch: expected %s, got %s",
external.Checksum.SHA384, hex.EncodeToString(gotSHA384Sum)))
}
}

if external.Checksum.SHA512 != nil {
if gotSHA512Sum := sha512Sum(data); !bytes.Equal(gotSHA512Sum, external.Checksum.SHA512) {
err = multierr.Append(err, fmt.Errorf("SHA512 mismatch: expected %s, got %s",
errs = append(errs, fmt.Errorf("SHA512 mismatch: expected %s, got %s",
external.Checksum.SHA512, hex.EncodeToString(gotSHA512Sum)))
}
}

if err != nil {
return nil, fmt.Errorf("%s: %w", externalRelPath, err)
if len(errs) != 0 {
return nil, fmt.Errorf("%s: %w", externalRelPath, errors.Join(errs...))
}

if external.Encrypted {
Expand Down Expand Up @@ -1875,17 +1878,16 @@ func (s *SourceState) newModifyTargetStateEntryFunc(
if tempFile, err = os.CreateTemp("", "*."+fileAttr.TargetName); err != nil {
return
}
defer func() {
err = multierr.Append(err, os.RemoveAll(tempFile.Name()))
}()
defer chezmoierrors.CombineFunc(&err, func() error {
return os.RemoveAll(tempFile.Name())
})
if runtime.GOOS != "windows" {
if err = tempFile.Chmod(0o700); err != nil {
return
}
}
_, err = tempFile.Write(modifierContents)
multierr.AppendInvoke(&err, multierr.Close(tempFile))
if err != nil {
if chezmoierrors.CombineFunc(&err, tempFile.Close); err != nil {
return
}

Expand Down
40 changes: 40 additions & 0 deletions internal/chezmoierrors/chezmoierrors.go
@@ -0,0 +1,40 @@
// Package chezmoierrors contains convenience functions for combining multiple
// errors.
package chezmoierrors

import "errors"

// Combine combines all non-nil errors in errs into one. If there are no non-nil
// errors, it returns nil. If there is exactly one non-nil error then it returns
// that error. Otherwise, it returns the non-nil errors combined with
// errors.Join.
func Combine(errs ...error) error {
nonNilErrs := make([]error, 0, len(errs))
for _, err := range errs {
if err != nil {
nonNilErrs = append(nonNilErrs, err)
}
}
switch len(nonNilErrs) {
case 0:
return nil
case 1:
return nonNilErrs[0]
default:
return errors.Join(nonNilErrs...)
}
}

// CombineClose combines the error pointed to by errp with the result of calling
// closer.Close().
func CombineClose(errp *error, closer interface{ Close() error }) {
CombineFunc(errp, closer.Close)
}

// CombineFunc combines the error pointed to by errp with the result of calling
// f.
func CombineFunc(errp *error, f func() error) {
if err := f(); err != nil {
*errp = Combine(*errp, err)
}
}
6 changes: 3 additions & 3 deletions internal/cmd/cmd.go
Expand Up @@ -14,10 +14,10 @@ import (
"github.com/rs/zerolog"
"github.com/spf13/cobra"
"go.etcd.io/bbolt"
"go.uber.org/multierr"

"github.com/twpayne/chezmoi/v2/assets/chezmoi.io/docs/reference/commands"
"github.com/twpayne/chezmoi/v2/internal/chezmoi"
"github.com/twpayne/chezmoi/v2/internal/chezmoierrors"
)

// GitHub owner and repo for chezmoi itself.
Expand Down Expand Up @@ -208,7 +208,7 @@ func extractHelp(
// registerExcludeIncludeFlagCompletionFuncs registers the flag completion
// functions for the include and exclude flags of cmd. It panics on any error.
func registerExcludeIncludeFlagCompletionFuncs(cmd *cobra.Command) {
if err := multierr.Combine(
if err := chezmoierrors.Combine(
cmd.RegisterFlagCompletionFunc("exclude", chezmoi.EntryTypeSetFlagCompletionFunc),
cmd.RegisterFlagCompletionFunc("include", chezmoi.EntryTypeSetFlagCompletionFunc),
); err != nil {
Expand Down Expand Up @@ -281,7 +281,7 @@ func runMain(versionInfo VersionInfo, args []string) (err error) {
); err != nil {
return err
}
defer multierr.AppendInvoke(&err, multierr.Close(config))
defer chezmoierrors.CombineFunc(&err, config.Close)
err = config.execute(args)
if errors.Is(err, bbolt.ErrTimeout) {
// Translate bbolt timeout errors into a friendlier message. As the
Expand Down

0 comments on commit 3c72387

Please sign in to comment.