#!/bin/sh gitpack_url="https://gitpack.htlc.io" bin_dir="$HOME/.local/bin" cmd_help() { echo "Usage: gitpack " echo "" echo "Commands:" echo " gitpack install [app] - Install an app" echo " gitpack remove [app] - Remove an app" echo " gitpack run [app] % - Update and run an app. Additional arguments are passed through to the app" echo " gitpack update - Update gitpack itself" echo "" } ensure_gitpack_installed() { # Ensure ~/.local/bin exists mkdir -p "$bin_dir" # Ensure ~/.local/bin is in PATH case ":$PATH:" in *":$bin_dir:"*) ;; *) echo "Warning: $bin_dir is not in your PATH." # Detect the appropriate dotfile for the user's shell shell_name="$(basename "$SHELL")" case "$shell_name" in zsh) dotfile="$HOME/.zshrc" ;; bash) dotfile="$HOME/.bashrc" ;; fish) dotfile="$HOME/.config/fish/config.fish" ;; ksh) dotfile="$HOME/.kshrc" ;; *) dotfile="" ;; esac if [ -n "$dotfile" ] && [ -e /dev/tty ]; then printf "Add %s to PATH in %s? [Y/n] " "$bin_dir" "$dotfile" read -r answer >"$dotfile" else echo "export PATH=\"$bin_dir:\$PATH\"" >>"$dotfile" fi echo "Added. Restart your shell or run: source $dotfile" ;; esac else echo "Could not detect your shell config file. Add $bin_dir to your PATH manually." fi ;; esac # Copy gitpack itself if not already installed if [ ! -f "$bin_dir/gitpack" ]; then curl -fsSL "$gitpack_url/gitpack" -o "$bin_dir/gitpack" chmod +x "$bin_dir/gitpack" fi } parse_yml_field() { field="$1" file="$2" grep "^${field}:" "$file" | sed "s/^${field}:[[:space:]]*//" | sed 's/[[:space:]]*#.*//' | tr -d "\"'" } cmd_install() { ensure_gitpack_installed git_url="$1" if [ -z "$git_url" ]; then echo "Usage: gitpack install " exit 1 fi tmp_dir="$(mktemp -d)" echo "Cloning $git_url..." if ! git clone "$git_url" "$tmp_dir"; then rm -rf "$tmp_dir" echo "Error: Failed to clone repository." exit 1 fi config_file="$tmp_dir/.gitpack.yml" if [ ! -f "$config_file" ]; then rm -rf "$tmp_dir" echo "Error: Not a valid gitpack package (missing .gitpack.yml)." exit 1 fi app_name="$(parse_yml_field name "$config_file")" entrypoint="$(parse_yml_field entrypoint "$config_file")" setup="$(parse_yml_field setup "$config_file")" if [ -z "$app_name" ]; then rm -rf "$tmp_dir" echo "Error: .gitpack.yml is missing required field: name" exit 1 fi if [ -z "$entrypoint" ]; then rm -rf "$tmp_dir" echo "Error: .gitpack.yml is missing required field: entrypoint" exit 1 fi install_dir="$HOME/.local/share/gitpack/$app_name" if [ -d "$install_dir" ]; then rm -rf "$tmp_dir" echo "Error: '$app_name' is already installed. Use 'gitpack remove $app_name' first." exit 1 fi mkdir -p "$(dirname "$install_dir")" mv "$tmp_dir" "$install_dir" # Write a launcher script that delegates to `gitpack run` launcher="$bin_dir/$app_name" printf '#!/bin/sh\nexec gitpack run %s "$@"\n' "$app_name" >"$launcher" chmod +x "$launcher" if [ -n "$setup" ]; then setup_path="$install_dir/$setup" if [ -f "$setup_path" ]; then echo "Running setup..." chmod +x "$setup_path" "$setup_path" else echo "Warning: setup script '$setup' not found in repository." fi fi echo "" echo "📦 $app_name installed successfully!" } cmd_remove() { app_name="$1" if [ -z "$app_name" ]; then echo "Usage: gitpack remove " exit 1 fi install_dir="$HOME/.local/share/gitpack/$app_name" if [ ! -d "$install_dir" ]; then echo "Error: '$app_name' is not installed." exit 1 fi rm -rf "$install_dir" rm -f "$bin_dir/$app_name" echo "$app_name removed." } cmd_run() { app_name="$1" shift if [ -z "$app_name" ]; then echo "Usage: gitpack run " exit 1 fi install_dir="$HOME/.local/share/gitpack/$app_name" if [ ! -d "$install_dir" ]; then echo "Error: '$app_name' is not installed." exit 1 fi config_file="$install_dir/.gitpack.yml" # Fetch remote and check if we're behind before attempting a merge git -C "$install_dir" fetch origin --quiet local_rev="$(git -C "$install_dir" rev-parse HEAD)" remote_rev="$(git -C "$install_dir" rev-parse @{u} 2>/dev/null)" if [ -n "$remote_rev" ] && [ "$local_rev" != "$remote_rev" ]; then echo "[📦 gitpack] Update for $app_name is available. Fetching..." echo "" if ! git -C "$install_dir" merge --ff-only --quiet; then echo "Warning: Could not fast-forward $app_name. Skipping update." fi setup="$(parse_yml_field setup "$config_file")" if [ -n "$setup" ]; then setup_path="$install_dir/$setup" if [ -f "$setup_path" ]; then chmod +x "$setup_path" "$setup_path" fi fi fi entrypoint="$(parse_yml_field entrypoint "$config_file")" if [ -z "$entrypoint" ]; then echo "Error: .gitpack.yml is missing required field: entrypoint" exit 1 fi entrypoint_path="$install_dir/$entrypoint" if [ ! -f "$entrypoint_path" ]; then echo "Error: entrypoint '$entrypoint' not found in repository." exit 1 fi chmod +x "$entrypoint_path" exec "$entrypoint_path" "$@" } cmd_update() { target="$bin_dir/gitpack" tmp="$(mktemp)" echo "Updating gitpack..." if curl -fsSL "$gitpack_url/gitpack" -o "$tmp"; then chmod +x "$tmp" mv "$tmp" "$target" echo "gitpack updated." else rm -f "$tmp" echo "Error: Failed to download update." exit 1 fi } case "$1" in help) cmd_help ;; install) cmd_install "$2" ;; remove) cmd_remove "$2" ;; run) shift; cmd_run "$@" ;; update) cmd_update ;; *) echo "Unknown command: $1" echo "Run gitpack help for usage instructions" exit 1 ;; esac