Skip to content

Commit

Permalink
Merge pull request twpayne#1116 from twpayne/fix-1115
Browse files Browse the repository at this point in the history
Fix upgrade command for older versions
  • Loading branch information
twpayne committed Mar 30, 2021
2 parents 75681a7 + 58aac9b commit d59ca5d
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 33 deletions.
1 change: 1 addition & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ builds:

archives:
- builds:
- chezmoi-cgo-glibc # Required for chezmoi upgrade for versions <= 2.0.5
- chezmoi-nocgo
files:
- LICENSE
Expand Down
22 changes: 11 additions & 11 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ const (
var (
noArgs = []string(nil)

commandsRegexp = regexp.MustCompile(`^## Commands`)
commandRegexp = regexp.MustCompile("^### `(\\S+)`")
exampleRegexp = regexp.MustCompile("^#### `\\w+` examples")
endOfCommandsRegexp = regexp.MustCompile(`^## `)
trailingSpaceRegexp = regexp.MustCompile(` +\n`)
commandsRx = regexp.MustCompile(`^## Commands`)
commandRx = regexp.MustCompile("^### `(\\S+)`")
exampleRx = regexp.MustCompile("^#### `\\w+` examples")
endOfCommandsRx = regexp.MustCompile(`^## `)
trailingSpaceRx = regexp.MustCompile(` +\n`)

helps map[string]*help
)
Expand Down Expand Up @@ -154,7 +154,7 @@ func extractHelps(r io.Reader) (map[string]*help, error) {
if err != nil {
return err
}
s = trailingSpaceRegexp.ReplaceAllString(s, "\n")
s = trailingSpaceRx.ReplaceAllString(s, "\n")
s = strings.Trim(s, "\n")
switch state {
case "in-command":
Expand All @@ -174,17 +174,17 @@ FOR:
for s.Scan() {
switch state {
case "find-commands":
if commandsRegexp.MatchString(s.Text()) {
if commandsRx.MatchString(s.Text()) {
state = "find-first-command"
}
case "find-first-command":
if m := commandRegexp.FindStringSubmatch(s.Text()); m != nil {
if m := commandRx.FindStringSubmatch(s.Text()); m != nil {
h = &help{}
helps[m[1]] = h
state = "in-command"
}
case "in-command", "in-example":
m := commandRegexp.FindStringSubmatch(s.Text())
m := commandRx.FindStringSubmatch(s.Text())
switch {
case m != nil:
if err := saveAndReset(); err != nil {
Expand All @@ -193,12 +193,12 @@ FOR:
h = &help{}
helps[m[1]] = h
state = "in-command"
case exampleRegexp.MatchString(s.Text()):
case exampleRx.MatchString(s.Text()):
if err := saveAndReset(); err != nil {
return nil, err
}
state = "in-example"
case endOfCommandsRegexp.MatchString(s.Text()):
case endOfCommandsRx.MatchString(s.Text()):
if err := saveAndReset(); err != nil {
return nil, err
}
Expand Down
45 changes: 42 additions & 3 deletions cmd/upgradecmd_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const (
methodUpgradePackage = "upgrade-package"
methodSudoPrefix = "sudo-"

libcTypeGlibc = "glibc"
libcTypeMusl = "musl"

packageTypeNone = ""
packageTypeAPK = "apk"
packageTypeAUR = "aur"
Expand Down Expand Up @@ -70,7 +73,9 @@ var (
},
}

checksumRegexp = regexp.MustCompile(`\A([0-9a-f]{64})\s+(\S+)\z`)
checksumRx = regexp.MustCompile(`\A([0-9a-f]{64})\s+(\S+)\z`)
libcTypeGlibcRx = regexp.MustCompile(`(?i)glibc|gnu libc`)
libcTypeMuslRx = regexp.MustCompile(`(?i)musl`)
)

func (c *Config) runUpgradeCmd(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -173,7 +178,7 @@ func (c *Config) getChecksums(ctx context.Context, rr *github.RepositoryRelease)
checksums := make(map[string][]byte)
s := bufio.NewScanner(bytes.NewReader(data))
for s.Scan() {
m := checksumRegexp.FindStringSubmatch(s.Text())
m := checksumRx.FindStringSubmatch(s.Text())
if m == nil {
return nil, fmt.Errorf("%q: cannot parse checksum", s.Text())
}
Expand Down Expand Up @@ -212,8 +217,42 @@ func (c *Config) downloadURL(ctx context.Context, url string) ([]byte, error) {
return data, nil
}

// getLibc attempts to determine the system's libc.
func (c *Config) getLibc() (string, error) {
// First, try parsing the output of ldd --version. On glibc systems it
// writes to stdout and exits with code 0. On musl libc systems it writes to
// stderr and exits with code 1.
lddCmd := exec.Command("ldd", "--version")
if output, _ := c.baseSystem.IdempotentCmdCombinedOutput(lddCmd); len(output) != 0 {
switch {
case libcTypeGlibcRx.Match(output):
return libcTypeGlibc, nil
case libcTypeMuslRx.Match(output):
return libcTypeMusl, nil
}
}

// Second, try getconf GNU_LIBC_VERSION.
getconfCmd := exec.Command("getconf", "GNU_LIBC_VERSION")
if output, err := c.baseSystem.IdempotentCmdOutput(getconfCmd); err != nil {
if libcTypeGlibcRx.Match(output) {
return libcTypeGlibc, nil
}
}

return "", errors.New("unable to determine libc")
}

func (c *Config) replaceExecutable(ctx context.Context, executableFilenameAbsPath chezmoi.AbsPath, releaseVersion *semver.Version, rr *github.RepositoryRelease) error {
name := fmt.Sprintf("%s_%s_%s_%s.tar.gz", c.upgrade.repo, releaseVersion, runtime.GOOS, runtime.GOARCH)
goos := runtime.GOOS
if goos == "linux" {
libc, err := c.getLibc()
if err != nil {
return err
}
goos += "-" + libc
}
name := fmt.Sprintf("%s_%s_%s_%s.tar.gz", c.upgrade.repo, releaseVersion, goos, runtime.GOARCH)
releaseAsset := getReleaseAssetByName(rr, name)
if releaseAsset == nil {
return fmt.Errorf("%s: cannot find release asset", name)
Expand Down
12 changes: 12 additions & 0 deletions internal/chezmoi/debugsystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ func (s *DebugSystem) Glob(name string) ([]string, error) {
return matches, err
}

// IdempotentCmdCombinedOutput implements System.IdempotentCmdCombinedOutput.
func (s *DebugSystem) IdempotentCmdCombinedOutput(cmd *exec.Cmd) ([]byte, error) {
output, err := s.system.IdempotentCmdCombinedOutput(cmd)
log.Logger.Debug().
EmbedObject(chezmoilog.OSExecCmdLogObject{Cmd: cmd}).
Bytes("output", chezmoilog.FirstFewBytes(output)).
Err(err).
EmbedObject(chezmoilog.OSExecExitErrorLogObject{Err: err}).
Msg("IdempotentCmdCombinedOutput")
return output, err
}

// IdempotentCmdOutput implements System.IdempotentCmdOutput.
func (s *DebugSystem) IdempotentCmdOutput(cmd *exec.Cmd) ([]byte, error) {
output, err := s.system.IdempotentCmdOutput(cmd)
Expand Down
5 changes: 5 additions & 0 deletions internal/chezmoi/dryrunsystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ func (s *DryRunSystem) Glob(pattern string) ([]string, error) {
return s.system.Glob(pattern)
}

// IdempotentCmdCombinedOutput implements System.IdempotentCmdCombinedOutput.
func (s *DryRunSystem) IdempotentCmdCombinedOutput(cmd *exec.Cmd) ([]byte, error) {
return s.system.IdempotentCmdCombinedOutput(cmd)
}

// IdempotentCmdOutput implements System.IdempotentCmdOutput.
func (s *DryRunSystem) IdempotentCmdOutput(cmd *exec.Cmd) ([]byte, error) {
return s.system.IdempotentCmdOutput(cmd)
Expand Down
5 changes: 5 additions & 0 deletions internal/chezmoi/gitdiffsystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ func (s *GitDiffSystem) Glob(pattern string) ([]string, error) {
return s.system.Glob(pattern)
}

// IdempotentCmdCombinedOutput implements System.IdempotentCmdCombinedOutput.
func (s *GitDiffSystem) IdempotentCmdCombinedOutput(cmd *exec.Cmd) ([]byte, error) {
return s.system.IdempotentCmdCombinedOutput(cmd)
}

// IdempotentCmdOutput implements System.IdempotentCmdOutput.
func (s *GitDiffSystem) IdempotentCmdOutput(cmd *exec.Cmd) ([]byte, error) {
return s.system.IdempotentCmdOutput(cmd)
Expand Down
5 changes: 5 additions & 0 deletions internal/chezmoi/readonlysystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ func (s *ReadOnlySystem) Glob(pattern string) ([]string, error) {
return s.system.Glob(pattern)
}

// IdempotentCmdCombinedOutput implements System.IdempotentCmdCombinedOutput.
func (s *ReadOnlySystem) IdempotentCmdCombinedOutput(cmd *exec.Cmd) ([]byte, error) {
return s.system.IdempotentCmdCombinedOutput(cmd)
}

// IdempotentCmdOutput implements System.IdempotentCmdOutput.
func (s *ReadOnlySystem) IdempotentCmdOutput(cmd *exec.Cmd) ([]byte, error) {
return s.system.IdempotentCmdOutput(cmd)
Expand Down
5 changes: 5 additions & 0 deletions internal/chezmoi/realsystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ func (s *RealSystem) Glob(pattern string) ([]string, error) {
return doublestar.GlobOS(doubleStarOS{FS: s.UnderlyingFS()}, pattern)
}

// IdempotentCmdCombinedOutput implements System.IdempotentCmdCombinedOutput.
func (s *RealSystem) IdempotentCmdCombinedOutput(cmd *exec.Cmd) ([]byte, error) {
return chezmoilog.LogCmdCombinedOutput(log.Logger, cmd)
}

// IdempotentCmdOutput implements System.IdempotentCmdOutput.
func (s *RealSystem) IdempotentCmdOutput(cmd *exec.Cmd) ([]byte, error) {
return chezmoilog.LogCmdOutput(log.Logger, cmd)
Expand Down
20 changes: 11 additions & 9 deletions internal/chezmoi/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
type System interface {
Chmod(name AbsPath, mode os.FileMode) error
Glob(pattern string) ([]string, error)
IdempotentCmdCombinedOutput(cmd *exec.Cmd) ([]byte, error)
IdempotentCmdOutput(cmd *exec.Cmd) ([]byte, error)
Lstat(filename AbsPath) (os.FileInfo, error)
Mkdir(name AbsPath, perm os.FileMode) error
Expand All @@ -33,15 +34,16 @@ type System interface {
// A emptySystemMixin simulates an empty system.
type emptySystemMixin struct{}

func (emptySystemMixin) Glob(pattern string) ([]string, error) { return nil, nil }
func (emptySystemMixin) IdempotentCmdOutput(cmd *exec.Cmd) ([]byte, error) { return nil, nil }
func (emptySystemMixin) Lstat(name AbsPath) (os.FileInfo, error) { return nil, os.ErrNotExist }
func (emptySystemMixin) RawPath(path AbsPath) (AbsPath, error) { return path, nil }
func (emptySystemMixin) ReadDir(name AbsPath) ([]os.DirEntry, error) { return nil, os.ErrNotExist }
func (emptySystemMixin) ReadFile(name AbsPath) ([]byte, error) { return nil, os.ErrNotExist }
func (emptySystemMixin) Readlink(name AbsPath) (string, error) { return "", os.ErrNotExist }
func (emptySystemMixin) Stat(name AbsPath) (os.FileInfo, error) { return nil, os.ErrNotExist }
func (emptySystemMixin) UnderlyingFS() vfs.FS { return nil }
func (emptySystemMixin) Glob(pattern string) ([]string, error) { return nil, nil }
func (emptySystemMixin) IdempotentCmdCombinedOutput(cmd *exec.Cmd) ([]byte, error) { return nil, nil }
func (emptySystemMixin) IdempotentCmdOutput(cmd *exec.Cmd) ([]byte, error) { return nil, nil }
func (emptySystemMixin) Lstat(name AbsPath) (os.FileInfo, error) { return nil, os.ErrNotExist }
func (emptySystemMixin) RawPath(path AbsPath) (AbsPath, error) { return path, nil }
func (emptySystemMixin) ReadDir(name AbsPath) ([]os.DirEntry, error) { return nil, os.ErrNotExist }
func (emptySystemMixin) ReadFile(name AbsPath) ([]byte, error) { return nil, os.ErrNotExist }
func (emptySystemMixin) Readlink(name AbsPath) (string, error) { return "", os.ErrNotExist }
func (emptySystemMixin) Stat(name AbsPath) (os.FileInfo, error) { return nil, os.ErrNotExist }
func (emptySystemMixin) UnderlyingFS() vfs.FS { return nil }

// A noUpdateSystemMixin panics on any update.
type noUpdateSystemMixin struct{}
Expand Down
20 changes: 10 additions & 10 deletions internal/git/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ type Status struct {
}

var (
statusPorcelainV2ZOrdinaryRegexp = regexp.MustCompile(`` +
statusPorcelainV2ZOrdinaryRx = regexp.MustCompile(`` +
`^1 ` +
`([!\.\?ACDMRU])([!\.\?ACDMRU]) ` +
`(N\.\.\.|S[\.C][\.M][\.U]) ` +
Expand All @@ -87,7 +87,7 @@ var (
`(.*)` +
`$`,
)
statusPorcelainV2ZRenamedOrCopiedRegexp = regexp.MustCompile(`` +
statusPorcelainV2ZRenamedOrCopiedRx = regexp.MustCompile(`` +
`^2 ` +
`([!\.\?ACDMRU])([!\.\?ACDMRU]) ` +
`(N\.\.\.|S[\.C][\.M][\.U]) ` +
Expand All @@ -100,7 +100,7 @@ var (
`(.*?)\t(.*)` +
`$`,
)
statusPorcelainV2ZUnmergedRegexp = regexp.MustCompile(`` +
statusPorcelainV2ZUnmergedRx = regexp.MustCompile(`` +
`^u ` +
`([!\.\?ACDMRU])([!\.\?ACDMRU]) ` +
`(N\.\.\.|S[\.C][\.M][\.U]) ` +
Expand All @@ -114,12 +114,12 @@ var (
`(.*)` +
`$`,
)
statusPorcelainV2ZUntrackedRegexp = regexp.MustCompile(`` +
statusPorcelainV2ZUntrackedRx = regexp.MustCompile(`` +
`^\? ` +
`(.*)` +
`$`,
)
statusPorcelainV2ZIgnoredRegexp = regexp.MustCompile(`` +
statusPorcelainV2ZIgnoredRx = regexp.MustCompile(`` +
`^! ` +
`(.*)` +
`$`,
Expand All @@ -140,7 +140,7 @@ func ParseStatusPorcelainV2(output []byte) (*Status, error) {
text := s.Text()
switch text[0] {
case '1':
m := statusPorcelainV2ZOrdinaryRegexp.FindStringSubmatchIndex(text)
m := statusPorcelainV2ZOrdinaryRx.FindStringSubmatchIndex(text)
if m == nil {
return nil, ParseError(text)
}
Expand Down Expand Up @@ -169,7 +169,7 @@ func ParseStatusPorcelainV2(output []byte) (*Status, error) {
}
status.Ordinary = append(status.Ordinary, os)
case '2':
m := statusPorcelainV2ZRenamedOrCopiedRegexp.FindStringSubmatchIndex(text)
m := statusPorcelainV2ZRenamedOrCopiedRx.FindStringSubmatchIndex(text)
if m == nil {
return nil, ParseError(text)
}
Expand Down Expand Up @@ -205,7 +205,7 @@ func ParseStatusPorcelainV2(output []byte) (*Status, error) {
}
status.RenamedOrCopied = append(status.RenamedOrCopied, rocs)
case 'u':
m := statusPorcelainV2ZUnmergedRegexp.FindStringSubmatchIndex(text)
m := statusPorcelainV2ZUnmergedRx.FindStringSubmatchIndex(text)
if m == nil {
return nil, ParseError(text)
}
Expand Down Expand Up @@ -236,7 +236,7 @@ func ParseStatusPorcelainV2(output []byte) (*Status, error) {
}
status.Unmerged = append(status.Unmerged, us)
case '?':
m := statusPorcelainV2ZUntrackedRegexp.FindStringSubmatchIndex(text)
m := statusPorcelainV2ZUntrackedRx.FindStringSubmatchIndex(text)
if m == nil {
return nil, ParseError(text)
}
Expand All @@ -245,7 +245,7 @@ func ParseStatusPorcelainV2(output []byte) (*Status, error) {
}
status.Untracked = append(status.Untracked, us)
case '!':
m := statusPorcelainV2ZIgnoredRegexp.FindStringSubmatchIndex(text)
m := statusPorcelainV2ZIgnoredRx.FindStringSubmatchIndex(text)
if m == nil {
return nil, ParseError(text)
}
Expand Down

0 comments on commit d59ca5d

Please sign in to comment.