Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package chezmoi for openSUSE:Factory checked in at 2024-05-01 14:56:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/chezmoi (Old) and /work/SRC/openSUSE:Factory/.chezmoi.new.1880 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "chezmoi" Wed May 1 14:56:48 2024 rev:52 rq:1171014 version:2.48.0 Changes: -------- --- /work/SRC/openSUSE:Factory/chezmoi/chezmoi.changes 2024-04-16 20:12:03.714572283 +0200 +++ /work/SRC/openSUSE:Factory/.chezmoi.new.1880/chezmoi.changes 2024-05-01 14:57:10.875495367 +0200 @@ -1,0 +2,16 @@ +Tue Apr 30 15:39:55 UTC 2024 - Filippo Bonazzi <filippo.bona...@suse.com> + +- Update to version 2.48.0: + - Features + * feat: Add --tree flag to unmanaged command + * feat: Add --tree flag to managed command + * feat: Add --tree flag to ignored command + * feat: Include name of target in error message + - Fixes + * fix: Apply .chezmoiignore to dirs in external archives + * fix: Remove unmanaged files from exact_ directories containing external files + * fix: Better detect username on Android/Termux systems + - Documentation updates + * docs: Document --tree flag + +------------------------------------------------------------------- Old: ---- chezmoi-2.47.4.obscpio New: ---- chezmoi-2.48.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ chezmoi.spec ++++++ --- /var/tmp/diff_new_pack.gGnN0Q/_old 2024-05-01 14:57:11.571520620 +0200 +++ /var/tmp/diff_new_pack.gGnN0Q/_new 2024-05-01 14:57:11.571520620 +0200 @@ -17,7 +17,7 @@ Name: chezmoi -Version: 2.47.4 +Version: 2.48.0 Release: 0 Summary: A multi-host manager for dotfiles License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.gGnN0Q/_old 2024-05-01 14:57:11.615522217 +0200 +++ /var/tmp/diff_new_pack.gGnN0Q/_new 2024-05-01 14:57:11.619522361 +0200 @@ -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.47.4</param> + <param name="revision">v2.48.0</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> </service> ++++++ chezmoi-2.47.4.obscpio -> chezmoi-2.48.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/.github/workflows/govulncheck.yml new/chezmoi-2.48.0/.github/workflows/govulncheck.yml --- old/chezmoi-2.47.4/.github/workflows/govulncheck.yml 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/.github/workflows/govulncheck.yml 2024-04-26 21:51:18.000000000 +0200 @@ -16,7 +16,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - name: go-version id: go-version run: | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/.github/workflows/installer.yml new/chezmoi-2.48.0/.github/workflows/installer.yml --- old/chezmoi-2.47.4/.github/workflows/installer.yml 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/.github/workflows/installer.yml 2024-04-26 21:51:18.000000000 +0200 @@ -17,7 +17,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - id: filter uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 with: @@ -36,7 +36,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: reviewdog/action-misspell@5bd7be2fc7ae56a517184f5c4bbcf2fd7afe3927 with: locale: US @@ -50,7 +50,7 @@ env: BINARY: ${{ matrix.os == 'windows-2022' && 'bin/chezmoi.exe' || 'bin/chezmoi' }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - name: test-${{ matrix.os }}-local shell: bash run: | @@ -73,7 +73,7 @@ env: BINARY: ${{ matrix.os == 'windows-2022' && 'bin/chezmoi.exe' || 'bin/chezmoi' }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - name: test-${{ matrix.os }}-local shell: pwsh run: | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/.github/workflows/main.yml new/chezmoi-2.48.0/.github/workflows/main.yml --- old/chezmoi-2.47.4/.github/workflows/main.yml 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/.github/workflows/main.yml 2024-04-26 21:51:18.000000000 +0200 @@ -30,7 +30,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - id: filter uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 with: @@ -56,7 +56,7 @@ permissions: security-events: write steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b with: fetch-depth: 1 - uses: github/codeql-action/init@1b1aada464948af03b950897e5eb522f92603cc2 @@ -68,7 +68,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: reviewdog/action-misspell@5bd7be2fc7ae56a517184f5c4bbcf2fd7afe3927 with: locale: US @@ -79,7 +79,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - name: test env: CHEZMOI_GITHUB_TOKEN: ${{ secrets.CHEZMOI_GITHUB_TOKEN }} @@ -92,7 +92,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - name: test env: CHEZMOI_GITHUB_TOKEN: ${{ secrets.CHEZMOI_GITHUB_TOKEN }} @@ -105,7 +105,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 with: go-version: ${{ env.GO_VERSION }} @@ -140,7 +140,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 with: go-version: oldstable @@ -173,7 +173,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b with: fetch-depth: 0 - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 @@ -238,7 +238,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b with: fetch-depth: 0 - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 @@ -280,7 +280,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 with: go-version: ${{ env.GO_VERSION }} @@ -298,7 +298,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 with: go-version: ${{ env.GO_VERSION }} @@ -324,7 +324,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b with: fetch-depth: 0 - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 @@ -372,7 +372,7 @@ permissions: contents: read steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 with: go-version: ${{ env.GO_VERSION }} @@ -414,13 +414,13 @@ run: snapcraft whoami env: SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }} - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b with: fetch-depth: 0 - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 with: go-version: ${{ env.GO_VERSION }} - - uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 + - uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 - name: create-syso run: | make create-syso @@ -442,7 +442,7 @@ permissions: contents: write steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b with: fetch-depth: 0 - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/assets/chezmoi.io/docs/links/articles.md.yaml new/chezmoi-2.48.0/assets/chezmoi.io/docs/links/articles.md.yaml --- old/chezmoi-2.47.4/assets/chezmoi.io/docs/links/articles.md.yaml 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/assets/chezmoi.io/docs/links/articles.md.yaml 2024-04-26 21:51:18.000000000 +0200 @@ -1,4 +1,4 @@ -articles: +Garticles: - date: '2019-01-10' version: 0.0.11 title: 'Linux Fu: The kitchen sync' @@ -407,3 +407,7 @@ version: 2.47.2 title: Whatever happened to dotfiles? url: https://ryan0x44.substack.com/p/whatever-happened-to-dotfiles +- date: '2024-04-24' + version: 2.47.4 + title: 'Chezmoi: Manage Your Dotfiles Across Multiple Linux Systems' + url: https://linuxtldr.com/installing-chezmoi/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/assets/chezmoi.io/docs/quick-start.md new/chezmoi-2.48.0/assets/chezmoi.io/docs/quick-start.md --- old/chezmoi-2.47.4/assets/chezmoi.io/docs/quick-start.md 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/assets/chezmoi.io/docs/quick-start.md 2024-04-26 21:51:18.000000000 +0200 @@ -74,7 +74,7 @@ and then push your repo: ```console -$ git remote add origin https://github.com/$GITHUB_USERNAME/dotfiles.git +$ git remote add origin g...@github.com:$GITHUB_USERNAME/dotfiles.git $ git branch -M main $ git push -u origin main ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/assets/chezmoi.io/docs/reference/command-line-flags/common.md new/chezmoi-2.48.0/assets/chezmoi.io/docs/reference/command-line-flags/common.md --- old/chezmoi-2.47.4/assets/chezmoi.io/docs/reference/command-line-flags/common.md 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/assets/chezmoi.io/docs/reference/command-line-flags/common.md 2024-04-26 21:51:18.000000000 +0200 @@ -55,6 +55,10 @@ Interpret *targets* passed to the command as paths in the source directory rather than the destination directory. +## `--tree` + +Print paths as a tree instead of a list. + ## `--use-builtin-diff` Use chezmoi's builtin diff, even if the `diff.command` configuration variable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/go.mod new/chezmoi-2.48.0/go.mod --- old/chezmoi-2.47.4/go.mod 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/go.mod 2024-04-26 21:51:18.000000000 +0200 @@ -6,12 +6,12 @@ require ( filippo.io/age v1.1.1 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.1.0 github.com/Masterminds/sprig/v3 v3.2.3 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 github.com/Shopify/ejson v1.5.0 - github.com/alecthomas/assert/v2 v2.8.0 + github.com/alecthomas/assert/v2 v2.8.1 github.com/aws/aws-sdk-go-v2 v1.26.1 github.com/aws/aws-sdk-go-v2/config v1.27.11 github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6 @@ -32,7 +32,7 @@ github.com/mitchellh/mapstructure v1.5.0 github.com/muesli/combinator v0.3.0 github.com/muesli/termenv v0.15.2 - github.com/pelletier/go-toml/v2 v2.2.0 + github.com/pelletier/go-toml/v2 v2.2.1 github.com/rogpeppe/go-internal v1.12.0 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 github.com/spf13/cobra v1.8.0 @@ -60,13 +60,13 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.1 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/BobuSumisu/aho-corasick v1.0.3 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/alecthomas/chroma/v2 v2.13.0 // indirect github.com/alecthomas/repr v0.4.0 // indirect @@ -88,7 +88,7 @@ github.com/bradenhilton/cityhash v1.0.0 // indirect github.com/charmbracelet/harmonica v0.2.0 // indirect github.com/charmbracelet/lipgloss v0.10.0 // indirect - github.com/cloudflare/circl v1.3.7 // indirect + github.com/cloudflare/circl v1.3.8 // indirect github.com/containerd/console v1.0.4 // indirect github.com/creack/pty/v2 v2.0.0-20231209135443-03db72c7b76c // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect @@ -136,7 +136,7 @@ github.com/rs/zerolog v1.32.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/shopspring/decimal v1.3.1 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/skeema/knownhosts v1.2.2 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect @@ -147,8 +147,7 @@ github.com/yuin/goldmark v1.7.1 // indirect github.com/yuin/goldmark-emoji v1.0.2 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect - golang.org/x/mod v0.17.0 // indirect + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.20.0 // indirect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/go.sum new/chezmoi-2.48.0/go.sum --- old/chezmoi-2.47.4/go.sum 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/go.sum 2024-04-26 21:51:18.000000000 +0200 @@ -20,14 +20,14 @@ filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 h1:FDif4R1+UUR+00q6wquyX90K7A8dN+R5E8GEadoP7sU= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2/go.mod h1:aiYBYui4BJ/BJCAIKs92XiPyQfTaBWqvHujDwKb6CBU= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 h1:sUFnFjzDUie80h24I7mrKtwCKgLY9L8h5Tp2x9+TWqk= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0/go.mod h1:52JbnQTp15qg5mRkMBHwp0j0ZFwHJ42Sx3zVV5RE9p0= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.1.0 h1:h4Zxgmi9oyZL2l8jeg1iRTqPloHktywWcu0nlJmo1tA= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.1.0/go.mod h1:LgLGXawqSreJz135Elog0ywTJDsm0Hz2k+N+6ZK35u8= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.1 h1:9fXQS/0TtQmKXp8SureKouF+idbQvp7cPUxykiohnBs= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.1/go.mod h1:f+OaoSg0VQYPMqB0Jp2D54j1VHzITYcJaCNwV+k00ts= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BobuSumisu/aho-corasick v1.0.3 h1:uuf+JHwU9CHP2Vx+wAy6jcksJThhJS9ehR8a+4nPE9g= @@ -40,16 +40,16 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/Shopify/ejson v1.5.0 h1:SDV5HmQlpn3hSUiw9HV0nOj9tpzup5i0OV71ioLYkpw= github.com/Shopify/ejson v1.5.0/go.mod h1:a4+JLWuTe9+tTofPBGWZoqzf0af6eQKGmFqbxoMSARc= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= -github.com/alecthomas/assert/v2 v2.8.0 h1:8b0foWfS2dH6MltxQMPvWdSGN1wE4K1vyab9PGW4qgE= -github.com/alecthomas/assert/v2 v2.8.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/assert/v2 v2.8.1 h1:YCxnYR6jjpfnEK5AK5SysALKdUEBPGH4Y7As6tBnDw0= +github.com/alecthomas/assert/v2 v2.8.1/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI= github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= @@ -115,8 +115,8 @@ github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s= github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI= +github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= @@ -304,6 +304,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5 h1:8Q0qkMVC/MmWkpIdlvZgcv2o2jrlF6zqVOh7W5YHdMA= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU= github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= @@ -328,8 +330,8 @@ github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= -github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg= +github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= @@ -368,11 +370,11 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= @@ -466,8 +468,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= -golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/chezmoi/sourcestate.go new/chezmoi-2.48.0/internal/chezmoi/sourcestate.go --- old/chezmoi-2.47.4/internal/chezmoi/sourcestate.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/chezmoi/sourcestate.go 2024-04-26 21:51:18.000000000 +0200 @@ -1108,6 +1108,14 @@ allSourceStateEntries[targetRelPath] = append(allSourceStateEntries[targetRelPath], sourceStateEntry) } + // Where there are multiple SourceStateEntries for a single target, replace + // them with a single canonical SourceStateEntry if possible. + for targetRelPath, sourceStateEntries := range allSourceStateEntries { + if sourceStateEntry, ok := canonicalSourceStateEntry(sourceStateEntries); ok { + allSourceStateEntries[targetRelPath] = []SourceStateEntry{sourceStateEntry} + } + } + // Generate SourceStateRemoves for exact directories. for targetRelPath, sourceStateEntries := range allSourceStateEntries { if len(sourceStateEntries) != 1 { @@ -1231,11 +1239,6 @@ continue } - // Allow duplicate equivalent source entries for directories. - if allEquivalentDirs(sourceStateEntries) { - continue - } - origins := make([]string, 0, len(sourceStateEntries)) for _, sourceStateEntry := range sourceStateEntries { origins = append(origins, sourceStateEntry.Origin().OriginString()) @@ -2191,7 +2194,7 @@ }, nil } -// populateImplicitDirs creates implicit parent directories for externalRelPath. +// populateImplicitParentDirs creates implicit parent directories for externalRelPath. func (s *SourceState) populateImplicitParentDirs( externalRelPath RelPath, external *External, @@ -2307,6 +2310,9 @@ targetRelPath := externalRelPath.JoinString(name) if s.Ignore(targetRelPath) { + if fileInfo.IsDir() { + return fs.SkipDir + } return nil } @@ -2793,9 +2799,12 @@ return e.URL + " defined in " + e.sourceAbsPath.String() } -// allEquivalentDirs returns if sourceStateEntries are all equivalent -// directories. -func allEquivalentDirs(sourceStateEntries []SourceStateEntry) bool { +// canonicalSourceStateEntry returns the canonical SourceStateEntry for the +// given sourceStateEntries. +// +// This only applies to directories, where SourceStateImplicitDirs are +// considered equivalent to all SourceStateDirs. +func canonicalSourceStateEntry(sourceStateEntries []SourceStateEntry) (SourceStateEntry, bool) { // Find all directories to check for equivalence. var firstSourceStateDir *SourceStateDir sourceStateDirs := make([]SourceStateEntry, 0, len(sourceStateEntries)) @@ -2807,29 +2816,37 @@ case *SourceStateImplicitDir: sourceStateDirs = append(sourceStateDirs, sourceStateEntry) default: - return false + return nil, false } } - // If there are no SourceStateDirs then there are no equivalent directories. - if len(sourceStateDirs) == 0 { - return false - } - - // Check for equivalence. - for _, sourceStateDir := range sourceStateDirs { - switch sourceStateDir := sourceStateDir.(type) { - case *SourceStateDir: - if sourceStateDir.Attr != firstSourceStateDir.Attr { - return false + switch len(sourceStateDirs) { + case 0: + // If there are no SourceStateDirs then there are no equivalent directories. + return nil, false + case 1: + return sourceStateDirs[0], true + default: + // Check for equivalence. + for _, sourceStateDir := range sourceStateDirs { + switch sourceStateDir := sourceStateDir.(type) { + case *SourceStateDir: + if sourceStateDir.Attr != firstSourceStateDir.Attr { + return nil, false + } + case *SourceStateImplicitDir: + // SourceStateImplicitDirs are considered equivalent to all other + // directories. } - case *SourceStateImplicitDir: - // SourceStateImplicitDirs are considered equivalent to all other - // directories. } + // If all directories are equivalent then return the first real + // *SourceStateDir, if it exists. + if firstSourceStateDir != nil { + return firstSourceStateDir, true + } + // Otherwise, return the first entry which is a *SourceStateImplicitDir. + return sourceStateDirs[0], true } - - return true } // isAppleDoubleFile returns true if the file looks like and has the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/chezmoitest/chezmoitest.go new/chezmoi-2.48.0/internal/chezmoitest/chezmoitest.go --- old/chezmoi-2.47.4/internal/chezmoitest/chezmoitest.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/chezmoitest/chezmoitest.go 2024-04-26 21:51:18.000000000 +0200 @@ -69,6 +69,9 @@ // JoinLines joins lines with newlines. func JoinLines(lines ...string) string { + if len(lines) == 0 { + return "" + } return strings.Join(lines, "\n") + "\n" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/chezmoitest/chezmoitest_test.go new/chezmoi-2.48.0/internal/chezmoitest/chezmoitest_test.go --- old/chezmoi-2.47.4/internal/chezmoitest/chezmoitest_test.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/chezmoitest/chezmoitest_test.go 2024-04-26 21:51:18.000000000 +0200 @@ -14,7 +14,7 @@ }{ { lines: nil, - expected: "\n", + expected: "", }, { lines: []string{""}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/applycmd_test.go new/chezmoi-2.48.0/internal/cmd/applycmd_test.go --- old/chezmoi-2.47.4/internal/cmd/applycmd_test.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/applycmd_test.go 2024-04-26 21:51:18.000000000 +0200 @@ -2,6 +2,8 @@ import ( "io/fs" + "net/http" + "net/http/httptest" "path/filepath" "testing" @@ -233,6 +235,27 @@ }) } +func TestIssue2597(t *testing.T) { + chezmoitest.WithTestFS(t, map[string]any{ + "/home/user": map[string]any{ + ".local/share/chezmoi": map[string]any{ + ".chezmoiexternal.toml": chezmoitest.JoinLines( + `[".oh-my-zsh"]`, + ` type = "archive"`, + ` url = "https://github.com/ohmyzsh/ohmyzsh/archive/master.tar.gz"`, + ` exact = true`, + ` stripComponents = 1`, + ), + ".chezmoiignore": chezmoitest.JoinLines( + `.oh-my-zsh/cache`, + ), + }, + }, + }, func(fileSystem vfs.FS) { + assert.NoError(t, newTestConfig(t, fileSystem).execute([]string{"apply"})) + }) +} + func TestIssue3206(t *testing.T) { chezmoitest.WithTestFS(t, map[string]any{ "/home/user": map[string]any{ @@ -264,3 +287,39 @@ assert.NoError(t, newTestConfig(t, fileSystem).execute([]string{"apply"})) }) } + +func TestIssue3703(t *testing.T) { + httpServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, err := w.Write([]byte("contents of file\n")) + assert.NoError(t, err) + })) + defer httpServer.Close() + + chezmoitest.WithTestFS(t, map[string]any{ + "/home/user": map[string]any{ + ".local": map[string]any{ + "bin": map[string]any{ + "unmanaged": "", + }, + "share/chezmoi": map[string]any{ + ".chezmoiexternal.toml.tmpl": chezmoitest.JoinLines( + `[".local/bin/file"]`, + ` type = "file"`, + ` url = "`+httpServer.URL+`/file"`, + ), + "dot_local/exact_bin/.keep": "", + }, + }, + }, + }, func(fileSystem vfs.FS) { + assert.NoError(t, newTestConfig(t, fileSystem).execute([]string{"apply"})) + vfst.RunTests(t, fileSystem, ".local/bin", + vfst.TestPath("/home/user/.local/bin/file", + vfst.TestContentsString("contents of file\n"), + ), + vfst.TestPath("/home/user/.local/bin/unmanaged", + vfst.TestDoesNotExist(), + ), + ) + }) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/cmd.go new/chezmoi-2.48.0/internal/cmd/cmd.go --- old/chezmoi-2.47.4/internal/cmd/cmd.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/cmd.go 2024-04-26 21:51:18.000000000 +0200 @@ -138,7 +138,7 @@ return help.example } -// extractHelps returns the helps parse from r. +// extractHelp returns the helps parse from r. func extractHelp(command string, data []byte, longHelpTermRenderer, exampleTermRenderer *glamour.TermRenderer) (*help, error) { type stateType int const ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/config.go new/chezmoi-2.48.0/internal/cmd/config.go --- old/chezmoi-2.47.4/internal/cmd/config.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/config.go 2024-04-26 21:51:18.000000000 +0200 @@ -194,6 +194,7 @@ chattr chattrCmdConfig dump dumpCmdConfig executeTemplate executeTemplateCmdConfig + ignored ignoredCmdConfig _import importCmdConfig init initCmdConfig managed managedCmdConfig @@ -652,11 +653,14 @@ switch err := sourceState.Apply(targetSystem, c.destSystem, c.persistentState, targetDirAbsPath, targetRelPath, applyOptions); { case errors.Is(err, fs.SkipDir): continue - case err != nil && c.keepGoing: - c.errorf("%v\n", err) - keptGoingAfterErr = true case err != nil: - return err + err = fmt.Errorf("%s: %w", targetRelPath, err) + if c.keepGoing { + c.errorf("%v\n", err) + keptGoingAfterErr = true + } else { + return err + } } } @@ -2219,23 +2223,28 @@ func (c *Config) newTemplateData(cmd *cobra.Command) *templateData { // Determine the user's username and group, if possible. // - // user.Current and user.LookupGroupId in Go's standard library are + // os/user.Current and os/user.LookupGroupId in Go's standard library are // generally unreliable, so work around errors if possible, or ignore them. // + // On Android, user.Current always fails. Instead, use $LOGNAME (as this is + // set by Termux), or $USER if $LOGNAME is not set. + // // If CGO is disabled, then the Go standard library falls back to parsing // /etc/passwd and /etc/group, which will return incorrect results without // error if the system uses an alternative password database such as NIS or // LDAP. // - // If CGO is enabled then user.Current and user.LookupGroupId will use the - // underlying libc functions, namely getpwuid_r and getgrnam_r. If linked - // with glibc this will return the correct result. If linked with musl then - // they will use musl's implementation which, like Go's non-CGO + // If CGO is enabled then os/user.Current and os/user.LookupGroupId will use + // the underlying libc functions, namely getpwuid_r and getgrnam_r. If + // linked with glibc this will return the correct result. If linked with + // musl then they will use musl's implementation which, like Go's non-CGO // implementation, also only parses /etc/passwd and /etc/group and so also // returns incorrect results without error if NIS or LDAP are being used. // - // On Windows, the user's group ID returned by user.Current() is an SID and - // no further useful lookup is possible with Go's standard library. + // On Windows, the user's group ID returned by os/user.Current() is an SID + // and no further useful lookup is possible with Go's standard library. + // + // If os/user.Current fails, then fallback to $USER. // // Since neither the username nor the group are likely widely used in // templates, leave these variables unset if their values cannot be @@ -2243,7 +2252,9 @@ // alerting the user to the problem and allowing them to find alternative // solutions. var gid, group, uid, username string - if currentUser, err := user.Current(); err == nil { + if runtime.GOOS == "android" { + username = firstNonEmptyString(os.Getenv("LOGNAME"), os.Getenv("USER")) + } else if currentUser, err := user.Current(); err == nil { gid = currentUser.Gid uid = currentUser.Uid username = currentUser.Username @@ -2657,6 +2668,23 @@ return os.WriteFile(c.outputAbsPath.String(), data, 0o666) //nolint:gosec } +type writePathsOptions struct { + tree bool +} + +func (c *Config) writePaths(paths []string, options writePathsOptions) error { + builder := strings.Builder{} + if options.tree { + newPathListTreeFromPathsSlice(paths).writeChildren(&builder, "", " ") + } else { + sort.Strings(paths) + for _, path := range paths { + fmt.Fprintln(&builder, path) + } + } + return c.writeOutputString(builder.String()) +} + // writeOutputString writes data to the configured output. func (c *Config) writeOutputString(data string) error { return c.writeOutput([]byte(data)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/ignoredcmd.go new/chezmoi-2.48.0/internal/cmd/ignoredcmd.go --- old/chezmoi-2.47.4/internal/cmd/ignoredcmd.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/ignoredcmd.go 2024-04-26 21:51:18.000000000 +0200 @@ -1,13 +1,15 @@ package cmd import ( - "strings" - "github.com/spf13/cobra" "github.com/twpayne/chezmoi/v2/internal/chezmoi" ) +type ignoredCmdConfig struct { + tree bool +} + func (c *Config) newIgnoredCmd() *cobra.Command { ignoredCmd := &cobra.Command{ Use: "ignored", @@ -19,18 +21,13 @@ Annotations: newAnnotations(), } + ignoredCmd.Flags().BoolVarP(&c.ignored.tree, "tree", "t", c.ignored.tree, "Print paths as a tree") + return ignoredCmd } func (c *Config) runIgnoredCmd(cmd *cobra.Command, args []string, sourceState *chezmoi.SourceState) error { - builder := strings.Builder{} - for _, relPath := range sourceState.Ignored() { - if _, err := builder.WriteString(relPath.String()); err != nil { - return err - } - if err := builder.WriteByte('\n'); err != nil { - return err - } - } - return c.writeOutputString(builder.String()) + return c.writePaths(stringersToStrings(sourceState.Ignored()), writePathsOptions{ + tree: c.ignored.tree, + }) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/managedcmd.go new/chezmoi-2.48.0/internal/cmd/managedcmd.go --- old/chezmoi-2.47.4/internal/cmd/managedcmd.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/managedcmd.go 2024-04-26 21:51:18.000000000 +0200 @@ -2,8 +2,6 @@ import ( "fmt" - "sort" - "strings" "github.com/spf13/cobra" @@ -13,6 +11,7 @@ type managedCmdConfig struct { filter *chezmoi.EntryTypeFilter pathStyle chezmoi.PathStyle + tree bool } func (c *Config) newManagedCmd() *cobra.Command { @@ -30,6 +29,7 @@ managedCmd.Flags().VarP(c.managed.filter.Exclude, "exclude", "x", "Exclude entry types") managedCmd.Flags().VarP(c.managed.filter.Include, "include", "i", "Include entry types") managedCmd.Flags().VarP(&c.managed.pathStyle, "path-style", "p", "Path style") + managedCmd.Flags().BoolVarP(&c.managed.tree, "tree", "t", c.managed.tree, "Print paths as a tree") return managedCmd } @@ -48,7 +48,7 @@ } } - var paths []string + var paths []fmt.Stringer _ = sourceState.ForEach( func(targetRelPath chezmoi.RelPath, sourceStateEntry chezmoi.SourceStateEntry) error { if !c.managed.filter.IncludeSourceStateEntry(sourceStateEntry) { @@ -77,26 +77,23 @@ } } - var path string + var path fmt.Stringer switch c.managed.pathStyle { case chezmoi.PathStyleAbsolute: - path = c.DestDirAbsPath.Join(targetRelPath).String() + path = c.DestDirAbsPath.Join(targetRelPath) case chezmoi.PathStyleRelative: - path = targetRelPath.String() + path = targetRelPath case chezmoi.PathStyleSourceAbsolute: - path = c.SourceDirAbsPath.Join(sourceStateEntry.SourceRelPath().RelPath()).String() + path = c.SourceDirAbsPath.Join(sourceStateEntry.SourceRelPath().RelPath()) case chezmoi.PathStyleSourceRelative: - path = sourceStateEntry.SourceRelPath().RelPath().String() + path = sourceStateEntry.SourceRelPath().RelPath() } paths = append(paths, path) return nil }, ) - sort.Strings(paths) - builder := strings.Builder{} - for _, path := range paths { - fmt.Fprintln(&builder, path) - } - return c.writeOutputString(builder.String()) + return c.writePaths(stringersToStrings(paths), writePathsOptions{ + tree: c.managed.tree, + }) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/pathlist.go new/chezmoi-2.48.0/internal/cmd/pathlist.go --- old/chezmoi-2.47.4/internal/cmd/pathlist.go 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.48.0/internal/cmd/pathlist.go 2024-04-26 21:51:18.000000000 +0200 @@ -0,0 +1,49 @@ +package cmd + +import ( + "strings" + + "github.com/twpayne/chezmoi/v2/internal/chezmoimaps" +) + +type pathListTreeNode struct { + component string + children map[string]*pathListTreeNode +} + +func newPathListTreeNode(component string) *pathListTreeNode { + return &pathListTreeNode{ + component: component, + children: make(map[string]*pathListTreeNode), + } +} + +func newPathListTreeFromPathsSlice(paths []string) *pathListTreeNode { + root := newPathListTreeNode("") + for _, path := range paths { + n := root + for _, component := range strings.Split(path, "/") { + child, ok := n.children[component] + if !ok { + child = newPathListTreeNode(component) + n.children[component] = child + } + n = child + } + } + return root +} + +func (n *pathListTreeNode) write(sb *strings.Builder, prefix, indent string) { + sb.WriteString(prefix) + sb.WriteString(n.component) + sb.WriteByte('\n') + n.writeChildren(sb, prefix+indent, indent) +} + +func (n *pathListTreeNode) writeChildren(sb *strings.Builder, prefix, indent string) { + for _, key := range chezmoimaps.SortedKeys(n.children) { + child := n.children[key] + child.write(sb, prefix, indent) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/pathlist_test.go new/chezmoi-2.48.0/internal/cmd/pathlist_test.go --- old/chezmoi-2.47.4/internal/cmd/pathlist_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.48.0/internal/cmd/pathlist_test.go 2024-04-26 21:51:18.000000000 +0200 @@ -0,0 +1,75 @@ +package cmd + +import ( + "strings" + "testing" + + "github.com/alecthomas/assert/v2" + + "github.com/twpayne/chezmoi/v2/internal/chezmoitest" +) + +func TestNewNodeFromPathsSlice(t *testing.T) { + for _, tc := range []struct { + name string + paths []string + expected []string + }{ + { + name: "empty", + }, + { + name: "root", + paths: []string{ + "a", + }, + expected: []string{ + "a", + }, + }, + { + name: "simple", + paths: []string{ + "a", + "b", + }, + expected: []string{ + "a", + "b", + }, + }, + { + name: "simple_nesting", + paths: []string{ + "a/b", + }, + expected: []string{ + "a", + " b", + }, + }, + { + name: "multiple_simple_nesting", + paths: []string{ + "a/a", + "a/b", + "b/a", + "b/b", + }, + expected: []string{ + "a", + " a", + " b", + "b", + " a", + " b", + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + var sb strings.Builder + newPathListTreeFromPathsSlice(tc.paths).writeChildren(&sb, "", " ") + assert.Equal(t, chezmoitest.JoinLines(tc.expected...), sb.String()) + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/apply.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/apply.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/apply.txtar 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/apply.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -69,3 +69,4 @@ # test that chezmoi apply --source-path fails when called with a targetDirAbsPath ! exec chezmoi apply --force --source-path $HOME${/}.file +[!windows] stderr ${HOME@R}/\.file:\snot\sin\s${CHEZMOISOURCEDIR@R}$ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/external.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/external.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/external.txtar 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/external.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -97,7 +97,7 @@ # test that checksums detect corrupt files ! exec chezmoi apply --force -stderr 'MD5 mismatch' +stderr \.file:\sMD5\smismatch stderr 'SHA256 mismatch' chhome home12/user diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/ignore.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/ignore.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/ignore.txtar 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/ignore.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -11,6 +11,10 @@ exec chezmoi ignored cmp stdout golden/ignored +# test that chezmoi ignored --tree lists the ignored entries in a tree-like format +exec chezmoi ignored --tree +cmp stdout golden/ignored-tree + chhome home2/user # test that chezmoi manage lists all managed files @@ -48,6 +52,9 @@ -- golden/ignored -- .dir README.md +-- golden/ignored-tree -- +.dir +README.md -- golden/managed-all -- .dir .dir/file.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/issue2597.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/issue2597.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/issue2597.txtar 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/issue2597.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -0,0 +1,20 @@ +exec tar czf www/master.tar.gz master + +httpd www + +exec chezmoi apply +exists $HOME/.oh-my-zsh/README.md +! exists $HOME/.oh-my-zsh/cache/.gitkeep + +-- home/user/.local/share/chezmoi/.chezmoiexternal.toml.tmpl -- +[".oh-my-zsh"] + type = "archive" + url = "{{ env "HTTPD_URL" }}/master.tar.gz" + exact = true + stripComponents = 1 +-- home/user/.local/share/chezmoi/.chezmoiignore -- +.oh-my-zsh/cache +-- master/README.md -- +# contents of README.md +-- master/cache/.gitkeep -- +-- www/.keep -- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/issue3703.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/issue3703.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/issue3703.txtar 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/issue3703.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -0,0 +1,16 @@ +httpd www + +# test that chezmoi apply removes unmanaged files from an exact_ directory containing an external +exists $HOME/.local/bin/unmanaged +exec chezmoi apply --debug +cmp $HOME/.local/bin/file www/file +! exists $HOME/.local/bin/unmanaged + +-- home/user/.local/bin/unmanaged -- +-- home/user/.local/share/chezmoi/.chezmoiexternal.toml.tmpl -- +[".local/bin/file"] + type = "file" + url = "{{ env "HTTPD_URL" }}/file" +-- home/user/.local/share/chezmoi/dot_local/exact_bin/.keep -- +-- www/file -- +# contents of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/keepgoing.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/keepgoing.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/keepgoing.txtar 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/keepgoing.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -8,6 +8,7 @@ cmp $HOME/1ok golden/1ok ! exists $HOME/2error ! exists $HOME/3ok +stderr '2error: template: 2error\.tmpl:2: unclosed action started at 2error\.tmpl:1' # test that chezmoi apply with --keep-going writes all files that it can without errors ! exec chezmoi apply --force --keep-going diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/managedtree.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/managedtree.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/managedtree.txtar 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/managedtree.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -0,0 +1,20 @@ +mksourcedir + +# test that chezmoi managed --tree produces tree-like output +exec chezmoi managed --tree +cmp stdout golden/stdout + +-- golden/stdout -- +.create +.dir + file + subdir + file +.empty +.executable +.file +.private +.readonly +.remove +.symlink +.template diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/noencryption.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/noencryption.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/noencryption.txtar 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/noencryption.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -6,7 +6,7 @@ # test that chezmoi apply without encryption fails ! exec chezmoi apply --force -stderr 'no encryption' +stderr \.encrypted:\sno\sencryption$ -- home/user/.encrypted -- # contents of .encrypted diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/scriptsdir_unix.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/scriptsdir_unix.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/scriptsdir_unix.txtar 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/scriptsdir_unix.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -8,13 +8,13 @@ # test that chezmoi apply fails if .chezmoiscripts contains a non-script ! exec chezmoi apply -stderr 'not a script' +stderr ${CHEZMOISOURCEDIR@R}/\.chezmoiscripts/dot_file:\snot\sa\sscript$ chhome home3/user # test that chezmoi apply fails if .chezmoiscripts contains duplicate targets ! exec chezmoi apply -stderr 'inconsistent state' +stderr \.chezmoiscripts/script\.sh:\sinconsistent\sstate chhome home4/user diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/testdata/scripts/unmanagedtree.txtar new/chezmoi-2.48.0/internal/cmd/testdata/scripts/unmanagedtree.txtar --- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/unmanagedtree.txtar 1970-01-01 01:00:00.000000000 +0100 +++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/unmanagedtree.txtar 2024-04-26 21:51:18.000000000 +0200 @@ -0,0 +1,12 @@ +# test that chezmoi unmanaged --tree produces tree-like output +exec chezmoi unmanaged --tree +cmp stdout golden/stdout + +-- golden/stdout -- +.dir + file + subdir +.local +-- home/user/.dir/file -- +-- home/user/.dir/subdir/file -- +-- home/user/.local/share/chezmoi/dot_dir/.keep -- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/unmanagedcmd.go new/chezmoi-2.48.0/internal/cmd/unmanagedcmd.go --- old/chezmoi-2.47.4/internal/cmd/unmanagedcmd.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/unmanagedcmd.go 2024-04-26 21:51:18.000000000 +0200 @@ -4,7 +4,6 @@ "fmt" "io/fs" "sort" - "strings" "github.com/spf13/cobra" @@ -14,6 +13,7 @@ type unmanagedCmdConfig struct { pathStyle chezmoi.PathStyle + tree bool } func (c *Config) newUnmanagedCmd() *cobra.Command { @@ -28,6 +28,7 @@ } unmanagedCmd.Flags().VarP(&c.unmanaged.pathStyle, "path-style", "p", "Path style") + unmanagedCmd.Flags().BoolVarP(&c.unmanaged.tree, "tree", "t", c.unmanaged.tree, "Print paths as a tree") return unmanagedCmd } @@ -93,16 +94,18 @@ } } - builder := strings.Builder{} - sortedRelPaths := chezmoi.RelPaths(unmanagedRelPaths.Elements()) - sort.Sort(sortedRelPaths) - for _, relPath := range sortedRelPaths { - switch c.unmanaged.pathStyle { - case chezmoi.PathStyleAbsolute: - fmt.Fprintln(&builder, c.DestDirAbsPath.Join(relPath)) - case chezmoi.PathStyleRelative: - fmt.Fprintln(&builder, relPath) + paths := make([]fmt.Stringer, 0, len(unmanagedRelPaths.Elements())) + for relPath := range unmanagedRelPaths { + var path fmt.Stringer + if c.unmanaged.pathStyle == chezmoi.PathStyleAbsolute { + path = c.DestDirAbsPath.Join(relPath) + } else { + path = relPath } + paths = append(paths, path) } - return c.writeOutputString(builder.String()) + + return c.writePaths(stringersToStrings(paths), writePathsOptions{ + tree: c.unmanaged.tree, + }) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/util.go new/chezmoi-2.48.0/internal/cmd/util.go --- old/chezmoi-2.47.4/internal/cmd/util.go 2024-04-12 13:51:15.000000000 +0200 +++ new/chezmoi-2.48.0/internal/cmd/util.go 2024-04-26 21:51:18.000000000 +0200 @@ -1,6 +1,7 @@ package cmd import ( + "fmt" "strings" "unicode" @@ -107,6 +108,15 @@ return singular + "s" } +// stringersToStrings converts a slice of fmt.Stringers to a list of strings. +func stringersToStrings[T fmt.Stringer](ss []T) []string { + result := make([]string, 0, len(ss)) + for _, s := range ss { + result = append(result, s.String()) + } + return result +} + // titleFirst returns s with its first rune converted to title case. func titleFirst(s string) string { if s == "" { @@ -130,7 +140,7 @@ return strings.Join(words, "") } -// upperSnakeCaseToCamelCaseKeys returns m with all keys converted from +// upperSnakeCaseToCamelCaseMap returns m with all keys converted from // UPPER_SNAKE_CASE to camelCase. func upperSnakeCaseToCamelCaseMap[V any](m map[string]V) map[string]V { result := make(map[string]V) ++++++ chezmoi.obsinfo ++++++ --- /var/tmp/diff_new_pack.gGnN0Q/_old 2024-05-01 14:57:12.027537165 +0200 +++ /var/tmp/diff_new_pack.gGnN0Q/_new 2024-05-01 14:57:12.031537311 +0200 @@ -1,5 +1,5 @@ name: chezmoi -version: 2.47.4 -mtime: 1712922675 -commit: d6ad485c86aa6501f5a7754ccba2a2b03d46c1a2 +version: 2.48.0 +mtime: 1714161078 +commit: c758a1c57fb6084631736a7dda5ac0aaeeffa946 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/chezmoi/vendor.tar.gz /work/SRC/openSUSE:Factory/.chezmoi.new.1880/vendor.tar.gz differ: char 5, line 1