commit 69392aa7f1f02037e6fa4e27788ba9bf9b3983da Author: a Date: Wed May 1 18:12:04 2024 -0500 noot diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..157cb28 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +.PHONY: all + +SOURCES_LIBS:=$(shell find lib -type f) +SOURCES_SRC:=$(shell find src -type f ) + +all: repotool + +src/lib/repotool/stdlib.sh: $(SOURCES_LIBS) + bashly add --source . stdlib -f + +repotool: $(SOURCES_SRC) + bashly generate + + diff --git a/cli b/cli new file mode 100755 index 0000000..da0e510 --- /dev/null +++ b/cli @@ -0,0 +1,514 @@ +#!/usr/bin/env bash +# This script was generated by bashly 1.1.3 (https://bashly.dannyb.co) +# Modifying it manually is not recommended + +# :wrapper.bash3_bouncer +if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then + printf "bash version 4 or higher is required\n" >&2 + exit 1 +fi + +# :command.master_script + +# :command.version_command +version_command() { + echo "$version" +} + +# :command.usage +cli_usage() { + if [[ -n $long_usage ]]; then + printf "cli - Sample application\n" + echo + + else + printf "cli - Sample application\n" + echo + + fi + + printf "%s\n" "Usage:" + printf " cli COMMAND\n" + printf " cli [COMMAND] --help | -h\n" + printf " cli --version | -v\n" + echo + # :command.usage_commands + printf "%s\n" "Commands:" + printf " %s Download a file\n" "download" + printf " %s Upload a file\n" "upload " + echo + + # :command.long_usage + if [[ -n $long_usage ]]; then + printf "%s\n" "Options:" + + # :command.usage_fixed_flags + printf " %s\n" "--help, -h" + printf " Show this help\n" + echo + printf " %s\n" "--version, -v" + printf " Show version number\n" + echo + + # :command.usage_environment_variables + printf "%s\n" "Environment Variables:" + + # :environment_variable.usage + printf " %s\n" "API_KEY" + printf " Set your API key\n" + echo + + fi +} + +# :command.usage +cli_download_usage() { + if [[ -n $long_usage ]]; then + printf "cli download - Download a file\n" + echo + + else + printf "cli download - Download a file\n" + echo + + fi + + printf "Alias: d\n" + echo + + printf "%s\n" "Usage:" + printf " cli download SOURCE [TARGET] [OPTIONS]\n" + printf " cli download --help | -h\n" + echo + + # :command.long_usage + if [[ -n $long_usage ]]; then + printf "%s\n" "Options:" + + # :command.usage_flags + # :flag.usage + printf " %s\n" "--force, -f" + printf " Overwrite existing files\n" + echo + + # :command.usage_fixed_flags + printf " %s\n" "--help, -h" + printf " Show this help\n" + echo + + # :command.usage_args + printf "%s\n" "Arguments:" + + # :argument.usage + printf " %s\n" "SOURCE" + printf " URL to download from\n" + echo + + # :argument.usage + printf " %s\n" "TARGET" + printf " Target filename (default: same as source)\n" + echo + + # :command.usage_environment_variables + printf "%s\n" "Environment Variables:" + + # :environment_variable.usage + printf " %s\n" "DEFAULT_TARGET_LOCATION" + printf " Set the default location to download to\n" + echo + + # :command.usage_examples + printf "%s\n" "Examples:" + printf " cli download example.com\n" + printf " cli download example.com ./output -f\n" + echo + + fi +} + +# :command.usage +cli_upload_usage() { + if [[ -n $long_usage ]]; then + printf "cli upload - Upload a file\n" + echo + + else + printf "cli upload - Upload a file\n" + echo + + fi + + printf "Alias: u\n" + echo + + printf "%s\n" "Usage:" + printf " cli upload SOURCE [OPTIONS]\n" + printf " cli upload --help | -h\n" + echo + + # :command.long_usage + if [[ -n $long_usage ]]; then + printf "%s\n" "Options:" + + # :command.usage_flags + # :flag.usage + printf " %s\n" "--user, -u USER (required)" + printf " Username to use for logging in\n" + echo + + # :flag.usage + printf " %s\n" "--password, -p PASSWORD" + printf " Password to use for logging in\n" + echo + + # :command.usage_fixed_flags + printf " %s\n" "--help, -h" + printf " Show this help\n" + echo + + # :command.usage_args + printf "%s\n" "Arguments:" + + # :argument.usage + printf " %s\n" "SOURCE" + printf " File to upload\n" + echo + + fi +} + +# :command.normalize_input +normalize_input() { + local arg flags + + while [[ $# -gt 0 ]]; do + arg="$1" + if [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then + input+=("${BASH_REMATCH[1]}") + input+=("${BASH_REMATCH[2]}") + elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then + input+=("${BASH_REMATCH[1]}") + input+=("${BASH_REMATCH[2]}") + elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then + flags="${BASH_REMATCH[1]}" + for ((i = 0; i < ${#flags}; i++)); do + input+=("-${flags:i:1}") + done + else + input+=("$arg") + fi + + shift + done +} +# :command.inspect_args +inspect_args() { + if ((${#args[@]})); then + readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort) + echo args: + for k in "${sorted_keys[@]}"; do echo "- \${args[$k]} = ${args[$k]}"; done + else + echo args: none + fi + + if ((${#other_args[@]})); then + echo + echo other_args: + echo "- \${other_args[*]} = ${other_args[*]}" + for i in "${!other_args[@]}"; do + echo "- \${other_args[$i]} = ${other_args[$i]}" + done + fi + + if ((${#deps[@]})); then + readarray -t sorted_keys < <(printf '%s\n' "${!deps[@]}" | sort) + echo + echo deps: + for k in "${sorted_keys[@]}"; do echo "- \${deps[$k]} = ${deps[$k]}"; done + fi + +} + +# :command.command_functions +# :command.function +cli_download_command() { + # src/download_command.sh + echo "# this file is located in 'src/download_command.sh'" + echo "# code for 'cli download' goes here" + echo "# you can edit it freely and regenerate (it will not be overwritten)" + inspect_args + +} + +# :command.function +cli_upload_command() { + # src/upload_command.sh + echo "# this file is located in 'src/upload_command.sh'" + echo "# code for 'cli upload' goes here" + echo "# you can edit it freely and regenerate (it will not be overwritten)" + inspect_args + +} + +# :command.parse_requirements +parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + case "${1:-}" in + --version | -v) + version_command + exit + ;; + + --help | -h) + long_usage=yes + cli_usage + exit + ;; + + *) + break + ;; + + esac + done + + # :command.command_filter + action=${1:-} + + case $action in + -*) ;; + + download | d) + action="download" + shift + cli_download_parse_requirements "$@" + shift $# + ;; + + upload | u) + action="upload" + shift + cli_upload_parse_requirements "$@" + shift $# + ;; + + # :command.command_fallback + "") + cli_usage >&2 + exit 1 + ;; + + *) + printf "invalid command: %s\n" "$action" >&2 + exit 1 + ;; + + esac + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + + ;; + + esac + done + +} + +# :command.parse_requirements +cli_download_parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + case "${1:-}" in + --help | -h) + long_usage=yes + cli_download_usage + exit + ;; + + *) + break + ;; + + esac + done + + # :command.command_filter + action="download" + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + # :flag.case + --force | -f) + + # :flag.case_no_arg + args['--force']=1 + shift + ;; + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + if [[ -z ${args['source']+x} ]]; then + + args['source']=$1 + shift + elif [[ -z ${args['target']+x} ]]; then + + args['target']=$1 + shift + else + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + fi + + ;; + + esac + done + + # :command.required_args_filter + if [[ -z ${args['source']+x} ]]; then + printf "missing required argument: SOURCE\nusage: cli download SOURCE [TARGET] [OPTIONS]\n" >&2 + exit 1 + fi + +} + +# :command.parse_requirements +cli_upload_parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + case "${1:-}" in + --help | -h) + long_usage=yes + cli_upload_usage + exit + ;; + + *) + break + ;; + + esac + done + + # :command.command_filter + action="upload" + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + # :flag.case + --user | -u) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + + args['--user']="$2" + shift + shift + else + printf "%s\n" "--user requires an argument: --user, -u USER" >&2 + exit 1 + fi + ;; + + # :flag.case + --password | -p) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + + args['--password']="$2" + shift + shift + else + printf "%s\n" "--password requires an argument: --password, -p PASSWORD" >&2 + exit 1 + fi + ;; + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + if [[ -z ${args['source']+x} ]]; then + + args['source']=$1 + shift + else + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + fi + + ;; + + esac + done + + # :command.required_args_filter + if [[ -z ${args['source']+x} ]]; then + printf "missing required argument: SOURCE\nusage: cli upload SOURCE [OPTIONS]\n" >&2 + exit 1 + fi + + # :command.required_flags_filter + if [[ -z ${args['--user']+x} ]]; then + printf "missing required flag: --user, -u USER\n" >&2 + exit 1 + fi + +} + +# :command.initialize +initialize() { + version="0.1.0" + long_usage='' + set -e + +} + +# :command.run +run() { + declare -A args=() + declare -A deps=() + declare -a other_args=() + declare -a input=() + normalize_input "$@" + parse_requirements "${input[@]}" + + case "$action" in + "download") cli_download_command ;; + "upload") cli_upload_command ;; + esac +} + +initialize +run "$@" diff --git a/lib/stdlib.sh b/lib/stdlib.sh new file mode 100755 index 0000000..84f412b --- /dev/null +++ b/lib/stdlib.sh @@ -0,0 +1,38 @@ + + +# ((git|ssh|http(s)?)?|(git@[\w\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)?(/)? +valid_url() +{ + # matches https:/// + if [[ "$1" =~ ^https?://.*\..*/.*$ ]]; then + echo '1' + return 0 + fi + # matches @: + if [[ "$1" =~ ^(.*?)(:|/)(.+)(\/.+)*$ ]]; then + echo '2' + return 0 + fi + echo '-1' + return 0 +} + +lcat() +{ + if [[ -z "$DEBUG_LOG" || "$DEBUG_LOG" == 0 ]]; then + return 0 + fi + cat $@ >&2 +} + +lecho() +{ + if [[ -z "$DEBUG_LOG" || "$DEBUG_LOG" == 0 ]]; then + return 0 + fi + + echo $@ >&2 +} + + + diff --git a/libraries.yml b/libraries.yml new file mode 100644 index 0000000..8408d5c --- /dev/null +++ b/libraries.yml @@ -0,0 +1,5 @@ +stdlib: + help: stdlib for repotool + files: + - source: "lib/stdlib.sh" + target: "%{user_lib_dir}/repotool/stdlib.%{user_ext}" diff --git a/repotool b/repotool new file mode 100755 index 0000000..659b559 --- /dev/null +++ b/repotool @@ -0,0 +1,603 @@ +#!/usr/bin/env bash +# This script was generated by bashly 1.1.10 (https://bashly.dannyb.co) +# Modifying it manually is not recommended + +# :wrapper.bash3_bouncer +if [[ "${BASH_VERSINFO:-0}" -lt 4 ]]; then + printf "bash version 4 or higher is required\n" >&2 + exit 1 +fi + +# :command.master_script + +# :command.version_command +version_command() { + echo "$version" +} + +# :command.usage +repotool_usage() { + if [[ -n $long_usage ]]; then + printf "repotool - repo tool\n" + echo + + else + printf "repotool - repo tool\n" + echo + + fi + + printf "%s\n" "Usage:" + printf " repotool COMMAND\n" + printf " repotool [COMMAND] --help | -h\n" + printf " repotool --version | -v\n" + echo + # :command.usage_commands + printf "%s\n" "Commands:" + printf " %s gets repo if not found\n" "get" + echo + + # :command.long_usage + if [[ -n $long_usage ]]; then + printf "%s\n" "Options:" + + # :command.usage_fixed_flags + printf " %s\n" "--help, -h" + printf " Show this help\n" + echo + printf " %s\n" "--version, -v" + printf " Show version number\n" + echo + + # :command.usage_environment_variables + printf "%s\n" "Environment Variables:" + + # :environment_variable.usage + printf " %s\n" "REPOS_PATH" + printf " default path to clone to\n" + printf " Default: $HOME/repo\n" + echo + + # :environment_variable.usage + printf " %s\n" "DEBUG_LOG" + printf " set to 1 to enable debug logg\n" + printf " Default: 0\n" + echo + + fi +} + +# :command.usage +repotool_get_usage() { + if [[ -n $long_usage ]]; then + printf "repotool get - gets repo if not found\n" + echo + + else + printf "repotool get - gets repo if not found\n" + echo + + fi + + printf "Alias: g\n" + echo + + printf "%s\n" "Usage:" + printf " repotool get REPO [OPTIONS]\n" + printf " repotool get --help | -h\n" + echo + + # :command.long_usage + if [[ -n $long_usage ]]; then + printf "%s\n" "Options:" + + # :command.usage_flags + # :flag.usage + printf " %s\n" "--ssh-user SSH_USER" + printf " ssh user to clone with.\n" + printf " Default: git\n" + echo + + # :flag.usage + printf " %s\n" "--http-user HTTP_USER" + printf " http user to clone with.\n" + printf " Default: \n" + echo + + # :flag.usage + printf " %s\n" "--http-pass HTTP_PASS" + printf " http pass to clone with.\n" + printf " Default: \n" + echo + + # :flag.usage + printf " %s\n" "--method, -m METHOD" + printf " the method to clone the repo with\n" + printf " Allowed: ssh, https, http\n" + printf " Default: ssh\n" + echo + + # :command.usage_fixed_flags + printf " %s\n" "--help, -h" + printf " Show this help\n" + echo + + # :command.usage_args + printf "%s\n" "Arguments:" + + # :argument.usage + printf " %s\n" "REPO" + printf " URL to repo\n" + echo + + # :command.usage_examples + printf "%s\n" "Examples:" + printf " repo get tuxpa.in/a/repotool\n" + echo + + fi +} + +# :command.normalize_input +# :command.normalize_input_function +normalize_input() { + local arg flags passthru + passthru=false + + while [[ $# -gt 0 ]]; do + arg="$1" + if [[ $passthru == true ]]; then + input+=("$arg") + elif [[ $arg =~ ^(--[a-zA-Z0-9_\-]+)=(.+)$ ]]; then + input+=("${BASH_REMATCH[1]}") + input+=("${BASH_REMATCH[2]}") + elif [[ $arg =~ ^(-[a-zA-Z0-9])=(.+)$ ]]; then + input+=("${BASH_REMATCH[1]}") + input+=("${BASH_REMATCH[2]}") + elif [[ $arg =~ ^-([a-zA-Z0-9][a-zA-Z0-9]+)$ ]]; then + flags="${BASH_REMATCH[1]}" + for ((i = 0; i < ${#flags}; i++)); do + input+=("-${flags:i:1}") + done + elif [[ "$arg" == "--" ]]; then + passthru=true + input+=("$arg") + else + input+=("$arg") + fi + + shift + done +} + +# :command.inspect_args +inspect_args() { + if ((${#args[@]})); then + readarray -t sorted_keys < <(printf '%s\n' "${!args[@]}" | sort) + echo args: + for k in "${sorted_keys[@]}"; do + echo "- \${args[$k]} = ${args[$k]}" + done + else + echo args: none + fi + + if ((${#other_args[@]})); then + echo + echo other_args: + echo "- \${other_args[*]} = ${other_args[*]}" + for i in "${!other_args[@]}"; do + echo "- \${other_args[$i]} = ${other_args[$i]}" + done + fi + + if ((${#deps[@]})); then + readarray -t sorted_keys < <(printf '%s\n' "${!deps[@]}" | sort) + echo + echo deps: + for k in "${sorted_keys[@]}"; do + echo "- \${deps[$k]} = ${deps[$k]}" + done + fi + + if ((${#env_var_names[@]})); then + readarray -t sorted_names < <(printf '%s\n' "${env_var_names[@]}" | sort) + echo + echo "environment variables:" + for k in "${sorted_names[@]}"; do + echo "- \$$k = ${!k:-}" + done + fi +} + +# :command.user_lib +# src/lib/repotool/stdlib.sh + +# ((git|ssh|http(s)?)?|(git@[\w\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)?(/)? +valid_url() +{ + # matches https:/// + if [[ "$1" =~ ^https?://.*\..*/.*$ ]]; then + echo '1' + return 0 + fi + # matches @: + if [[ "$1" =~ ^(.*?)(:|/)(.+)(\/.+)*$ ]]; then + echo '2' + return 0 + fi + echo '-1' + return 0 +} + +lcat() +{ + if [[ -z "$DEBUG_LOG" || "$DEBUG_LOG" == 0 ]]; then + return 0 + fi + cat $@ >&2 +} + +lecho() +{ + if [[ -z "$DEBUG_LOG" || "$DEBUG_LOG" == 0 ]]; then + return 0 + fi + + echo $@ >&2 +} + +# :command.command_functions +# :command.function +repotool_get_command() { + # src/get_command.sh + #inspect_args>&2 + local resp + + resp=$(valid_url ${args[repo]}) + if [[ $resp == -1 ]]; then + echo "${args[repo]} is not a valid repo" + exit 1 + fi + + local regex="${deps[perl]} -n -l -e" + + local ssh_user; + # the ssh user to clone with + + local http_user; + local http_pass; + + local domain + local path + #now extract the args we need + # this is where we use perl + if [[ $resp == 1 ]]; then + # TODO: properly extract user and password, if exists. + output=($(echo ${args[repo]} | ${regex} '/^https?:\/\/(?:.*?:)?(.*\..*?)\/(.*?)(\.git)?$/ && print "$1 $2" ' -)) + domain=${output[0]} + path=${output[1]} + fi + + if [[ $resp == 2 ]]; then + # TODO: properly extract ssh user, if exists. + output=($(echo ${args[repo]} | ${regex} '/^(?:.*?@)?(.*\..*?)(?::|\/)(.*?)(\.git)?$/ && print "$1 $2" ' -)) + domain=${output[0]} + path=${output[1]} + fi + + if [[ ! -z "${args[--ssh-user]}" && -z "$ssh_user" ]]; then + ssh_user=${args[--ssh-user]} + fi + + if [[ ! -z "${args[--http-user]}" && -z "$http_user" ]]; then + http_user=${args[--http-user]} + fi + + if [[ ! -z "${args[--http-pass]}" && -z "$http_pass" ]]; then + http_pass=${args[--http-pass]} + fi + + if [[ -z "$method" ]]; then + method=${args[--method]} + fi + + lcat << EOF +found valid repo target + +domain: $domain +path: $path + +ssh_user: $ssh_user +method: $method + +http_user: $http_user +http_pass: $http_pass +EOF + + local target_dir="$REPOS_PATH/$domain/$path" + #mkdir for our target directory + + if [[ ! -d $target_dir ]]; then + mkdir -p $target_dir + fi + + cd $target_dir + + local repo_url="" + + case $method in + ssh) + repo_url="$ssh_user@$domain:$path" + ;; + https | http) + # TODO: support http_user and http_pass + repo_url="$method://$domain/$path.git" + ;; + *) + >&2 echo "unrecognized clone method $method" + exit 1 + esac + + # we check if we have cloned the repo via the if the .git folder exists + if [[ ! -d .git ]]; then + # check if the remote actually exists + git ls-remote $repo_url > /dev/null && RC=$? || RC=$? + if [[ $RC == 0 ]]; then + git clone $repo_url $target_dir >&2 + else + >&2 echo "Could not find repo: $repo_url" + fi + fi + + echo dir=$target_dir domain=$domain path=$path repo_url=$repo_url + +} + +# :command.parse_requirements +parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + case "${1:-}" in + --version | -v) + version_command + exit + ;; + + --help | -h) + long_usage=yes + repotool_usage + exit + ;; + + *) + break + ;; + + esac + done + + # :command.environment_variables_filter + # :command.environment_variables_default + export REPOS_PATH="${REPOS_PATH:-$HOME/repo}" + export DEBUG_LOG="${DEBUG_LOG:-0}" + + env_var_names+=("REPOS_PATH") + env_var_names+=("DEBUG_LOG") + + # :command.command_filter + action=${1:-} + + case $action in + -*) ;; + + get | g) + action="get" + shift + repotool_get_parse_requirements "$@" + shift $# + ;; + + # :command.command_fallback + "") + repotool_usage >&2 + exit 1 + ;; + + *) + printf "invalid command: %s\n" "$action" >&2 + exit 1 + ;; + + esac + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + + ;; + + esac + done + +} + +# :command.parse_requirements +repotool_get_parse_requirements() { + # :command.fixed_flags_filter + while [[ $# -gt 0 ]]; do + case "${1:-}" in + --help | -h) + long_usage=yes + repotool_get_usage + exit + ;; + + *) + break + ;; + + esac + done + + # :command.dependencies_filter + if command -v git >/dev/null 2>&1; then + deps['git']="$(command -v git | head -n1)" + else + printf "missing dependency: git\n" >&2 + exit 1 + fi + + if command -v perl >/dev/null 2>&1; then + deps['perl']="$(command -v perl | head -n1)" + else + printf "missing dependency: perl\n" >&2 + exit 1 + fi + + # :command.command_filter + action="get" + + # :command.parse_requirements_while + while [[ $# -gt 0 ]]; do + key="$1" + case "$key" in + # :flag.case + --ssh-user) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--ssh-user']="$2" + shift + shift + else + printf "%s\n" "--ssh-user requires an argument: --ssh-user SSH_USER" >&2 + exit 1 + fi + ;; + + # :flag.case + --http-user) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--http-user']="$2" + shift + shift + else + printf "%s\n" "--http-user requires an argument: --http-user HTTP_USER" >&2 + exit 1 + fi + ;; + + # :flag.case + --http-pass) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--http-pass']="$2" + shift + shift + else + printf "%s\n" "--http-pass requires an argument: --http-pass HTTP_PASS" >&2 + exit 1 + fi + ;; + + # :flag.case + --method | -m) + + # :flag.case_arg + if [[ -n ${2+x} ]]; then + args['--method']="$2" + shift + shift + else + printf "%s\n" "--method requires an argument: --method, -m METHOD" >&2 + exit 1 + fi + ;; + + -?*) + printf "invalid option: %s\n" "$key" >&2 + exit 1 + ;; + + *) + # :command.parse_requirements_case + # :command.parse_requirements_case_simple + # :argument.case + if [[ -z ${args['repo']+x} ]]; then + args['repo']=$1 + shift + else + printf "invalid argument: %s\n" "$key" >&2 + exit 1 + fi + + ;; + + esac + done + + # :command.required_args_filter + if [[ -z ${args['repo']+x} ]]; then + printf "missing required argument: REPO\nusage: repotool get REPO [OPTIONS]\n" >&2 + exit 1 + fi + + # :command.default_assignments + [[ -n ${args['--ssh-user']:-} ]] || args['--ssh-user']="git" + [[ -n ${args['--http-user']:-} ]] || args['--http-user']="" + [[ -n ${args['--http-pass']:-} ]] || args['--http-pass']="" + [[ -n ${args['--method']:-} ]] || args['--method']="ssh" + + # :command.whitelist_filter + if [[ ${args['--method']:-} ]] && [[ ! ${args['--method']:-} =~ ^(ssh|https|http)$ ]]; then + printf "%s\n" "--method must be one of: ssh, https, http" >&2 + exit 1 + fi + +} + +# :command.initialize +initialize() { + version="0.1.0" + long_usage='' + set -e + + # :command.environment_variables_default + export REPOS_PATH="${REPOS_PATH:-$HOME/repo}" + export DEBUG_LOG="${DEBUG_LOG:-0}" + +} + +# :command.run +run() { + declare -A args=() + declare -A deps=() + declare -a other_args=() + declare -a env_var_names=() + declare -a input=() + normalize_input "$@" + parse_requirements "${input[@]}" + + case "$action" in + "get") repotool_get_command ;; + esac +} + +initialize +run "$@" diff --git a/settings.yml b/settings.yml new file mode 100644 index 0000000..dfbfab3 --- /dev/null +++ b/settings.yml @@ -0,0 +1,63 @@ +# All settings are optional (with their default values provided below), and +# can also be set with an environment variable with the same name, capitalized +# and prefixed by `BASHLY_` - for example: BASHLY_SOURCE_DIR +# +# When setting environment variables, you can use: +# - "0", "false" or "no" to represent false +# - "1", "true" or "yes" to represent true +# +# If you wish to change the path to this file, set the environment variable +# BASHLY_SETTINGS_PATH. + +# The path containing the bashly source files +source_dir: src + +# The path to bashly.yml +config_path: "%{source_dir}/bashly.yml" + +# The path to use for creating the bash script +target_dir: . + +# The path to use for common library files, relative to source_dir +lib_dir: lib + +# The path to use for command files, relative to source_dir +# When set to nil (~), command files will be placed directly under source_dir +# When set to any other string, command files will be placed under this +# directory, and each command will get its own subdirectory +commands_dir: ~ + +# Configure the bash options that will be added to the initialize function: +# strict: true Bash strict mode (set -euo pipefail) +# strict: false Only exit on errors (set -e) +# strict: '' Do not add any 'set' directive +# strict: Add any other custom 'set' directive +strict: false + +# When true, the generated script will use tab indentation instead of spaces +# (every 2 leading spaces will be converted to a tab character) +tab_indent: false + +# When true, the generated script will consider any argument in the form of +# `-abc` as if it is `-a -b -c`. +compact_short_flags: true + +# Set to 'production' or 'development': +# env: production Generate a smaller script, without file markers +# env: development Generate with file markers +env: development + +# The extension to use when reading/writing partial script snippets +partials_extension: sh + +# Display various usage elements in color by providing the name of the color +# function. The value for each property is a name of a function that is +# available in your script, for example: `green` or `bold`. +# You can run `bashly add colors` to add a standard colors library. +# This option cannot be set via environment variables. +usage_colors: + caption: ~ + command: ~ + arg: ~ + flag: ~ + environment_variable: ~ diff --git a/src/bashly.yml b/src/bashly.yml new file mode 100644 index 0000000..cb4be57 --- /dev/null +++ b/src/bashly.yml @@ -0,0 +1,46 @@ +name: repotool +help: repo tool +version: 0.1.0 + +environment_variables: +- name: REPOS_PATH + default: $HOME/repo + help: default path to clone to +- name: DEBUG_LOG + default: "0" + help: set to 1 to enable debug logg + +commands: +- name: get + alias: g + help: gets repo if not found + dependencies: + git: + command: ["git"] + perl: + command: ["perl"] + args: + - name: repo + required: true + help: URL to repo + flags: + - long: --ssh-user + help: ssh user to clone with. + arg: "ssh_user" + default: "git" + - long: --http-user + help: http user to clone with. + arg: "http_user" + default: "" + - long: --http-pass + help: http pass to clone with. + arg: "http_pass" + default: "" + - long: --method + short: -m + help: the method to clone the repo with + arg: "method" + default: "ssh" + allowed: ["ssh", "https", "http"] + examples: + - repo get tuxpa.in/a/repotool diff --git a/src/get_command.sh b/src/get_command.sh new file mode 100755 index 0000000..9a93bab --- /dev/null +++ b/src/get_command.sh @@ -0,0 +1,105 @@ +#inspect_args>&2 +local resp + +resp=$(valid_url ${args[repo]}) +if [[ $resp == -1 ]]; then + echo "${args[repo]} is not a valid repo" + exit 1 +fi + +local regex="${deps[perl]} -n -l -e" + + +local ssh_user; +# the ssh user to clone with + +local http_user; +local http_pass; + +local domain +local path +#now extract the args we need +# this is where we use perl +if [[ $resp == 1 ]]; then + # TODO: properly extract user and password, if exists. + output=($(echo ${args[repo]} | ${regex} '/^https?:\/\/(?:.*?:)?(.*\..*?)\/(.*?)(\.git)?$/ && print "$1 $2" ' -)) + domain=${output[0]} + path=${output[1]} +fi + +if [[ $resp == 2 ]]; then + # TODO: properly extract ssh user, if exists. + output=($(echo ${args[repo]} | ${regex} '/^(?:.*?@)?(.*\..*?)(?::|\/)(.*?)(\.git)?$/ && print "$1 $2" ' -)) + domain=${output[0]} + path=${output[1]} +fi + +if [[ ! -z "${args[--ssh-user]}" && -z "$ssh_user" ]]; then + ssh_user=${args[--ssh-user]} +fi + +if [[ ! -z "${args[--http-user]}" && -z "$http_user" ]]; then + http_user=${args[--http-user]} +fi + +if [[ ! -z "${args[--http-pass]}" && -z "$http_pass" ]]; then + http_pass=${args[--http-pass]} +fi + + +if [[ -z "$method" ]]; then + method=${args[--method]} +fi + +lcat << EOF +found valid repo target + +domain: $domain +path: $path + +ssh_user: $ssh_user +method: $method + +http_user: $http_user +http_pass: $http_pass +EOF + + +local target_dir="$REPOS_PATH/$domain/$path" +#mkdir for our target directory + +if [[ ! -d $target_dir ]]; then + mkdir -p $target_dir +fi + +cd $target_dir + +local repo_url="" + +case $method in + ssh) + repo_url="$ssh_user@$domain:$path" + ;; + https | http) + # TODO: support http_user and http_pass + repo_url="$method://$domain/$path.git" + ;; + *) + >&2 echo "unrecognized clone method $method" + exit 1 +esac + + + +# we check if we have cloned the repo via the if the .git folder exists +if [[ ! -d .git ]]; then + # check if the remote actually exists + git ls-remote $repo_url > /dev/null && RC=$? || RC=$? + if [[ $RC == 0 ]]; then + git clone $repo_url $target_dir >&2 + else + >&2 echo "Could not find repo: $repo_url" + fi +fi + +echo dir=$target_dir domain=$domain path=$path repo_url=$repo_url diff --git a/src/lib/repotool/stdlib.sh b/src/lib/repotool/stdlib.sh new file mode 100644 index 0000000..84f412b --- /dev/null +++ b/src/lib/repotool/stdlib.sh @@ -0,0 +1,38 @@ + + +# ((git|ssh|http(s)?)?|(git@[\w\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)?(/)? +valid_url() +{ + # matches https:/// + if [[ "$1" =~ ^https?://.*\..*/.*$ ]]; then + echo '1' + return 0 + fi + # matches @: + if [[ "$1" =~ ^(.*?)(:|/)(.+)(\/.+)*$ ]]; then + echo '2' + return 0 + fi + echo '-1' + return 0 +} + +lcat() +{ + if [[ -z "$DEBUG_LOG" || "$DEBUG_LOG" == 0 ]]; then + return 0 + fi + cat $@ >&2 +} + +lecho() +{ + if [[ -z "$DEBUG_LOG" || "$DEBUG_LOG" == 0 ]]; then + return 0 + fi + + echo $@ >&2 +} + + +