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-02-13 16:41:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/chezmoi (Old) and /work/SRC/openSUSE:Factory/.chezmoi.new.1848 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "chezmoi" Mon Feb 13 16:41:30 2023 rev:14 rq:1065522 version:2.30.1 Changes: -------- --- /work/SRC/openSUSE:Factory/chezmoi/chezmoi.changes 2023-02-07 18:51:01.883759317 +0100 +++ /work/SRC/openSUSE:Factory/.chezmoi.new.1848/chezmoi.changes 2023-02-13 16:43:24.780256882 +0100 @@ -1,0 +2,9 @@ +Mon Feb 13 14:18:00 UTC 2023 - Filippo Bonazzi <filippo.bona...@suse.com> + +- Update to version 2.30.1: + * Add deleteValueAtPath and pruneEmptyDicts template functions + * feat: Extend toPrettyJson template function to take indent + * fix: Fix chezmoi target-path when using .chezmoiroot + * chore: Use strings.Cut{Prefix,Suffix} + +------------------------------------------------------------------- Old: ---- chezmoi-2.30.0.obscpio New: ---- chezmoi-2.30.1.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ chezmoi.spec ++++++ --- /var/tmp/diff_new_pack.HfxlPn/_old 2023-02-13 16:43:25.408260582 +0100 +++ /var/tmp/diff_new_pack.HfxlPn/_new 2023-02-13 16:43:25.412260605 +0100 @@ -17,7 +17,7 @@ Name: chezmoi -Version: 2.30.0 +Version: 2.30.1 Release: 0 Summary: A multi-host manager for dotfiles License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.HfxlPn/_old 2023-02-13 16:43:25.448260817 +0100 +++ /var/tmp/diff_new_pack.HfxlPn/_new 2023-02-13 16:43:25.452260842 +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.30.0</param> + <param name="revision">v2.30.1</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> </service> ++++++ chezmoi-2.30.0.obscpio -> chezmoi-2.30.1.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/chezmoi.io/docs/reference/templates/functions/deleteValueAtPath.md new/chezmoi-2.30.1/assets/chezmoi.io/docs/reference/templates/functions/deleteValueAtPath.md --- old/chezmoi-2.30.0/assets/chezmoi.io/docs/reference/templates/functions/deleteValueAtPath.md 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.30.1/assets/chezmoi.io/docs/reference/templates/functions/deleteValueAtPath.md 2023-02-11 19:06:40.000000000 +0100 @@ -0,0 +1,16 @@ +# `deleteValueAtPath` *path* *dict* + +`deleteValueAtPath` modifies *dict* to delete the value at *path* and returns +*dict*. *path* can be either a string containing a `.`-separated list of keys or +a list of keys. + +If *path* does not exist in *dict* then `deleteValueAtPath` returns *dict* +unchanged. + +!!! example + + ``` + {{ dict "outer" (dict "inner" "value") | deleteValueAtPath "outer.inner" | toJson }} + {{ dict | setValueAtPath "key1" "value1" | setValueAtPath "key2.nestedKey" "value2" | toJson }} + {{ dict | setValueAtPath (list "key2" "nestedKey") "value2" | toJson }} + ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/chezmoi.io/docs/reference/templates/functions/pruneEmptyDicts.md new/chezmoi-2.30.1/assets/chezmoi.io/docs/reference/templates/functions/pruneEmptyDicts.md --- old/chezmoi-2.30.0/assets/chezmoi.io/docs/reference/templates/functions/pruneEmptyDicts.md 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.30.1/assets/chezmoi.io/docs/reference/templates/functions/pruneEmptyDicts.md 2023-02-11 19:06:40.000000000 +0100 @@ -0,0 +1,11 @@ +# `pruneEmptyDicts` *dict* + +`pruneEmptyDicts` modifies *dict* to remove nested empty dicts. Properties are +pruned from the bottom up, so any nested dicts that themselves only contain +empty dicts are pruned. + +!!! example + + ``` + {{ dict "key" "value" inner (dict) | pruneEmptyDicts | toJson }} + ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/chezmoi.io/docs/reference/templates/functions/toPrettyJson.md new/chezmoi-2.30.1/assets/chezmoi.io/docs/reference/templates/functions/toPrettyJson.md --- old/chezmoi-2.30.0/assets/chezmoi.io/docs/reference/templates/functions/toPrettyJson.md 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.30.1/assets/chezmoi.io/docs/reference/templates/functions/toPrettyJson.md 2023-02-11 19:06:40.000000000 +0100 @@ -0,0 +1,11 @@ +# `toPrettyJson` [*indent*] *value* + +`toPrettyJson` returns the JSON representation of *value*. The optional *indent* +specifies how much nested elements are indented relative to their parent. +*indent* defaults to two spaces. + +!!! examples + + ``` + {{ dict "a" (dict "b" "c") | toPrettyJson "\t" }} + ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/chezmoi.io/mkdocs.yml new/chezmoi-2.30.1/assets/chezmoi.io/mkdocs.yml --- old/chezmoi-2.30.0/assets/chezmoi.io/mkdocs.yml 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/assets/chezmoi.io/mkdocs.yml 2023-02-11 19:06:40.000000000 +0100 @@ -176,6 +176,7 @@ - comment: reference/templates/functions/comment.md - completion: reference/templates/functions/completion.md - decrypt: reference/templates/functions/decrypt.md + - deleteValueAtPath: reference/templates/functions/deleteValueAtPath.md - encrypt: reference/templates/functions/encrypt.md - eqFold: reference/templates/functions/eqFold.md - fromIni: reference/templates/functions/fromIni.md @@ -192,11 +193,13 @@ - lstat: reference/templates/functions/lstat.md - mozillaInstallHash: reference/templates/functions/mozillaInstallHash.md - output: reference/templates/functions/output.md + - pruneEmptyDicts: reference/templates/functions/pruneEmptyDicts.md - quoteList: reference/templates/functions/quoteList.md - replaceAllRegex: reference/templates/functions/replaceAllRegex.md - setValueAtPath: reference/templates/functions/setValueAtPath.md - stat: reference/templates/functions/stat.md - toIni: reference/templates/functions/toIni.md + - toPrettyJson: reference/templates/functions/toPrettyJson.md - toToml: reference/templates/functions/toToml.md - toYaml: reference/templates/functions/toYaml.md - GitHub functions: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/docker/test.sh new/chezmoi-2.30.1/assets/docker/test.sh --- old/chezmoi-2.30.0/assets/docker/test.sh 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/assets/docker/test.sh 2023-02-11 19:06:40.000000000 +0100 @@ -4,19 +4,19 @@ cd ../.. for distribution in "$@"; do - echo "${distribution}" - dockerfile="assets/docker/${distribution}.Dockerfile" - if [ ! -f "${dockerfile}" ]; then - echo "${dockerfile} not found" - exit 1 - fi - image="$(docker build . -f "assets/docker/${distribution}.Dockerfile" -q)" - docker run \ - --env "CHEZMOI_GITHUB_ACCESS_TOKEN=${CHEZMOI_GITHUB_ACCESS_TOKEN-}" \ - --env "CHEZMOI_GITHUB_TOKEN=${CHEZMOI_GITHUB_TOKEN-}" \ - --env "GITHUB_ACCESS_TOKEN=${GITHUB_ACCESS_TOKEN-}" \ - --env "GITHUB_TOKEN=${GITHUB_TOKEN-}" \ - --rm \ - --volume "${PWD}:/chezmoi" \ - "${image}" + echo "${distribution}" + dockerfile="assets/docker/${distribution}.Dockerfile" + if [ ! -f "${dockerfile}" ]; then + echo "${dockerfile} not found" + exit 1 + fi + image="$(docker build . -f "assets/docker/${distribution}.Dockerfile" -q)" + docker run \ + --env "CHEZMOI_GITHUB_ACCESS_TOKEN=${CHEZMOI_GITHUB_ACCESS_TOKEN-}" \ + --env "CHEZMOI_GITHUB_TOKEN=${CHEZMOI_GITHUB_TOKEN-}" \ + --env "GITHUB_ACCESS_TOKEN=${GITHUB_ACCESS_TOKEN-}" \ + --env "GITHUB_TOKEN=${GITHUB_TOKEN-}" \ + --rm \ + --volume "${PWD}:/chezmoi" \ + "${image}" done diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/scripts/generate-commit.sh new/chezmoi-2.30.1/assets/scripts/generate-commit.sh --- old/chezmoi-2.30.0/assets/scripts/generate-commit.sh 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/assets/scripts/generate-commit.sh 2023-02-11 19:06:40.000000000 +0100 @@ -16,5 +16,5 @@ if [ -z "${output}" ]; then echo "${commit}" else - echo "${commit}" > "${output}" + echo "${commit}" >"${output}" fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/scripts/install.sh new/chezmoi-2.30.1/assets/scripts/install.sh --- old/chezmoi-2.30.0/assets/scripts/install.sh 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/assets/scripts/install.sh 2023-02-11 19:06:40.000000000 +0100 @@ -60,6 +60,7 @@ GOOS_EXTRA="-musl" ;; esac + ;; esac ;; windows) @@ -187,7 +188,7 @@ get_libc() { if is_command ldd; then case "$(ldd --version 2>&1 | tr '[:upper:]' '[:lower:]')" in - *glibc*|*"gnu libc"*) + *glibc* | *"gnu libc"*) printf glibc return ;; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/scripts/stow-to-chezmoi.sh new/chezmoi-2.30.1/assets/scripts/stow-to-chezmoi.sh --- old/chezmoi-2.30.0/assets/scripts/stow-to-chezmoi.sh 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/assets/scripts/stow-to-chezmoi.sh 2023-02-11 19:06:40.000000000 +0100 @@ -38,24 +38,24 @@ trap 'exit' INT TERM find "${BASEDIR}" \! -path '* -*' \! -path "${BASEDIR}/${STOWDIR}*" -type l >"${work_file}" || \ +*' \! -path "${BASEDIR}/${STOWDIR}*" -type l >"${work_file}" || printf "Find skipped some files\n" >&2 while read -r f; do target="$("${READLINK}" -f -- "${f}" || :)" case "${target}" in - "${BASEDIR}/${STOWDIR}/"*) - printf 'Add %s\n' "${f}" >&2 - printf '%s\n' "${f}" >>"${act_file}" - ;; + "${BASEDIR}/${STOWDIR}/"*) + printf 'Add %s\n' "${f}" >&2 + printf '%s\n' "${f}" >>"${act_file}" + ;; esac done <"${work_file}" printf 'Migrate the above to chezmoi? y/N ' >&2 read -r migrate case "${migrate}" in - [Yy]*) printf 'Migrating...\n' >&2 ;; - *) exit 1 ;; +[Yy]*) printf 'Migrating...\n' >&2 ;; +*) exit 1 ;; esac mkdir -p -- "${BASEDIR}/.local/share" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/templates/install.sh new/chezmoi-2.30.1/assets/templates/install.sh --- old/chezmoi-2.30.0/assets/templates/install.sh 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/assets/templates/install.sh 2023-02-11 19:06:40.000000000 +0100 @@ -5,19 +5,19 @@ set -eu if ! chezmoi="$(command -v chezmoi)"; then - bin_dir="${HOME}/.local/bin" - chezmoi="${bin_dir}/chezmoi" - echo "Installing chezmoi to '${chezmoi}'" >&2 - if command -v curl >/dev/null; then - chezmoi_install_script="$(curl -fsSL get.chezmoi.io)" - elif command -v wget >/dev/null; then - chezmoi_install_script="$(wget -qO- get.chezmoi.io)" - else - echo "To install chezmoi, you must have curl or wget installed." >&2 - exit 1 - fi - sh -c "${chezmoi_install_script}" -- -b "${bin_dir}" - unset chezmoi_install_script bin_dir + bin_dir="${HOME}/.local/bin" + chezmoi="${bin_dir}/chezmoi" + echo "Installing chezmoi to '${chezmoi}'" >&2 + if command -v curl >/dev/null; then + chezmoi_install_script="$(curl -fsSL get.chezmoi.io)" + elif command -v wget >/dev/null; then + chezmoi_install_script="$(wget -qO- get.chezmoi.io)" + else + echo "To install chezmoi, you must have curl or wget installed." >&2 + exit 1 + fi + sh -c "${chezmoi_install_script}" -- -b "${bin_dir}" + unset chezmoi_install_script bin_dir fi # POSIX way to get script's dir: https://stackoverflow.com/a/29834779/12156188 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/assets/vagrant/test.sh new/chezmoi-2.30.1/assets/vagrant/test.sh --- old/chezmoi-2.30.0/assets/vagrant/test.sh 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/assets/vagrant/test.sh 2023-02-11 19:06:40.000000000 +0100 @@ -3,19 +3,19 @@ set -eufo pipefail for os in "$@"; do - echo "${os}" - if [ ! -f "${os}.Vagrantfile" ]; then - echo "${os}.Vagrantfile not found" - exit 1 - fi - export VAGRANT_VAGRANTFILE=assets/vagrant/${os}.Vagrantfile - if ! ( cd ../.. && vagrant up ); then - exit 1 - fi - vagrant ssh -c "./test-chezmoi.sh" - vagrant_ssh_exit_code=$? - vagrant destroy -f || exit 1 - if [ $vagrant_ssh_exit_code -ne 0 ]; then - exit $vagrant_ssh_exit_code - fi + echo "${os}" + if [ ! -f "${os}.Vagrantfile" ]; then + echo "${os}.Vagrantfile not found" + exit 1 + fi + export VAGRANT_VAGRANTFILE=assets/vagrant/${os}.Vagrantfile + if ! (cd ../.. && vagrant up); then + exit 1 + fi + vagrant ssh -c "./test-chezmoi.sh" + vagrant_ssh_exit_code=$? + vagrant destroy -f || exit 1 + if [ $vagrant_ssh_exit_code -ne 0 ]; then + exit $vagrant_ssh_exit_code + fi done diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/internal/cmds/generate-install.sh/install.sh.tmpl new/chezmoi-2.30.1/internal/cmds/generate-install.sh/install.sh.tmpl --- old/chezmoi-2.30.0/internal/cmds/generate-install.sh/install.sh.tmpl 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/internal/cmds/generate-install.sh/install.sh.tmpl 2023-02-11 19:06:40.000000000 +0100 @@ -60,6 +60,7 @@ GOOS_EXTRA="-musl" ;; esac + ;; esac ;; windows) @@ -162,7 +163,7 @@ get_libc() { if is_command ldd; then case "$(ldd --version 2>&1 | tr '[:upper:]' '[:lower:]')" in - *glibc*|*"gnu libc"*) + *glibc* | *"gnu libc"*) printf glibc return ;; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/chezmoi/attr.go new/chezmoi-2.30.1/pkg/chezmoi/attr.go --- old/chezmoi-2.30.0/pkg/chezmoi/attr.go 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/chezmoi/attr.go 2023-02-11 19:06:40.000000000 +0100 @@ -78,37 +78,15 @@ // parseDirAttr parses a single directory name in the source state. func parseDirAttr(sourceName string) DirAttr { - var ( - name = sourceName - exact = false - external = false - private = false - readOnly = false - remove = false - ) - if strings.HasPrefix(name, externalPrefix) { - name = mustTrimPrefix(name, externalPrefix) - external = true - } - if strings.HasPrefix(name, removePrefix) { - name = mustTrimPrefix(name, removePrefix) - remove = true - } - if strings.HasPrefix(name, exactPrefix) { - name = mustTrimPrefix(name, exactPrefix) - exact = true - } - if strings.HasPrefix(name, privatePrefix) { - name = mustTrimPrefix(name, privatePrefix) - private = true - } - if strings.HasPrefix(name, readOnlyPrefix) { - name = mustTrimPrefix(name, readOnlyPrefix) - readOnly = true - } + name := sourceName + name, external := CutPrefix(name, externalPrefix) + name, remove := CutPrefix(name, removePrefix) + name, exact := CutPrefix(name, exactPrefix) + name, private := CutPrefix(name, privatePrefix) + name, readOnly := CutPrefix(name, readOnlyPrefix) switch { case strings.HasPrefix(name, dotPrefix): - name = "." + mustTrimPrefix(name, dotPrefix) + name = "." + name[len(dotPrefix):] case strings.HasPrefix(name, literalPrefix): name = name[len(literalPrefix):] } @@ -153,7 +131,7 @@ } switch { case strings.HasPrefix(da.TargetName, "."): - sourceName += dotPrefix + mustTrimPrefix(da.TargetName, ".") + sourceName += dotPrefix + da.TargetName[len("."):] case dirPrefixRx.MatchString(da.TargetName): sourceName += literalPrefix + da.TargetName default: @@ -191,109 +169,68 @@ switch { case strings.HasPrefix(name, createPrefix): sourceFileType = SourceFileTypeCreate - name = mustTrimPrefix(name, createPrefix) - if strings.HasPrefix(name, encryptedPrefix) { - name = mustTrimPrefix(name, encryptedPrefix) - encrypted = true - } - if strings.HasPrefix(name, privatePrefix) { - name = mustTrimPrefix(name, privatePrefix) - private = true - } - if strings.HasPrefix(name, readOnlyPrefix) { - name = mustTrimPrefix(name, readOnlyPrefix) - readOnly = true - } - if strings.HasPrefix(name, executablePrefix) { - name = mustTrimPrefix(name, executablePrefix) - executable = true - } + name = name[len(createPrefix):] + name, encrypted = CutPrefix(name, encryptedPrefix) + name, private = CutPrefix(name, privatePrefix) + name, readOnly = CutPrefix(name, readOnlyPrefix) + name, executable = CutPrefix(name, executablePrefix) case strings.HasPrefix(name, removePrefix): sourceFileType = SourceFileTypeRemove - name = mustTrimPrefix(name, removePrefix) + name = name[len(removePrefix):] case strings.HasPrefix(name, runPrefix): sourceFileType = SourceFileTypeScript - name = mustTrimPrefix(name, runPrefix) + name = name[len(runPrefix):] switch { case strings.HasPrefix(name, oncePrefix): - name = mustTrimPrefix(name, oncePrefix) + name = name[len(oncePrefix):] condition = ScriptConditionOnce case strings.HasPrefix(name, onChangePrefix): - name = mustTrimPrefix(name, onChangePrefix) + name = name[len(onChangePrefix):] condition = ScriptConditionOnChange default: condition = ScriptConditionAlways } switch { case strings.HasPrefix(name, beforePrefix): - name = mustTrimPrefix(name, beforePrefix) + name = name[len(beforePrefix):] order = ScriptOrderBefore case strings.HasPrefix(name, afterPrefix): - name = mustTrimPrefix(name, afterPrefix) + name = name[len(afterPrefix):] order = ScriptOrderAfter } case strings.HasPrefix(name, symlinkPrefix): sourceFileType = SourceFileTypeSymlink - name = mustTrimPrefix(name, symlinkPrefix) + name = name[len(symlinkPrefix):] case strings.HasPrefix(name, modifyPrefix): sourceFileType = SourceFileTypeModify - name = mustTrimPrefix(name, modifyPrefix) - if strings.HasPrefix(name, encryptedPrefix) { - name = mustTrimPrefix(name, encryptedPrefix) - encrypted = true - } - if strings.HasPrefix(name, privatePrefix) { - name = mustTrimPrefix(name, privatePrefix) - private = true - } - if strings.HasPrefix(name, readOnlyPrefix) { - name = mustTrimPrefix(name, readOnlyPrefix) - readOnly = true - } - if strings.HasPrefix(name, executablePrefix) { - name = mustTrimPrefix(name, executablePrefix) - executable = true - } + name = name[len(modifyPrefix):] + name, encrypted = CutPrefix(name, encryptedPrefix) + name, private = CutPrefix(name, privatePrefix) + name, readOnly = CutPrefix(name, readOnlyPrefix) + name, executable = CutPrefix(name, executablePrefix) default: - if strings.HasPrefix(name, encryptedPrefix) { - name = mustTrimPrefix(name, encryptedPrefix) - encrypted = true - } - if strings.HasPrefix(name, privatePrefix) { - name = mustTrimPrefix(name, privatePrefix) - private = true - } - if strings.HasPrefix(name, readOnlyPrefix) { - name = mustTrimPrefix(name, readOnlyPrefix) - readOnly = true - } - if strings.HasPrefix(name, emptyPrefix) { - name = mustTrimPrefix(name, emptyPrefix) - empty = true - } - if strings.HasPrefix(name, executablePrefix) { - name = mustTrimPrefix(name, executablePrefix) - executable = true - } + name, encrypted = CutPrefix(name, encryptedPrefix) + name, private = CutPrefix(name, privatePrefix) + name, readOnly = CutPrefix(name, readOnlyPrefix) + name, empty = CutPrefix(name, emptyPrefix) + name, executable = CutPrefix(name, executablePrefix) } switch { case strings.HasPrefix(name, dotPrefix): - name = "." + mustTrimPrefix(name, dotPrefix) + name = "." + name[len(dotPrefix):] case strings.HasPrefix(name, literalPrefix): name = name[len(literalPrefix):] } if encrypted { - name = strings.TrimSuffix(name, encryptedSuffix) + name, _ = CutSuffix(name, encryptedSuffix) } switch { case strings.HasSuffix(name, literalSuffix): - name = mustTrimSuffix(name, literalSuffix) + name = name[:len(name)-len(literalSuffix)] case strings.HasSuffix(name, TemplateSuffix): - name = mustTrimSuffix(name, TemplateSuffix) + name = name[:len(name)-len(TemplateSuffix)] template = true - if strings.HasSuffix(name, literalSuffix) { - name = mustTrimSuffix(name, literalSuffix) - } + name, _ = CutSuffix(name, literalSuffix) } return FileAttr{ TargetName: name, @@ -393,7 +330,7 @@ } switch { case strings.HasPrefix(fa.TargetName, "."): - sourceName += dotPrefix + mustTrimPrefix(fa.TargetName, ".") + sourceName += dotPrefix + fa.TargetName[len("."):] case filePrefixRx.MatchString(fa.TargetName): sourceName += literalPrefix + fa.TargetName default: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/chezmoi/chezmoi.go new/chezmoi-2.30.1/pkg/chezmoi/chezmoi.go --- old/chezmoi-2.30.0/pkg/chezmoi/chezmoi.go 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/chezmoi/chezmoi.go 2023-02-11 19:06:40.000000000 +0100 @@ -319,24 +319,6 @@ return fmt.Sprintf("0o%o: unknown type", mode.Type()) } -// mustTrimPrefix is like strings.TrimPrefix but panics if s is not prefixed by -// prefix. -func mustTrimPrefix(s, prefix string) string { - if !strings.HasPrefix(s, prefix) { - panic(fmt.Sprintf("%s: not prefixed by %s", s, prefix)) - } - return s[len(prefix):] -} - -// mustTrimSuffix is like strings.TrimSuffix but panics if s is not suffixed by -// suffix. -func mustTrimSuffix(s, suffix string) string { - if !strings.HasSuffix(s, suffix) { - panic(fmt.Sprintf("%s: not suffixed by %s", s, suffix)) - } - return s[:len(s)-len(suffix)] -} - // ripemd160Sum returns the RIPEMD-160 sum of data. func ripemd160Sum(data []byte) []byte { return ripemd160.New().Sum(data) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/chezmoi/chezmoi_go1.19.go new/chezmoi-2.30.1/pkg/chezmoi/chezmoi_go1.19.go --- old/chezmoi-2.30.0/pkg/chezmoi/chezmoi_go1.19.go 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/chezmoi/chezmoi_go1.19.go 2023-02-11 19:06:40.000000000 +0100 @@ -0,0 +1,19 @@ +//go:build !go1.20 + +package chezmoi + +import "strings" + +func CutPrefix(s, prefix string) (string, bool) { + if strings.HasPrefix(s, prefix) { + return s[len(prefix):], true + } + return s, false +} + +func CutSuffix(s, suffix string) (string, bool) { + if strings.HasSuffix(s, suffix) { + return s[:len(s)-len(suffix)], true + } + return s, false +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/chezmoi/chezmoi_go1.20.go new/chezmoi-2.30.1/pkg/chezmoi/chezmoi_go1.20.go --- old/chezmoi-2.30.0/pkg/chezmoi/chezmoi_go1.20.go 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/chezmoi/chezmoi_go1.20.go 2023-02-11 19:06:40.000000000 +0100 @@ -0,0 +1,10 @@ +//go:build go1.20 + +package chezmoi + +import "strings" + +var ( + CutPrefix = strings.CutPrefix + CutSuffix = strings.CutSuffix +) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/chezmoi/entrytypeset.go new/chezmoi-2.30.1/pkg/chezmoi/entrytypeset.go --- old/chezmoi-2.30.0/pkg/chezmoi/entrytypeset.go 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/chezmoi/entrytypeset.go 2023-02-11 19:06:40.000000000 +0100 @@ -296,11 +296,7 @@ if element == "" { continue } - exclude := false - if strings.HasPrefix(element, "no") { - exclude = true - element = element[2:] - } + element, exclude := CutPrefix(element, "no") bit, ok := entryTypeBits[element] if !ok { return fmt.Errorf("%s: unknown entry type", element) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/chezmoi/patternset.go new/chezmoi-2.30.1/pkg/chezmoi/patternset.go --- old/chezmoi-2.30.0/pkg/chezmoi/patternset.go 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/chezmoi/patternset.go 2023-02-11 19:06:40.000000000 +0100 @@ -87,7 +87,7 @@ } matchesSlice := allMatches.elements() for i, match := range matchesSlice { - matchesSlice[i] = mustTrimPrefix(filepath.ToSlash(match), prefix) + matchesSlice[i] = filepath.ToSlash(match)[len(prefix):] } sort.Strings(matchesSlice) return matchesSlice, nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/chezmoi/sourcestate.go new/chezmoi-2.30.1/pkg/chezmoi/sourcestate.go --- old/chezmoi-2.30.0/pkg/chezmoi/sourcestate.go 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/chezmoi/sourcestate.go 2023-02-11 19:06:40.000000000 +0100 @@ -1212,9 +1212,9 @@ continue } include := patternSetInclude - if strings.HasPrefix(text, "!") { + text, ok := CutPrefix(text, "!") + if ok { include = patternSetExclude - text = mustTrimPrefix(text, "!") } pattern := dir.JoinString(text).String() if err := patternSet.add(pattern, include); err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/cmd/config.go new/chezmoi-2.30.1/pkg/cmd/config.go --- old/chezmoi-2.30.0/pkg/cmd/config.go 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/cmd/config.go 2023-02-11 19:06:40.000000000 +0100 @@ -346,16 +346,21 @@ stderr: os.Stderr, } + // Override sprig's toPrettyJson template function. Delete it from the + // template function map first to avoid a duplication function panic. + delete(c.templateFuncs, "toPrettyJson") + + // The completion template function is added in persistentPreRunRootE as + // it needs a *cobra.Command, which we don't yet have. for key, value := range map[string]any{ - "awsSecretsManager": c.awsSecretsManagerTemplateFunc, - "awsSecretsManagerRaw": c.awsSecretsManagerRawTemplateFunc, - "bitwarden": c.bitwardenTemplateFunc, - "bitwardenAttachment": c.bitwardenAttachmentTemplateFunc, - "bitwardenFields": c.bitwardenFieldsTemplateFunc, - "comment": c.commentTemplateFunc, - // The completion template function is added in persistentPreRunRootE as - // it needs a *cobra.Command, which we don't yet have. + "awsSecretsManager": c.awsSecretsManagerTemplateFunc, + "awsSecretsManagerRaw": c.awsSecretsManagerRawTemplateFunc, + "bitwarden": c.bitwardenTemplateFunc, + "bitwardenAttachment": c.bitwardenAttachmentTemplateFunc, + "bitwardenFields": c.bitwardenFieldsTemplateFunc, + "comment": c.commentTemplateFunc, "decrypt": c.decryptTemplateFunc, + "deleteValueAtPath": c.deleteValueAtPathTemplateFunc, "encrypt": c.encryptTemplateFunc, "eqFold": c.eqFoldTemplateFunc, "fromIni": c.fromIniTemplateFunc, @@ -395,6 +400,7 @@ "passFields": c.passFieldsTemplateFunc, "passRaw": c.passRawTemplateFunc, "passhole": c.passholeTemplateFunc, + "pruneEmptyDicts": c.pruneEmptyDictsTemplateFunc, "quoteList": c.quoteListTemplateFunc, "replaceAllRegex": c.replaceAllRegexTemplateFunc, "secret": c.secretTemplateFunc, @@ -402,6 +408,7 @@ "setValueAtPath": c.setValueAtPathTemplateFunc, "stat": c.statTemplateFunc, "toIni": c.toIniTemplateFunc, + "toPrettyJson": c.toPrettyJsonTemplateFunc, "toToml": c.toTomlTemplateFunc, "toYaml": c.toYamlTemplateFunc, "vault": c.vaultTemplateFunc, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/cmd/targetpathcmd.go new/chezmoi-2.30.1/pkg/cmd/targetpathcmd.go --- old/chezmoi-2.30.0/pkg/cmd/targetpathcmd.go 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/cmd/targetpathcmd.go 2023-02-11 19:06:40.000000000 +0100 @@ -33,7 +33,7 @@ return err } - argRelPath, err := argAbsPath.TrimDirPrefix(c.SourceDirAbsPath) + argRelPath, err := argAbsPath.TrimDirPrefix(c.sourceDirAbsPath) if err != nil { return err } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/cmd/templatefuncs.go new/chezmoi-2.30.1/pkg/cmd/templatefuncs.go --- old/chezmoi-2.30.0/pkg/cmd/templatefuncs.go 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/cmd/templatefuncs.go 2023-02-11 19:06:40.000000000 +0100 @@ -2,6 +2,7 @@ import ( "encoding/hex" + "encoding/json" "errors" "fmt" "io" @@ -96,6 +97,29 @@ return builder.String() } +func (c *Config) deleteValueAtPathTemplateFunc(path string, dict map[string]any) any { + keys, lastKey, err := keysFromPath(path) + if err != nil { + panic(err) + } + + currentMap := dict + for _, key := range keys { + value, ok := currentMap[key] + if !ok { + return dict + } + nestedMap, ok := value.(map[string]any) + if !ok { + return dict + } + currentMap = nestedMap + } + delete(currentMap, lastKey) + + return dict +} + func (c *Config) eqFoldTemplateFunc(first, second string, more ...string) bool { if strings.EqualFold(first, second) { return true @@ -289,6 +313,11 @@ return string(output) } +func (c *Config) pruneEmptyDictsTemplateFunc(dict map[string]any) map[string]any { + pruneEmptyMaps(dict) + return dict +} + func (c *Config) quoteListTemplateFunc(list []any) []string { result := make([]string, 0, len(list)) for _, elem := range list { @@ -385,6 +414,34 @@ return builder.String() } +//nolint:revive,stylecheck +func (c *Config) toPrettyJsonTemplateFunc(args ...any) string { + var ( + indent = " " + value any + ) + switch len(args) { + case 1: + value = args[0] + case 2: + var ok bool + indent, ok = args[0].(string) + if !ok { + panic(fmt.Errorf("arg 1: expected a string, got a %T", args[0])) + } + value = args[1] + default: + panic(fmt.Errorf("expected 1 or 2 arguments, got %d", len(args))) + } + var builder strings.Builder + encoder := json.NewEncoder(&builder) + encoder.SetIndent("", indent) + if err := encoder.Encode(value); err != nil { + panic(err) + } + return builder.String() +} + func (c *Config) toTomlTemplateFunc(data any) string { toml, err := chezmoi.FormatTOML.Marshal(data) if err != nil { @@ -564,6 +621,21 @@ return false } +// pruneEmptyMaps prunes all empty maps from m and returns if m is now empty +// itself. +func pruneEmptyMaps(m map[string]any) bool { + for key, value := range m { + nestedMap, ok := value.(map[string]any) + if !ok { + continue + } + if pruneEmptyMaps(nestedMap) { + delete(m, key) + } + } + return len(m) == 0 +} + func sortedKeys[K constraints.Ordered, V any](m map[K]V) []K { keys := maps.Keys(m) slices.Sort(keys) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/cmd/templatefuncs_test.go new/chezmoi-2.30.1/pkg/cmd/templatefuncs_test.go --- old/chezmoi-2.30.0/pkg/cmd/templatefuncs_test.go 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/cmd/templatefuncs_test.go 2023-02-11 19:06:40.000000000 +0100 @@ -54,6 +54,145 @@ } } +func TestDeleteValueAtPathTemplateFunc(t *testing.T) { + for _, tc := range []struct { + name string + dict map[string]any + path string + expected any + expectedErr string + }{ + { + name: "empty", + expectedErr: "empty path", + }, + { + name: "outer", + dict: map[string]any{ + "key": "value", + }, + path: "key", + expected: map[string]any{}, + }, + { + name: "inner", + dict: map[string]any{ + "key1": map[string]any{ + "key2a": "value2a", + "key2b": "value2b", + }, + }, + path: "key1.key2a", + expected: map[string]any{ + "key1": map[string]any{ + "key2b": "value2b", + }, + }, + }, + { + name: "missing", + dict: map[string]any{ + "key": "value", + }, + path: "missingKey", + expected: map[string]any{ + "key": "value", + }, + }, + { + name: "missing_inner", + dict: map[string]any{ + "key1": map[string]any{ + "key2": 0, + }, + }, + path: "key1.key3", + expected: map[string]any{ + "key1": map[string]any{ + "key2": 0, + }, + }, + }, + { + name: "missing_depth2", + dict: map[string]any{ + "key1": map[string]any{ + "key2": map[string]any{ + "key3": 0, + }, + }, + }, + path: "key1.key2.missingKey", + expected: map[string]any{ + "key1": map[string]any{ + "key2": map[string]any{ + "key3": 0, + }, + }, + }, + }, + { + name: "not_an_inner_dict", + dict: map[string]any{ + "key1": map[string]any{ + "key2": 0, + }, + }, + path: "key1.key2.key3", + expected: map[string]any{ + "key1": map[string]any{ + "key2": 0, + }, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + var c Config + if tc.expectedErr == "" { + actual := c.deleteValueAtPathTemplateFunc(tc.path, tc.dict) + assert.Equal(t, tc.expected, actual) + } else { + assert.PanicsWithError(t, tc.expectedErr, func() { + c.deleteValueAtPathTemplateFunc(tc.path, tc.dict) + }) + } + }) + } +} + +func TestPruneEmptyDicts(t *testing.T) { + for _, tc := range []struct { + name string + dict map[string]any + expected map[string]any + }{ + { + name: "nil", + dict: nil, + expected: nil, + }, + { + name: "empty", + dict: map[string]any{}, + expected: map[string]any{}, + }, + { + name: "nested_empty", + dict: map[string]any{ + "key1": map[string]any{}, + "key2": 0, + }, + expected: map[string]any{ + "key2": 0, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expected, (&Config{}).pruneEmptyDictsTemplateFunc(tc.dict)) + }) + } +} + func TestSetValueAtPathTemplateFunc(t *testing.T) { for _, tc := range []struct { name string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/cmd/testdata/scripts/issue2752.txtar new/chezmoi-2.30.1/pkg/cmd/testdata/scripts/issue2752.txtar --- old/chezmoi-2.30.0/pkg/cmd/testdata/scripts/issue2752.txtar 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/cmd/testdata/scripts/issue2752.txtar 2023-02-11 19:06:40.000000000 +0100 @@ -0,0 +1,10 @@ +[windows] skip 'uses forward slashes in paths' + +# test that chezmoi target-path does not include .chezmoiroot in the output +exec chezmoi target-path $CHEZMOISOURCEDIR${/}home${/}dot_file +stdout ${HOME@R}/\.file + +-- home/user/.local/share/chezmoi/.chezmoiroot -- +home +-- home/user/.local/share/chezmoi/home/dot_file -- +# contents of .file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.30.0/pkg/cmd/testdata/scripts/templatefuncs.txtar new/chezmoi-2.30.1/pkg/cmd/testdata/scripts/templatefuncs.txtar --- old/chezmoi-2.30.0/pkg/cmd/testdata/scripts/templatefuncs.txtar 2023-02-06 09:14:47.000000000 +0100 +++ new/chezmoi-2.30.1/pkg/cmd/testdata/scripts/templatefuncs.txtar 2023-02-11 19:06:40.000000000 +0100 @@ -14,6 +14,11 @@ exec chezmoi execute-template '{{ completion "zsh" }}' stdout '^# zsh completion for chezmoi' +# test deleteValueAtPath template function +exec chezmoi execute-template '{{ dict "a" (dict "b" (dict "c" 1 "d" 2)) | deleteValueAtPath "a.b.c" | toJson }}' +rmfinalnewline golden/deleteValueAtPath +cmp stdout golden/deleteValueAtPath + # test eqFold template function exec chezmoi execute-template '{{ eqFold "foo" "Foo" "FOO" }}' stdout '^true$' @@ -79,6 +84,11 @@ [!(windows||illumos)] stderr 'error calling output: .*/false: exit status 1' [illumos] stderr 'error calling output: .*/false: exit status 255' +# test pruneEmptyDicts template function +exec chezmoi execute-template '{{ dict "key1" "value1" "key2" (dict) | pruneEmptyDicts | toJson }}' +rmfinalnewline golden/pruneEmptyDicts +cmp stdout golden/pruneEmptyDicts + # test replaceAllRegex template function exec chezmoi execute-template '{{ "foo bar baz" | replaceAllRegex "ba" "BA" }}' stdout 'foo BAr BAz' @@ -111,6 +121,10 @@ exec chezmoi execute-template '{{ dict "key" "value" | toToml }}' stdout '^key = .value.$' +# test toPrettyJson template function +exec chezmoi execute-template '{{ dict "a" (dict "b" "c") | toPrettyJson " " }}' +cmp stdout golden/toPrettyJson + # test fromYaml template function exec chezmoi execute-template '{{ (fromYaml "key1: value1\nkey2: value2").key2 }}' stdout '^value2$' @@ -175,6 +189,8 @@ -- golden/comment -- # line1 # line2 +-- golden/deleteValueAtPath -- +{"a":{"b":{"d":2}}} -- golden/expected -- 255 -- golden/glob -- @@ -184,6 +200,8 @@ # contents of .include -- golden/include-relpath -- # contents of .local/share/chezmoi/.include +-- golden/pruneEmptyDicts -- +{"key1":"value1"} -- golden/setValueAtPath -- {"key1":{"key2":"value2"}} -- golden/toIni -- @@ -191,6 +209,12 @@ [section] subkey = subvalue +-- golden/toPrettyJson -- +{ + "a": { + "b": "c" + } +} -- home/user/.include -- # contents of .include -- home/user/.local/share/chezmoi/.chezmoitemplates/template -- ++++++ chezmoi.obsinfo ++++++ --- /var/tmp/diff_new_pack.HfxlPn/_old 2023-02-13 16:43:25.884263386 +0100 +++ /var/tmp/diff_new_pack.HfxlPn/_new 2023-02-13 16:43:25.888263410 +0100 @@ -1,5 +1,5 @@ name: chezmoi -version: 2.30.0 -mtime: 1675671287 -commit: d16ce211bcd2c55cc1c9ad8df13f3222944caf5f +version: 2.30.1 +mtime: 1676138800 +commit: ff0c704a9068c81b3ad301236d730fefcd9ce98c ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/chezmoi/vendor.tar.gz /work/SRC/openSUSE:Factory/.chezmoi.new.1848/vendor.tar.gz differ: char 5, line 1