git-sparse Added first raku script. git-sparse creates a sparse checkout of a git repository, creating a new repository if needed.
2 files changed, 180 insertions(+), 0 deletions(-) M core/README.md A core/git-sparse.raku
M core/README.md => core/README.md +1 -0
@@ 12,6 12,7 @@ Executable |Description | ctdir |Count entries in a target directory(ies) debom |Remove BOM from a target file |`bash` gitstat |Fetch updates on git repositories |`bash` git-sparse |Create a sparse checkout repository |`raku` enumerate |Rename files in current directory into sequential numbers |`bash` mkbak |Create a backup of a target file |`bash` rand |Get a random number within an inclusive range |`bash`, `shuf`
A core/git-sparse.raku => core/git-sparse.raku +179 -0
@@ 0,0 1,179 @@ #!/usr/bin/env raku #TODO: add standard program header #TODO: add --help message sub check-environment() { my $proc = shell <git --version>, :out, :err; if $proc.exitcode != 0 { #say $proc.err.slurp(:close); #TODO: gate this behind a --verbose feature say "$*PROGRAM-NAME: git is not installed"; exit 1; } } class Arguments { has Str @.options; has Str @.positionals; #TODO: add .interactive-mode } sub parse() { if any(@*ARGS) eq '--' { my $sep = @*ARGS.first("--", :k); return Arguments.new(options => |@*ARGS[0..^$sep], positionals => |@*ARGS[$sep^..*]); } else { return Arguments.new(options => @*ARGS, positionals => ()); } #TODO: set .interactive-mode here } sub check-arguments($args) { if $args.positionals.elems == 0 { say "$*PROGRAM-NAME: no targets specified"; exit 1; } } sub git-rev-parse() { my $root; my $proc = run <git rev-parse --show-toplevel>, :out, :err; if $proc.exitcode != 0 { #say $proc.err.slurp(:close); #TODO: gate this behind a --verbose feature } else { $root = $proc.out.slurp(:close).trim.IO; } return $root; } sub interactive-clone() { my $root = $*CWD; my $resp = prompt "Create a new repository in $root? [y/N] "; given $resp { when "y"|"Y" { } when "n"|"N" { say "Quiting..."; exit 1 } default { say "Invalid response. Quiting..."; exit 1 } } my $uri = prompt "Repository to clone: "; without $uri { say "$*PROGRAM-NAME: no repository to clone"; exit 1; } git-clone $uri; return $root; } sub git-clone($uri) { my @cmd = $uri, "."; @cmd.prepend(<git clone --filter=blob:none --no-checkout -->); # Purposefully not capturing STDOUT my $proc = run |@cmd, :err; if $proc.exitcode != 0 { say $proc.err.slurp(:close); #TODO: parse error message and print a cleaner version exit 1; } } #TODO: this should not be necessary long term, but no idea how to tell when sub git-sparse-checkout-legacy() { my $proc = run <git sparse-checkout init --cone --sparse-index>, :out, :err; if $proc.exitcode != 0 { #say $proc.err.slurp(:close); #TODO: gate this behind a --verbose feature say "$*PROGRAM-NAME: failed to set sparse checkouts"; exit 1; } } sub git-sparse-checkout($args) { git-sparse-checkout-legacy; my @cmd = $args.positionals; @cmd.prepend(<git sparse-checkout set -->); #@cmd.prepend(<git sparse-checkout set --cone --sparse-index -->); #TODO: swap these when legacy code not needed my $proc = run @cmd, :err; if $proc.exitcode != 0 { #say $proc.err.slurp(:close); #TODO: gate this behind a --verbose feature say "$*PROGRAM-NAME: failed to set sparse checkouts"; exit 1; } } sub git-remote-show-origin() { my $proc = run <git remote show origin>, :out, :err; if $proc.exitcode != 0 { #say $proc.err.slurp(:close); #TODO: gate this behind a --verbose feature say "$*PROGRAM-NAME: failed to set identify default branch"; exit 1; } my @lines = $proc.out.slurp(:close).lines; my @branch-line = @lines.grep(*.contains: "HEAD branch"); if @branch-line.elems != 1 { say "$*PROGRAM-NAME: failed to set identify default branch"; exit 1; } my $branch = @branch-line[0].trim; $branch ~~ s/.*\:\s*//; return $branch; } sub git-checkout($branch) { my @cmd = $branch; @cmd.prepend(<git checkout>); my $proc = run |@cmd, :out, :err; if $proc.exitcode != 0 { #say $proc.err.slurp(:close); #TODO: gate this behind a --verbose feature say "$*PROGRAM-NAME: failed to checkout branch $branch"; exit 1; } } # setup check-environment; my $args = parse; check-arguments $args; my $init-mode = any($args.options) eq '-i' | '--init' | '--interactive'; # this is a junction; collapse with .so method #TODO: move this into Arguments class as .interactive-mode # git repository my $root = git-rev-parse; with $root { if $init-mode.so { say "$*PROGRAM-NAME: not re-initializing the repository in $root" } } else { unless $init-mode.so { say "$*PROGRAM-NAME: not in a git repository"; exit 1; }; $root = interactive-clone; }; # sparse checkout git-sparse-checkout($args); git-checkout(git-remote-show-origin);