Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package chezmoi for openSUSE:Factory checked in at 2023-01-24 20:42:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/chezmoi (Old) and /work/SRC/openSUSE:Factory/.chezmoi.new.32243 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "chezmoi" Tue Jan 24 20:42:52 2023 rev:11 rq:1060686 version:2.29.3 Changes: -------- --- /work/SRC/openSUSE:Factory/chezmoi/chezmoi.changes 2023-01-16 18:02:18.527959803 +0100 +++ /work/SRC/openSUSE:Factory/.chezmoi.new.32243/chezmoi.changes 2023-01-24 20:59:41.261520298 +0100 @@ -1,0 +2,10 @@ +Tue Jan 24 18:10:48 UTC 2023 - Filippo Bonazzi <filippo.bona...@suse.com> + +- Update to version 2.29.3: + * feat: Add --recursive flag to chattr command + * feat: Check config file format in doctor command + * fix: Support .zip files with empty internal directories + * fix: Only prompt once for KeePassXC password + * fix: Remove problematic username guessing in init command + +------------------------------------------------------------------- Old: ---- chezmoi-2.29.2.obscpio New: ---- chezmoi-2.29.3.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ chezmoi.spec ++++++ --- /var/tmp/diff_new_pack.hM5tAD/_old 2023-01-24 20:59:43.333532264 +0100 +++ /var/tmp/diff_new_pack.hM5tAD/_new 2023-01-24 20:59:43.337532287 +0100 @@ -17,7 +17,7 @@ Name: chezmoi -Version: 2.29.2 +Version: 2.29.3 Release: 0 Summary: A multi-host manager for dotfiles License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.hM5tAD/_old 2023-01-24 20:59:43.369532472 +0100 +++ /var/tmp/diff_new_pack.hM5tAD/_new 2023-01-24 20:59:43.373532495 +0100 @@ -2,7 +2,7 @@ <service name="obs_scm" mode="manual"> <param name="scm">git</param> <param name="url">https://github.com/twpayne/chezmoi.git</param> - <param name="revision">v2.29.2</param> + <param name="revision">v2.29.3</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> </service> ++++++ chezmoi-2.29.2.obscpio -> chezmoi-2.29.3.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/.github/workflows/main.yml new/chezmoi-2.29.3/.github/workflows/main.yml --- old/chezmoi-2.29.2/.github/workflows/main.yml 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/.github/workflows/main.yml 2023-01-19 21:40:03.000000000 +0100 @@ -425,17 +425,21 @@ GITHUB_TOKEN: ${{ secrets.GORELEASER_GITHUB_TOKEN }} SCOOP_GITHUB_TOKEN: ${{ secrets.SCOOP_GITHUB_TOKEN }} SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }} - # The following is needed because chezmoi upgrade and - # assets/scripts/install.sh have inconsistently looked for - # chezmoi_${VERSION}_checksums.txt and checksums.txt. To ensure - # compatibility with all versions, upload checksums.txt as well. + # The following is needed because chezmoi upgrade and + # assets/scripts/install.sh have inconsistently looked for + # chezmoi_${VERSION}_checksums.txt and checksums.txt. To ensure + # compatibility with all versions, upload checksums.txt as well. + # + # We need to use a different GitHub token as fine-grained personal access + # tokens do not allow access to the GraphQL API, which gh depends on. So, we + # use a normal PAT instead. - name: upload-checksums.txt run: | VERSION=${GITHUB_REF##*/v} cp dist/chezmoi_${VERSION}_checksums.txt dist/checksums.txt gh release upload v${VERSION} dist/checksums.txt env: - GITHUB_TOKEN: ${{ secrets.GORELEASER_GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.RELEASE_GITHUB_TOKEN }} deploy-website: needs: - release diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/assets/chezmoi.io/docs/links/articles-podcasts-and-videos.md.yaml new/chezmoi-2.29.3/assets/chezmoi.io/docs/links/articles-podcasts-and-videos.md.yaml --- old/chezmoi-2.29.2/assets/chezmoi.io/docs/links/articles-podcasts-and-videos.md.yaml 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/assets/chezmoi.io/docs/links/articles-podcasts-and-videos.md.yaml 2023-01-19 21:40:03.000000000 +0100 @@ -323,3 +323,7 @@ title: 'Chezmoiã§ããããã¯ãã¹ãã©ãããã©ã¼ã dotfiles管çã®ã¹ã¹ã¡' lang: JP url: https://deflis.hatenablog.com/entry/hatena-advent-calendar-2022-chezmoi-dotfiles +- date: '2023-01-13' + version: 2.29.1 + title: 'Making the most out of distrobox and toolbx' + url: https://www.ypsidanger.com/making-the-most-out-of-distrobox-and-toolbx/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/assets/chezmoi.io/docs/user-guide/tools/merge.md new/chezmoi-2.29.3/assets/chezmoi.io/docs/user-guide/tools/merge.md --- old/chezmoi-2.29.2/assets/chezmoi.io/docs/user-guide/tools/merge.md 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/assets/chezmoi.io/docs/user-guide/tools/merge.md 2023-01-19 21:40:03.000000000 +0100 @@ -2,9 +2,9 @@ ## Use a custom merge command -By default, chezmoi uses `vimdiff.` You can use a custom command by setting the +By default, chezmoi uses `vimdiff`. You can use a custom command by setting the `merge.command` and `merge.args` configuration variables. The elements of -`merge.args` are interprested as templates with the variables `.Destination`, +`merge.args` are interpreted as templates with the variables `.Destination`, `.Source`, and `.Target` containing filenames of the file in the destination state, source state, and target state respectively. For example, to use [neovim's diff mode](https://neovim.io/doc/user/diff.html), specify: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/chezmoi/archive.go new/chezmoi-2.29.3/pkg/chezmoi/archive.go --- old/chezmoi-2.29.2/pkg/chezmoi/archive.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/chezmoi/archive.go 2023-01-19 21:40:03.000000000 +0100 @@ -12,6 +12,7 @@ "io/fs" "path" "strings" + "time" "github.com/ulikunitz/xz" ) @@ -132,10 +133,40 @@ return err == nil } +func implicitDirHeader(dir string, modTime time.Time) *tar.Header { + return &tar.Header{ + Typeflag: tar.TypeDir, + Name: dir, + Mode: 0o777, + Size: 0, + ModTime: modTime, + } +} + // walkArchiveTar walks over all the entries in a tar archive. func walkArchiveTar(r io.Reader, f WalkArchiveFunc) error { tarReader := tar.NewReader(r) var skippedDirPrefixes []string + seenDirs := newSet[string]() + processHeader := func(header *tar.Header, dir string) error { + for _, skippedDirPrefix := range skippedDirPrefixes { + if strings.HasPrefix(header.Name, skippedDirPrefix) { + return fs.SkipDir + } + } + if seenDirs.contains(dir) { + return nil + } + seenDirs.add(dir) + name := strings.TrimSuffix(header.Name, "/") + switch err := f(name, header.FileInfo(), tarReader, header.Linkname); { + case errors.Is(err, fs.SkipDir): + skippedDirPrefixes = append(skippedDirPrefixes, header.Name) + case err != nil: + return err + } + return nil + } HEADER: for { header, err := tarReader.Next() @@ -145,24 +176,28 @@ case err != nil: return err } - for _, skippedDirPrefix := range skippedDirPrefixes { - if strings.HasPrefix(header.Name, skippedDirPrefix) { - continue HEADER - } - } - name := strings.TrimSuffix(header.Name, "/") switch header.Typeflag { - case tar.TypeDir, tar.TypeReg: - switch err := f(name, header.FileInfo(), tarReader, ""); { - case errors.Is(err, fs.SkipDir): - skippedDirPrefixes = append(skippedDirPrefixes, header.Name) - case errors.Is(err, Break): - return nil - case err != nil: - return err + case tar.TypeReg, tar.TypeDir, tar.TypeSymlink: + if header.Typeflag == tar.TypeReg { + dirs, _ := path.Split(header.Name) + dirComponents := strings.Split(strings.TrimSuffix(dirs, "/"), "/") + for i := range dirComponents { + dir := strings.Join(dirComponents[0:i+1], "/") + if len(dir) > 0 { + switch err := processHeader(implicitDirHeader(dir+"/", header.ModTime), dir+"/"); { + case errors.Is(err, fs.SkipDir): + continue HEADER + case errors.Is(err, Break): + return nil + case err != nil: + return err + } + } + } } - case tar.TypeSymlink: - switch err := f(name, header.FileInfo(), nil, header.Linkname); { + switch err := processHeader(header, header.Name); { + case errors.Is(err, fs.SkipDir): + continue HEADER case errors.Is(err, Break): return nil case err != nil: @@ -183,6 +218,28 @@ return err } var skippedDirPrefixes []string + seenDirs := newSet[string]() + processHeader := func(fileInfo fs.FileInfo, dir string) error { + for _, skippedDirPrefix := range skippedDirPrefixes { + if strings.HasPrefix(dir, skippedDirPrefix) { + return fs.SkipDir + } + } + if seenDirs.contains(dir) { + return nil + } + seenDirs.add(dir) + name := strings.TrimSuffix(dir, "/") + dirFileInfo := implicitDirHeader(dir, fileInfo.ModTime()).FileInfo() + switch err := f(name, dirFileInfo, nil, ""); { + case errors.Is(err, fs.SkipDir): + skippedDirPrefixes = append(skippedDirPrefixes, dir) + return err + case err != nil: + return err + } + return nil + } FILE: for _, zipFile := range zipReader.File { zipFileReader, err := zipFile.Open() @@ -203,9 +260,25 @@ switch fileInfo := zipFile.FileInfo(); fileInfo.Mode() & fs.ModeType { case 0: + dirs, _ := path.Split(name) + dirComponents := strings.Split(strings.TrimSuffix(dirs, "/"), "/") + for i := range dirComponents { + dir := strings.Join(dirComponents[0:i+1], "/") + if len(dir) > 0 { + switch err := processHeader(fileInfo, dir+"/"); { + case errors.Is(err, fs.SkipDir): + continue FILE + case errors.Is(err, Break): + return nil + case err != nil: + return err + } + } + } + err = f(name, fileInfo, zipFileReader, "") case fs.ModeDir: - err = f(name, fileInfo, nil, "") + err = processHeader(fileInfo, name+"/") case fs.ModeSymlink: var linknameBytes []byte linknameBytes, err = io.ReadAll(zipFileReader) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/chezmoi/archive_test.go new/chezmoi-2.29.3/pkg/chezmoi/archive_test.go --- old/chezmoi-2.29.2/pkg/chezmoi/archive_test.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/chezmoi/archive_test.go 2023-01-19 21:40:03.000000000 +0100 @@ -12,50 +12,79 @@ ) func TestWalkArchive(t *testing.T) { + nestedRoot := map[string]any{ + "dir1": map[string]any{ + "subdir1": map[string]any{ + "file1": "", + "file2": "", + }, + "subdir2": map[string]any{ + "file1": "", + "file2": "", + }, + }, + "dir2": map[string]any{ + "subdir1": map[string]any{ + "file1": "", + "file2": "", + }, + "subdir2": map[string]any{ + "file1": "", + "file2": "", + }, + }, + "file1": "", + "file2": "", + "symlink1": &archivetest.Symlink{Target: "file1"}, + "symlink2": &archivetest.Symlink{Target: "file2"}, + } + flatRoot := map[string]any{ + "dir1/subdir1/file1": "", + "dir1/subdir1/file2": "", + "dir1/subdir2/file1": "", + "dir1/subdir2/file2": "", + "dir2/subdir1/file1": "", + "dir2/subdir1/file2": "", + "dir2/subdir2/file1": "", + "dir2/subdir2/file2": "", + "file1": "", + "file2": "", + "symlink1": &archivetest.Symlink{Target: "file1"}, + "symlink2": &archivetest.Symlink{Target: "file2"}, + } for _, tc := range []struct { name string + root map[string]any dataFunc func(map[string]any) ([]byte, error) archiveFormat ArchiveFormat }{ { name: "tar", + root: nestedRoot, dataFunc: archivetest.NewTar, archiveFormat: ArchiveFormatTar, }, { name: "zip", + root: nestedRoot, + dataFunc: archivetest.NewZip, + archiveFormat: ArchiveFormatZip, + }, + { + name: "zip-flat", + root: flatRoot, dataFunc: archivetest.NewZip, archiveFormat: ArchiveFormatZip, }, + { + name: "tar-flat", + root: flatRoot, + dataFunc: archivetest.NewTar, + archiveFormat: ArchiveFormatTar, + }, } { t.Run(tc.name, func(t *testing.T) { - root := map[string]any{ - "dir1": map[string]any{ - "subdir1": map[string]any{ - "file1": "", - "file2": "", - }, - "subdir2": map[string]any{ - "file1": "", - "file2": "", - }, - }, - "dir2": map[string]any{ - "subdir1": map[string]any{ - "file1": "", - "file2": "", - }, - "subdir2": map[string]any{ - "file1": "", - "file2": "", - }, - }, - "file1": "", - "file2": "", - "symlink1": &archivetest.Symlink{Target: "file1"}, - "symlink2": &archivetest.Symlink{Target: "file2"}, - } - data, err := tc.dataFunc(root) + data, err := tc.dataFunc(tc.root) require.NoError(t, err) expectedNames := []string{ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/annotation.go new/chezmoi-2.29.3/pkg/cmd/annotation.go --- old/chezmoi-2.29.2/pkg/cmd/annotation.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/annotation.go 2023-01-19 21:40:03.000000000 +0100 @@ -5,7 +5,6 @@ // Annotations. var ( createSourceDirectoryIfNeeded = tagAnnotation("chezmoi_create_source_directory_if_needed") - doesNotRequireValidConfig = tagAnnotation("chezmoi_does_not_require_valid_config") modifiesConfigFile = tagAnnotation("chezmoi_modifies_config_file") modifiesDestinationDirectory = tagAnnotation("chezmoi_modifies_destination_directory") modifiesSourceDirectory = tagAnnotation("chezmoi_modifies_source_directory") @@ -13,6 +12,7 @@ requiresSourceDirectory = tagAnnotation("chezmoi_requires_source_directory") requiresWorkingTree = tagAnnotation("chezmoi_requires_working_tree") runsCommands = tagAnnotation("chezmoi_runs_commands") + runsWithInvalidConfig = tagAnnotation("chezmoi_runs_with_invalid_config") ) // Persistent state modes. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/catconfigcmd.go new/chezmoi-2.29.3/pkg/cmd/catconfigcmd.go --- old/chezmoi-2.29.2/pkg/cmd/catconfigcmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/catconfigcmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -11,8 +11,8 @@ Args: cobra.NoArgs, RunE: c.runCatConfigCmd, Annotations: newAnnotations( - doesNotRequireValidConfig, requiresConfigDirectory, + runsWithInvalidConfig, ), } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/cdcmd.go new/chezmoi-2.29.3/pkg/cmd/cdcmd.go --- old/chezmoi-2.29.2/pkg/cmd/cdcmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/cdcmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -22,9 +22,9 @@ Args: cobra.MaximumNArgs(1), Annotations: newAnnotations( createSourceDirectoryIfNeeded, - doesNotRequireValidConfig, requiresWorkingTree, runsCommands, + runsWithInvalidConfig, ), } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/chattrcmd.go new/chezmoi-2.29.3/pkg/cmd/chattrcmd.go --- old/chezmoi-2.29.2/pkg/cmd/chattrcmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/chattrcmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -10,6 +10,10 @@ "github.com/twpayne/chezmoi/v2/pkg/chezmoi" ) +type chattrCmdConfig struct { + recursive bool +} + type boolModifier int const ( @@ -81,6 +85,9 @@ ), } + flags := chattrCmd.Flags() + flags.BoolVarP(&c.chattr.recursive, "recursive", "r", c.chattr.recursive, "Recurse into subdirectories") + return chattrCmd } @@ -144,6 +151,7 @@ targetRelPaths, err := c.targetRelPaths(sourceState, args[1:], targetRelPathsOptions{ mustBeInSourceState: true, + recursive: c.chattr.recursive, }) if err != nil { return err @@ -151,7 +159,7 @@ // Sort targets in reverse so we update children before their parent // directories. - sort.Sort(targetRelPaths) + sort.Sort(sort.Reverse(targetRelPaths)) encryptedSuffix := sourceState.Encryption().EncryptedSuffix() for _, targetRelPath := range targetRelPaths { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/cmd.go new/chezmoi-2.29.3/pkg/cmd/cmd.go --- old/chezmoi-2.29.2/pkg/cmd/cmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/cmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -29,7 +29,8 @@ var ( noArgs = []string(nil) - trailingSpaceRx = regexp.MustCompile(` +\n`) + deDuplicateErrorRx = regexp.MustCompile(`:\s+`) + trailingSpaceRx = regexp.MustCompile(` +\n`) helps = make(map[string]*help) ) @@ -109,12 +110,28 @@ if errors.As(err, &errExitCode) { return int(errExitCode) } - fmt.Fprintf(os.Stderr, "chezmoi: %v\n", err) + fmt.Fprintf(os.Stderr, "chezmoi: %s\n", deDuplicateError(err)) return 1 } return 0 } +// deDuplicateError returns err's human-readable string with duplicate components +// removed. +func deDuplicateError(err error) string { + components := deDuplicateErrorRx.Split(err.Error(), -1) + seenComponents := make(map[string]struct{}, len(components)) + uniqueComponents := make([]string, 0, len(components)) + for _, component := range components { + if _, ok := seenComponents[component]; ok { + continue + } + uniqueComponents = append(uniqueComponents, component) + seenComponents[component] = struct{}{} + } + return strings.Join(uniqueComponents, ": ") +} + // example returns command's example. func example(command string) string { help, ok := helps[command] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/cmd_test.go new/chezmoi-2.29.3/pkg/cmd/cmd_test.go --- old/chezmoi-2.29.2/pkg/cmd/cmd_test.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/cmd_test.go 2023-01-19 21:40:03.000000000 +0100 @@ -1,6 +1,8 @@ package cmd import ( + "errors" + "strconv" "testing" "github.com/stretchr/testify/assert" @@ -15,6 +17,51 @@ chezmoi.Umask = chezmoitest.Umask } +func TestDeDuplicateError(t *testing.T) { + for i, tc := range []struct { + errStr string + expected string + }{ + { + errStr: "", + expected: "", + }, + { + errStr: "a", + expected: "a", + }, + { + errStr: "a: a", + expected: "a", + }, + { + errStr: "a: b", + expected: "a: b", + }, + { + errStr: "a: a: b", //nolint:dupword + expected: "a: b", + }, + { + errStr: "a: b: b", + expected: "a: b", + }, + { + errStr: "a: b: c: b: a: d", + expected: "a: b: c: d", + }, + { + errStr: "a: b: a: b: c", + expected: "a: b: c", + }, + } { + t.Run(strconv.Itoa(i), func(t *testing.T) { + actual := deDuplicateError(errors.New(tc.errStr)) + assert.Equal(t, tc.expected, actual) + }) + } +} + func TestMustGetLongHelpPanics(t *testing.T) { assert.Panics(t, func() { mustLongHelp("non-existent-command") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/completioncmd.go new/chezmoi-2.29.3/pkg/cmd/completioncmd.go --- old/chezmoi-2.29.2/pkg/cmd/completioncmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/completioncmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -21,7 +21,7 @@ Example: example("completion"), RunE: c.runCompletionCmd, Annotations: newAnnotations( - doesNotRequireValidConfig, + runsWithInvalidConfig, ), } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/config.go new/chezmoi-2.29.3/pkg/cmd/config.go --- old/chezmoi-2.29.2/pkg/cmd/config.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/config.go 2023-01-19 21:40:03.000000000 +0100 @@ -157,6 +157,7 @@ // Command configurations, not settable in the config file. apply applyCmdConfig archive archiveCmdConfig + chattr chattrCmdConfig dump dumpCmdConfig executeTemplate executeTemplateCmdConfig _import importCmdConfig @@ -1658,7 +1659,7 @@ }) // Read the config file. - if annotations.hasTag(doesNotRequireValidConfig) { + if annotations.hasTag(runsWithInvalidConfig) { if c.configFileAbsPathErr == nil { _ = c.readConfig() } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/doctorcmd.go new/chezmoi-2.29.3/pkg/cmd/doctorcmd.go --- old/chezmoi-2.29.2/pkg/cmd/doctorcmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/doctorcmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -152,8 +152,8 @@ Long: mustLongHelp("doctor"), RunE: c.runDoctorCmd, Annotations: newAnnotations( - doesNotRequireValidConfig, runsCommands, + runsWithInvalidConfig, ), } @@ -490,7 +490,11 @@ if filenameAbsPath != c.expected { return checkResultFailed, fmt.Sprintf("found %s, expected %s", filenameAbsPath, c.expected) } - if _, err := system.ReadFile(filenameAbsPath); err != nil { + config, err := newConfig() + if err != nil { + return checkResultError, err.Error() + } + if err := config.decodeConfigFile(filenameAbsPath, &config.ConfigFile); err != nil { return checkResultError, fmt.Sprintf("%s: %v", filenameAbsPath, err) } fileInfo, err := system.Stat(filenameAbsPath) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/dumpconfigcmd.go new/chezmoi-2.29.3/pkg/cmd/dumpconfigcmd.go --- old/chezmoi-2.29.2/pkg/cmd/dumpconfigcmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/dumpconfigcmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -10,9 +10,6 @@ Example: example("dump-config"), Args: cobra.NoArgs, RunE: c.runDumpConfigCmd, - Annotations: newAnnotations( - doesNotRequireValidConfig, - ), } flags := dumpConfigCmd.Flags() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/editconfigcmd.go new/chezmoi-2.29.3/pkg/cmd/editconfigcmd.go --- old/chezmoi-2.29.2/pkg/cmd/editconfigcmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/editconfigcmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -13,10 +13,10 @@ Args: cobra.NoArgs, RunE: c.runEditConfigCmd, Annotations: newAnnotations( - doesNotRequireValidConfig, modifiesConfigFile, requiresConfigDirectory, runsCommands, + runsWithInvalidConfig, ), } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/generatecmd.go new/chezmoi-2.29.3/pkg/cmd/generatecmd.go --- old/chezmoi-2.29.2/pkg/cmd/generatecmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/generatecmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -19,7 +19,7 @@ ValidArgs: []string{"install.sh"}, RunE: c.runGenerateCmd, Annotations: newAnnotations( - doesNotRequireValidConfig, + runsWithInvalidConfig, ), } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/initcmd.go new/chezmoi-2.29.3/pkg/cmd/initcmd.go --- old/chezmoi-2.29.2/pkg/cmd/initcmd.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/initcmd.go 2023-01-19 21:40:03.000000000 +0100 @@ -4,11 +4,9 @@ "errors" "fmt" "io/fs" - "net/url" "regexp" "runtime" "strconv" - "strings" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" @@ -43,55 +41,46 @@ rx *regexp.Regexp httpRepoGuessRepl string sshRepoGuessRepl string - usernameGuessRepl string }{ { rx: regexp.MustCompile(`\A([-0-9A-Za-z]+)\z`), httpRepoGuessRepl: "https://github.com/$1/dotfiles.git", sshRepoGuessRepl: "g...@github.com:$1/dotfiles.git", - usernameGuessRepl: "$1", }, { rx: regexp.MustCompile(`\A([-0-9A-Za-z]+)/([-0-9A-Za-z]+)(\.git)?\z`), httpRepoGuessRepl: "https://github.com/$1/$2.git", sshRepoGuessRepl: "g...@github.com:$1/$2.git", - usernameGuessRepl: "$1", }, { rx: regexp.MustCompile(`\A([-.0-9A-Za-z]+)/([-0-9A-Za-z]+)\z`), httpRepoGuessRepl: "https://$1/$2/dotfiles.git", sshRepoGuessRepl: "git@$1:$2/dotfiles.git", - usernameGuessRepl: "$2", }, { rx: regexp.MustCompile(`\A([-0-9A-Za-z]+)/([-0-9A-Za-z]+)/([-.0-9A-Za-z]+)\z`), httpRepoGuessRepl: "https://$1/$2/$3.git", sshRepoGuessRepl: "git@$1:$2/$3.git", - usernameGuessRepl: "$2", }, { rx: regexp.MustCompile(`\A([-.0-9A-Za-z]+)/([-0-9A-Za-z]+)/([-0-9A-Za-z]+)(\.git)?\z`), httpRepoGuessRepl: "https://$1/$2/$3.git", sshRepoGuessRepl: "git@$1:$2/$3.git", - usernameGuessRepl: "$2", }, { rx: regexp.MustCompile(`\A(https?://)([-.0-9A-Za-z]+)/([-0-9A-Za-z]+)/([-0-9A-Za-z]+)(\.git)?\z`), httpRepoGuessRepl: "$1$2/$3/$4.git", sshRepoGuessRepl: "git@$2:$3/$4.git", - usernameGuessRepl: "$3", }, { rx: regexp.MustCompile(`\Asr\.ht/~([a-z_][a-z0-9_-]+)\z`), httpRepoGuessRepl: "https://git.sr.ht/~$1/dotfiles", sshRepoGuessRepl: "g...@git.sr.ht:~$1/dotfiles", - usernameGuessRepl: "$1", }, { rx: regexp.MustCompile(`\Asr\.ht/~([a-z_][a-z0-9_-]+)/([-0-9A-Za-z]+)\z`), httpRepoGuessRepl: "https://git.sr.ht/~$1/$2", sshRepoGuessRepl: "g...@git.sr.ht:~$1/$2", - usernameGuessRepl: "$1", }, } @@ -170,14 +159,14 @@ return err } } else { - var username, repoURLStr string + var repoURLStr string if c.init.guessRepoURL { - username, repoURLStr = guessRepoURL(args[0], c.init.ssh) + repoURLStr = guessRepoURL(args[0], c.init.ssh) } else { repoURLStr = args[0] } if useBuiltinGit { - if err := c.builtinGitClone(username, repoURLStr, workingTreeRawPath); err != nil { + if err := c.builtinGitClone(repoURLStr, workingTreeRawPath); err != nil { return err } } else { @@ -199,16 +188,6 @@ "--depth", strconv.Itoa(c.init.depth), ) } - if c.init.guessRepoURL && (strings.HasPrefix(repoURLStr, "http://") || strings.HasPrefix(repoURLStr, "https://")) { - repoURL, err := url.Parse(repoURLStr) - if err != nil { - return err - } - if repoURL.User == nil { - repoURL.User = url.User(username) - repoURLStr = repoURL.String() - } - } args = append(args, repoURLStr, workingTreeRawPath.String(), @@ -263,7 +242,7 @@ } // builtinGitClone clones a repo using the builtin git command. -func (c *Config) builtinGitClone(username, repoURLStr string, workingTreeRawPath chezmoi.AbsPath) error { +func (c *Config) builtinGitClone(repoURLStr string, workingTreeRawPath chezmoi.AbsPath) error { endpoint, err := transport.NewEndpoint(repoURLStr) if err != nil { return err @@ -299,12 +278,9 @@ return err } var basicAuth http.BasicAuth - if basicAuth.Username, err = c.readString("Username? ", &username); err != nil { + if basicAuth.Username, err = c.readString("Username? ", nil); err != nil { return err } - if basicAuth.Username == "" { - basicAuth.Username = username - } if basicAuth.Password, err = c.readPassword("Password? "); err != nil { return err } @@ -365,21 +341,16 @@ } // guessRepoURL guesses the user's username and repo from arg. -func guessRepoURL(arg string, ssh bool) (username, repo string) { +func guessRepoURL(arg string, ssh bool) string { for _, repoGuess := range repoGuesses { - if !repoGuess.rx.MatchString(arg) { - continue - } switch { + case !repoGuess.rx.MatchString(arg): + continue case ssh && repoGuess.sshRepoGuessRepl != "": - repo = repoGuess.rx.ReplaceAllString(arg, repoGuess.sshRepoGuessRepl) - return + return repoGuess.rx.ReplaceAllString(arg, repoGuess.sshRepoGuessRepl) case !ssh && repoGuess.httpRepoGuessRepl != "": - username = repoGuess.rx.ReplaceAllString(arg, repoGuess.usernameGuessRepl) - repo = repoGuess.rx.ReplaceAllString(arg, repoGuess.httpRepoGuessRepl) - return + return repoGuess.rx.ReplaceAllString(arg, repoGuess.httpRepoGuessRepl) } } - repo = arg - return + return arg } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/initcmd_test.go new/chezmoi-2.29.3/pkg/cmd/initcmd_test.go --- old/chezmoi-2.29.2/pkg/cmd/initcmd_test.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/initcmd_test.go 2023-01-19 21:40:03.000000000 +0100 @@ -17,7 +17,6 @@ arg string expectedHTTPRepoURL string expectedSSHRepoURL string - expectedUsername string }{ { arg: "g...@github.com:user/dotfiles.git", @@ -28,84 +27,70 @@ arg: "codeberg.org/user", expectedHTTPRepoURL: "https://codeberg.org/user/dotfiles.git", expectedSSHRepoURL: "g...@codeberg.org:user/dotfiles.git", - expectedUsername: "user", }, { arg: "codeberg.org/user/dots", expectedHTTPRepoURL: "https://codeberg.org/user/dots.git", expectedSSHRepoURL: "g...@codeberg.org:user/dots.git", - expectedUsername: "user", }, { arg: "gitlab.com/user", expectedHTTPRepoURL: "https://gitlab.com/user/dotfiles.git", expectedSSHRepoURL: "g...@gitlab.com:user/dotfiles.git", - expectedUsername: "user", }, { arg: "gitlab.com/user/dots", expectedHTTPRepoURL: "https://gitlab.com/user/dots.git", expectedSSHRepoURL: "g...@gitlab.com:user/dots.git", - expectedUsername: "user", }, { arg: "gitlab.com/user/dots.git", expectedHTTPRepoURL: "https://gitlab.com/user/dots.git", expectedSSHRepoURL: "g...@gitlab.com:user/dots.git", - expectedUsername: "user", }, { arg: "http://gitlab.com/user/dots.git", expectedHTTPRepoURL: "http://gitlab.com/user/dots.git", expectedSSHRepoURL: "g...@gitlab.com:user/dots.git", - expectedUsername: "user", }, { arg: "https://gitlab.com/user/dots.git", expectedHTTPRepoURL: "https://gitlab.com/user/dots.git", expectedSSHRepoURL: "g...@gitlab.com:user/dots.git", - expectedUsername: "user", }, { arg: "sr.ht/~user_name", expectedHTTPRepoURL: "https://git.sr.ht/~user_name/dotfiles", expectedSSHRepoURL: "g...@git.sr.ht:~user_name/dotfiles", - expectedUsername: "user_name", }, { arg: "sr.ht/~user_name/dots", expectedHTTPRepoURL: "https://git.sr.ht/~user_name/dots", expectedSSHRepoURL: "g...@git.sr.ht:~user_name/dots", - expectedUsername: "user_name", }, { arg: "user", expectedHTTPRepoURL: "https://github.com/user/dotfiles.git", expectedSSHRepoURL: "g...@github.com:user/dotfiles.git", - expectedUsername: "user", }, { arg: "user/dots", expectedHTTPRepoURL: "https://github.com/user/dots.git", expectedSSHRepoURL: "g...@github.com:user/dots.git", - expectedUsername: "user", }, { arg: "user/dots.git", expectedHTTPRepoURL: "https://github.com/user/dots.git", expectedSSHRepoURL: "g...@github.com:user/dots.git", - expectedUsername: "user", }, } { t.Run(tc.arg, func(t *testing.T) { ssh := false - actualHTTPUsername, actualHTTPRepoURL := guessRepoURL(tc.arg, ssh) - assert.Equal(t, tc.expectedUsername, actualHTTPUsername, "HTTPUsername") + actualHTTPRepoURL := guessRepoURL(tc.arg, ssh) assert.Equal(t, tc.expectedHTTPRepoURL, actualHTTPRepoURL, "HTTPRepoURL") ssh = true - actualSSHUsername, actualSSHRepoURL := guessRepoURL(tc.arg, ssh) - assert.Equal(t, "", actualSSHUsername, "SSHUsername") + actualSSHRepoURL := guessRepoURL(tc.arg, ssh) assert.Equal(t, tc.expectedSSHRepoURL, actualSSHRepoURL, "SSHRepoURL") }) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/keepassxctemplatefuncs.go new/chezmoi-2.29.3/pkg/cmd/keepassxctemplatefuncs.go --- old/chezmoi-2.29.2/pkg/cmd/keepassxctemplatefuncs.go 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/keepassxctemplatefuncs.go 2023-01-19 21:40:03.000000000 +0100 @@ -141,6 +141,8 @@ return nil, err } c.Keepassxc.password = password + } + if c.Keepassxc.password != "" { cmd.Stdin = bytes.NewBufferString(c.Keepassxc.password + "\n") } else { cmd.Stdin = os.Stdin diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/testdata/scripts/chattr.txtar new/chezmoi-2.29.3/pkg/cmd/testdata/scripts/chattr.txtar --- old/chezmoi-2.29.2/pkg/cmd/testdata/scripts/chattr.txtar 2023-01-15 15:35:48.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/testdata/scripts/chattr.txtar 2023-01-19 21:40:03.000000000 +0100 @@ -128,6 +128,13 @@ exec chezmoi chattr --dry-run --verbose +executable $HOME${/}.file cmp stdout golden/chattr-diff +# test that chezmoi chattr --recursive noexact recurses into subdirectories +exists $CHEZMOISOURCEDIR/exact_readonly_dot_dir +exists $CHEZMOISOURCEDIR/exact_readonly_dot_dir/exact_subdir +exec chezmoi chattr --recursive noexact $HOME${/}.dir +exists $CHEZMOISOURCEDIR/readonly_dot_dir +exists $CHEZMOISOURCEDIR/readonly_dot_dir/subdir + -- golden/chattr-diff -- diff --git a/dot_file b/executable_dot_file rename from dot_file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.29.2/pkg/cmd/testdata/scripts/issue2695.txtar new/chezmoi-2.29.3/pkg/cmd/testdata/scripts/issue2695.txtar --- old/chezmoi-2.29.2/pkg/cmd/testdata/scripts/issue2695.txtar 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.29.3/pkg/cmd/testdata/scripts/issue2695.txtar 2023-01-19 21:40:03.000000000 +0100 @@ -0,0 +1,40 @@ +# test that chezmoi status returns an error when the JSON config file is invalid +! exec chezmoi status +stderr 'invalid config' +! stderr 'json.*json' + +# check that chezmoi doctor warns about invalid JSON config files +! exec chezmoi doctor +stdout 'error\s+config-file\s+.*invalid character' + +chhome home2/user + +# test that chezmoi status returns an error when the TOML config file is invalid +! exec chezmoi status +stderr 'invalid config' +! stderr 'chezmoi\.toml.*chezmoi\.toml' + +# check that chezmoi doctor warns about invalid TOML config files +! exec chezmoi doctor +stdout 'error\s+config-file\s+.*incomplete number' + +chhome home3/user + +# test that chezmoi status returns an error when the YAML config file is invalid +! exec chezmoi status +stderr 'invalid config' +! stderr 'chezmoi\.yaml.*chezmoi\.yaml' + +# check that chezmoi doctor warns about invalid YAML config files +! exec chezmoi doctor +stdout 'error\s+config-file\s+.*unmarshal errors' + +-- home/user/.config/chezmoi/chezmoi.json -- +{ + "string": unquoted +} +-- home2/user/.config/chezmoi/chezmoi.toml -- +[example] + string = unquoted +-- home3/user/.config/chezmoi/chezmoi.yaml -- +string ++++++ chezmoi.obsinfo ++++++ --- /var/tmp/diff_new_pack.hM5tAD/_old 2023-01-24 20:59:43.745534643 +0100 +++ /var/tmp/diff_new_pack.hM5tAD/_new 2023-01-24 20:59:43.745534643 +0100 @@ -1,5 +1,5 @@ name: chezmoi -version: 2.29.2 -mtime: 1673793348 -commit: b9536aae9100a2367e7b5baad8a7e251542c45bd +version: 2.29.3 +mtime: 1674160803 +commit: fec55002b83b3688d13988055226aa716b0c7c14 ++++++ vendor.tar.gz ++++++