twpayne / chezmoi

Manage your dotfiles across multiple diverse machines, securely.
https://www.chezmoi.io/
MIT License
12.85k stars 477 forks source link

Also git-repo externals to add only a subdirectory of the repo #2678

Closed mew1033 closed 1 year ago

mew1033 commented 1 year ago

Is your feature request related to a problem? Please describe.

I see that git-repo externals were added in #1911, which is awesome. Thank you! What I'd like to see is a way to specify a specific folder from the git repo as the "root" to add to the target. As an example, I want to add this docker completion module: https://github.com/matt9ucci/DockerCompletion#other-methods. The module code itself is contained within a subdirectory of that repo (see the As a "well-formed" module section).

Describe the solution you'd like

It'd be great if chezmoi could pick a single folder from the repo of a git-repo external and discard the rest.

twpayne commented 1 year ago

This would be hard to implement, but there are two existing workarounds:

Firstly, you can use GitHub-generated archives with an include filter, instead of a git repo:

["path/where/PowerShell/installs/completions/DockerCompletion"]
    type = "archive"
    url = "https://github.com/matt9ucci/DockerCompletion/archive/refs/heads/master.zip"
    stripComponents = 2
    include = ["DockerCompletion-master/DockerCompletion/**"]
    refreshPeriod = "168h"

Secondly, you could write a script that uses git sparse-checkout.

fragolinux commented 1 year ago

Secondly, you could write a script that uses git sparse-checkout.

hi, how? I'm trying this, without success... all i want is just the skins and plugins folders, no other source files...

[".config/k9s/remote"]
    type = "git-repo"
    url = "https://github.com/derailed/k9s"
    exact = true
    include = ["plugins/*.yml", "skins/*.yml"]
    [".config/k9s/remote".clone]
        args = ["--depth", "1", "--filter=blob:none", "--sparse"]
    [".config/k9s/remote".filter]
        command = "git"
        args = ["sparse-checkout", "set", "plugins", "skins"]

this is what I'm manually doing right now, and works, but I'd like this integrates in my chezmoi setup:

#!/usr/bin/env bash

base="$HOME/.config/k9s"
custom="$base/custom"
remote="$base/remote"
backup="$base/backup"
mkdir -p $custom $remote $backup
DATA=$(date +%Y-%m-%d_%Hh%Mm)
git clone --depth 1 --filter=blob:none --sparse https://github.com/derailed/k9s $remote > /dev/null 2>&1
cd $remote
git sparse-checkout set plugins skins
[ -f $base/plugin.yml ] && mv $base/plugin.yml $backup/plugin-$DATA.yml
echo "plugin:" > $base/plugin.yml
for i in $(ls $remote/plugins/*.yml); do cat $i | grep -v "plugin:" | grep -v "plugin.yml" >> $base/plugin.yml ; done
for i in $(ls $custom/*.yml); do cat $i | grep -v "plugin:" | grep -v "plugin.yml" >> $base/plugin.yml ; done
cp -a $remote/skins $base
bradenhilton commented 1 year ago

Secondly, you could write a script that uses git sparse-checkout.

hi, how? I'm trying this, without success... all i want is just the skins and plugins folders, no other source files...

[".config/k9s/remote"]
    type = "git-repo"
    url = "https://github.com/derailed/k9s"
    exact = true
    include = ["plugins/*.yml", "skins/*.yml"]
    [".config/k9s/remote".clone]
        args = ["--depth", "1", "--filter=blob:none", "--sparse"]
    [".config/k9s/remote".filter]
        command = "git"
        args = ["sparse-checkout", "set", "plugins", "skins"]

@fragolinux that isn't a script.

fragolinux commented 1 year ago

I know, i tried to mix the "git-repo" type of pull with passing arguments to git via .filter, but don't know the correct way (if even possible) to do that... i ended up in this, which does what i want in the end... if any of you have better understanding of how to do via git (which for sure will be quicker, downloading only the needed parts and not a full zip file to just extract some files in it), you're welcome :)

[".config/k9s/remote"]
    type = "archive"
    url = "https://github.com/derailed/k9s/archive/refs/heads/master.zip"
    stripComponents = 1
    include = ["*/plugins/**", "*/skins/**"]
    exact = true
twpayne commented 1 year ago

I know, i tried to mix the "git-repo" type of pull with passing arguments to git via .filter, but don't know the correct way (if even possible) to do that...

With git-repo externals, you can use the clone.args and pull.args variables to set the arguments passed to git clone and git pull.

i ended up in this, which does what i want in the end...

I think this is the best way to do it.

if any of you have better understanding of how to do via git (which for sure will be quicker, downloading only the needed parts and not a full zip file to just extract some files in it), you're welcome :)

I doubt it would be quicker, as git pull requires significant negotiation between the client and the server to determine what data to transfer before transferring the data. Having the server create an archive of everything in master is probably much quicker.

twpayne commented 1 year ago

Hopefully this is now resolved. Please re-open if needed.