288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env bash
 | 
						|
# ---
 | 
						|
# This file is automatically generated from gitea.md - DO NOT EDIT
 | 
						|
# ---
 | 
						|
 | 
						|
# MIT License
 | 
						|
#
 | 
						|
# Copyright (c) 2017 PJ Eby
 | 
						|
#
 | 
						|
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
 | 
						|
# files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
 | 
						|
# modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
 | 
						|
# is furnished to do so, subject to the following conditions:
 | 
						|
#
 | 
						|
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 | 
						|
#
 | 
						|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 | 
						|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 | 
						|
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
						|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
 | 
						|
#!/usr/bin/env bash
 | 
						|
 | 
						|
realpath.location(){ realpath.follow "$1"; realpath.absolute "$REPLY" ".."; }
 | 
						|
realpath.resolved(){ realpath.follow "$1"; realpath.absolute "$REPLY"; }
 | 
						|
realpath.dirname() { if [[ $1 =~ /+[^/]+/*$ ]]; then REPLY="${1%${BASH_REMATCH[0]}}"; REPLY=${REPLY:-/}; else REPLY=.; fi }
 | 
						|
realpath.basename(){ if [[ $1 =~ /*([^/]+)/*$ ]]; then REPLY="${BASH_REMATCH[1]}"; else REPLY=/; fi }
 | 
						|
 | 
						|
realpath.follow() {
 | 
						|
	local target
 | 
						|
	while [[ -L "$1" ]] && target=$(readlink -- "$1"); do
 | 
						|
		realpath.dirname "$1"
 | 
						|
		# Resolve relative to symlink's directory
 | 
						|
		[[ $REPLY != . && $target != /* ]] && REPLY=$REPLY/$target || REPLY=$target
 | 
						|
		# Break out if we found a symlink loop
 | 
						|
		for target; do [[ $REPLY == "$target" ]] && break 2; done
 | 
						|
		# Add to the loop-detect list and tail-recurse
 | 
						|
		set -- "$REPLY" "$@"
 | 
						|
	done
 | 
						|
	REPLY="$1"
 | 
						|
}
 | 
						|
 | 
						|
realpath.absolute() {
 | 
						|
	REPLY=$PWD; local eg=extglob; ! shopt -q $eg || eg=; ${eg:+shopt -s $eg}
 | 
						|
	while (($#)); do case $1 in
 | 
						|
		/*) REPLY=/; set -- "${1##+(/)}" "${@:2}" ;;
 | 
						|
		*/*) set -- "${1%%/*}" "${1##${1%%/*}+(/)}" "${@:2}" ;;
 | 
						|
		''|.) shift ;;
 | 
						|
		..) realpath.dirname "$REPLY"; shift ;;
 | 
						|
		*) REPLY="${REPLY%/}/$1"; shift ;;
 | 
						|
	esac; done; ${eg:+shopt -u $eg}
 | 
						|
}
 | 
						|
 | 
						|
realpath.canonical() {
 | 
						|
	realpath.follow "$1"; set -- "$REPLY"   # $1 is now resolved
 | 
						|
	realpath.basename "$1"; set -- "$1" "$REPLY"   # $2 = basename $1
 | 
						|
	realpath.dirname "$1"
 | 
						|
	[[ $REPLY != "$1" ]] && realpath.canonical "$REPLY"; # recurse unless root
 | 
						|
	realpath.absolute "$REPLY" "$2";   # combine canon parent w/basename
 | 
						|
}
 | 
						|
 | 
						|
realpath.relative() {
 | 
						|
	local target=""
 | 
						|
	realpath.absolute "$1"; set -- "$REPLY" "${@:2}"; realpath.absolute "${2-$PWD}" X
 | 
						|
	while realpath.dirname "$REPLY"; [[ "$1" != "$REPLY" && "$1" == "${1#${REPLY%/}/}" ]]; do
 | 
						|
		target=../$target
 | 
						|
	done
 | 
						|
	[[ $1 == "$REPLY" ]] && REPLY=${target%/} || REPLY="$target${1#${REPLY%/}/}"
 | 
						|
	REPLY=${REPLY:-.}
 | 
						|
}
 | 
						|
# For documentation, see https://github.com/bashup/loco
 | 
						|
 | 
						|
set -euo pipefail
 | 
						|
 | 
						|
fn_exists() { declare -F -- "$1"; } >/dev/null
 | 
						|
fn_copy()   { REPLY="$(declare -f "$1")"; eval "$2 ${REPLY#$1}"; }
 | 
						|
findup()    { walkup "${1:-$PWD}" reply_if_exists "${@:2}"; }
 | 
						|
 | 
						|
reply_if_exists() {
 | 
						|
    local pat dir=$1 IFS= ; shift
 | 
						|
    for pat; do
 | 
						|
        for REPLY in ${dir%/}/$pat; do [[ -f "$REPLY" ]] && return 0; done
 | 
						|
    done
 | 
						|
    return 1
 | 
						|
}
 | 
						|
 | 
						|
walkup() {
 | 
						|
    realpath.absolute "$1"
 | 
						|
    until set -- "$REPLY" "${@:2}"; "$2" "$1" "${@:3}"; do
 | 
						|
        [[ "$1" != "/" ]] || return 1; realpath.dirname "$1"
 | 
						|
    done
 | 
						|
}
 | 
						|
 | 
						|
_loco_usage() { loco_error "Usage: $LOCO_COMMAND command args..."; }
 | 
						|
_loco_error() { echo "$@" >&2; exit 64; }
 | 
						|
_loco_cmd() { REPLY="$LOCO_NAME.$1"; }
 | 
						|
_loco_exec() { loco_error "Unrecognized command: $1"; }
 | 
						|
_loco_exists() { type -t "$1"; } >/dev/null
 | 
						|
 | 
						|
_loco_do() {
 | 
						|
    [[ "${1-}" ]] || loco_usage   # No command given, exit w/usage
 | 
						|
    REPLY=""; loco_cmd "$1"; local cmd="$REPLY"
 | 
						|
    [[ "$cmd" ]] || loco_usage   # Unrecognized command, exit w/usage
 | 
						|
 | 
						|
    if loco_exists "$cmd"; then
 | 
						|
        # Command, alias, function, or builtin exists
 | 
						|
        shift; "$cmd" "$@"
 | 
						|
    else
 | 
						|
        # Invoke the default command interpreter
 | 
						|
        loco_exec "$@"
 | 
						|
    fi
 | 
						|
}
 | 
						|
 | 
						|
_loco_findproject() {
 | 
						|
    # shellcheck disable=SC2015  # plain var assign can't be false
 | 
						|
    findup "$LOCO_PWD" "${LOCO_FILE[@]}" && LOCO_PROJECT=$REPLY ||
 | 
						|
        loco_error "Can't find $LOCO_FILE here";
 | 
						|
}
 | 
						|
_loco_preconfig() { true; }
 | 
						|
_loco_postconfig() { true; }
 | 
						|
_loco_findroot() { realpath.dirname "$LOCO_PROJECT"; LOCO_ROOT=$REPLY; }
 | 
						|
_loco_loadproject() { cd "$LOCO_ROOT";  $LOCO_LOAD "$1"; }
 | 
						|
_loco_site_config() { source "$1"; }
 | 
						|
_loco_user_config() { source "$1"; }
 | 
						|
 | 
						|
 | 
						|
# Find our configuration, exposing relevant paths and defaults
 | 
						|
 | 
						|
# shellcheck disable=SC2034  # some vars are only used by extending scripts
 | 
						|
_loco_config() {
 | 
						|
    LOCO_ARGS=("$@")
 | 
						|
    loco_preconfig "$@"
 | 
						|
    ${LOCO_COMMAND:+:} realpath.basename "$LOCO_SCRIPT"; LOCO_COMMAND="${LOCO_COMMAND-$REPLY}"
 | 
						|
    LOCO_NAME="${LOCO_NAME-${LOCO_COMMAND}}"
 | 
						|
    LOCO_PWD="${LOCO_PWD-$PWD}"
 | 
						|
 | 
						|
    LOCO_SITE_CONFIG="${LOCO_SITE_CONFIG-/etc/$LOCO_NAME/config}"
 | 
						|
    [ -f "$LOCO_SITE_CONFIG" ] && loco_site_config "$LOCO_SITE_CONFIG"
 | 
						|
    LOCO_RC="${LOCO_RC-.${LOCO_NAME}rc}"
 | 
						|
    LOCO_USER_CONFIG="${LOCO_USER_CONFIG-$HOME/$LOCO_RC}"
 | 
						|
    [ -f "$LOCO_USER_CONFIG" ] && loco_user_config "$LOCO_USER_CONFIG"
 | 
						|
 | 
						|
    [[ ${LOCO_FILE-} ]] || LOCO_FILE=(".$LOCO_NAME")
 | 
						|
    LOCO_LOAD="${LOCO_LOAD-source}"
 | 
						|
    loco_postconfig "$@"
 | 
						|
}
 | 
						|
 | 
						|
_loco_main() {
 | 
						|
    loco_config "$@"
 | 
						|
    fn_exists "$LOCO_NAME" || eval "$LOCO_NAME() { loco_do \"\$@\"; }"
 | 
						|
    ${LOCO_PROJECT:+:} loco_findproject "$@"
 | 
						|
    ${LOCO_ROOT:+:}    loco_findroot "$@"
 | 
						|
    loco_loadproject "$LOCO_PROJECT"
 | 
						|
    loco_do "$@"
 | 
						|
}
 | 
						|
 | 
						|
# Initialize default function implementations
 | 
						|
for f in $(compgen -A function _loco_); do
 | 
						|
    fn_exists "${f#_}" || fn_copy "$f" "${f#_}"
 | 
						|
done
 | 
						|
 | 
						|
# Clear all LOCO_*  variables before beginning
 | 
						|
for lv in ${!LOCO_@}; do unset "$lv"; done
 | 
						|
 | 
						|
LOCO_SCRIPT=$0
 | 
						|
GITEA_CREATE=()
 | 
						|
gitea.--with() {
 | 
						|
    local GITEA_CREATE=(${GITEA_CREATE[@]+"${GITEA_CREATE[@]}"} "${@:1:2}")
 | 
						|
    gitea "${@:3}"
 | 
						|
}
 | 
						|
gitea.--description() { gitea --with description "$1" "${@:2}"; }
 | 
						|
gitea.--desc()        { gitea --description "$@"; }
 | 
						|
gitea.-d()            { gitea --description "$@"; }
 | 
						|
gitea.--public() { gitea --with private= false "$@"; }
 | 
						|
gitea.-p()       { gitea --public "$@"; }
 | 
						|
gitea.--private() { gitea --with private= true "$@"; }
 | 
						|
gitea.-P()        { gitea --private "$@"; }
 | 
						|
gitea.--repo() {
 | 
						|
    split_repo "$1"; local PROJECT_ORG="${REPLY[1]}" PROJECT_NAME="${REPLY[2]}"; gitea "${@:2}"
 | 
						|
}
 | 
						|
gitea.-r() { gitea --repo "$@"; }
 | 
						|
gitea.--tag()  { local PROJECT_TAG="$1"; gitea "${@:2}" ; }
 | 
						|
gitea.-t()     { gitea --tag "$@"; }
 | 
						|
gitea.exists() { split_repo "$1" && auth api 200 404 "repos/$REPLY" ; }
 | 
						|
gitea.delete() { split_repo "$1" && auth api 204 "" "/repos/$REPLY" -X DELETE; }
 | 
						|
gitea.deploy-key() {
 | 
						|
    split_repo "$1"
 | 
						|
    jmap title "$2" key "$3" read_only= "${4-true}" | json auth api 201 "" /repos/$REPLY/keys
 | 
						|
}
 | 
						|
gitea.new() {
 | 
						|
    split_repo "$1"; local org="${REPLY[1]}" repo="${REPLY[2]}"
 | 
						|
    if [[ $org == "$GITEA_USER" ]]; then org=user; else org="org/$org"; fi
 | 
						|
    jmap name "$repo" ${GITEA_CREATE[@]+"${GITEA_CREATE[@]}"} "${@:2}" |
 | 
						|
        json api "200|201" "" "$org/repos?token=$GITEA_API_TOKEN"
 | 
						|
    [[ ! "${GITEA_DEPLOY_KEY-}" ]] ||
 | 
						|
        gitea deploy-key "$1" "${GITEA_DEPLOY_KEY_TITLE:-default}" \
 | 
						|
            "$GITEA_DEPLOY_KEY" "${GITEA_DEPLOY_READONLY:-true}"
 | 
						|
}
 | 
						|
gitea.vendor-merge() { :; }
 | 
						|
 | 
						|
branch-exists() { git rev-parse --verify "$1" &>/dev/null; }
 | 
						|
 | 
						|
gitea.vendor() {
 | 
						|
    [[ ! -d .git ]] || loco_error ".git repo must not exist here";
 | 
						|
    [[ -n "${PROJECT_ORG-}"  ]] || PROJECT_ORG=$GITEA_USER
 | 
						|
    [[ -n "${PROJECT_NAME-}" ]] || loco_error "PROJECT_NAME not set"
 | 
						|
 | 
						|
    local GITEA_GIT_URL=${GITEA_GIT_URL-$GITEA_URL}
 | 
						|
    [[ $GITEA_GIT_URL == *: ]] || GITEA_GIT_URL="${GITEA_GIT_URL%/}/";
 | 
						|
    local GIT_REPO="$GITEA_GIT_URL$PROJECT_ORG/$PROJECT_NAME.git"
 | 
						|
 | 
						|
    if gitea exists "$PROJECT_ORG/$PROJECT_NAME"; then
 | 
						|
        [[ -n "${PROJECT_TAG-}"  ]] || loco_error "PROJECT_TAG not set"
 | 
						|
        local MESSAGE="Vendor update to $PROJECT_TAG"
 | 
						|
        git clone --bare -b vendor "$GIT_REPO" .git ||
 | 
						|
        git clone --bare "$GIT_REPO" .git   # handle missing-branch case
 | 
						|
    else
 | 
						|
        local MESSAGE="Initial import"
 | 
						|
        gitea new "$PROJECT_ORG/$PROJECT_NAME" "$@"
 | 
						|
        git clone --bare "$GIT_REPO" .git
 | 
						|
    fi
 | 
						|
 | 
						|
    git config --local --bool core.bare false
 | 
						|
    git config --local user.name "${GITEA_VENDOR_NAME:-Vendor}"
 | 
						|
    git config --local user.email "${GITEA_VENDOR_EMAIL:-vendor@example.com}"
 | 
						|
 | 
						|
    git add .; git commit -m "$MESSAGE"             # commit to master or vendor
 | 
						|
    branch-exists vendor || git checkout -b vendor  # split off vendor branch if needed
 | 
						|
    git push --all
 | 
						|
 | 
						|
    [[ -z "${PROJECT_TAG-}" ]] || { git tag "vendor-$PROJECT_TAG"; git push --tags; }
 | 
						|
 | 
						|
    git checkout master
 | 
						|
    gitea vendor-merge
 | 
						|
}
 | 
						|
split_repo() {
 | 
						|
    [[ "$1" == */* ]] || set -- "$GITEA_USER/$1";
 | 
						|
    REPLY=("$1" "${1%/*}" "${1##*/}")
 | 
						|
}
 | 
						|
jmap() {
 | 
						|
    local filter='{}' opts=(-n) arg=1
 | 
						|
    while (($#)); do
 | 
						|
        if [[ $1 == *= ]]; then
 | 
						|
            filter+=" | .$1 $2"
 | 
						|
        else
 | 
						|
            filter+=" | .$1=\$__$arg"
 | 
						|
            opts+=(--arg "__$arg" "$2")
 | 
						|
            ((arg++))
 | 
						|
        fi
 | 
						|
        shift 2
 | 
						|
    done
 | 
						|
    jq "${opts[@]}" "$filter"
 | 
						|
}
 | 
						|
json() { "$@" -X POST -H "Content-Type: application/json" -d @-; }
 | 
						|
auth() { "$@" -H "Authorization: token $GITEA_API_TOKEN"; }
 | 
						|
api() {
 | 
						|
    if ! shopt -q extglob; then
 | 
						|
        # extglob is needed for pattern matching
 | 
						|
        local r=0; shopt -s extglob; api "$@" || r=$?; shopt -u extglob; return $r
 | 
						|
    fi
 | 
						|
    read-curl --silent --write-out '%{http_code}' --output /dev/null "${@:4}" "${GITEA_URL%/}/api/v1/${3#/}"
 | 
						|
    local true="@($1)" false="@($2)"
 | 
						|
    # shellcheck disable=2053  # glob matching is what we want!
 | 
						|
    if [[ $REPLY == $true ]]; then return 0; elif [[ $2 && $REPLY == $false ]]; then return 1
 | 
						|
    else case $REPLY in
 | 
						|
        000) fail "Invalid server response: check GITEA_URL" 78 ;;            # EX_PROTOCOL
 | 
						|
        401) fail "Unauthorized: check GITEA_USER and GITEA_API_TOKEN" 77  ;; # EX_NOPERM
 | 
						|
        404) fail "Server returned 404 Not Found" 69                       ;; # EX_UNAVAILABLE
 | 
						|
        *)   fail "Failure: HTTP code $REPLY (expected $1${2:+ or $2})" 70 ;; # EX_SOFTWARE
 | 
						|
        esac
 | 
						|
    fi
 | 
						|
}
 | 
						|
read-curl() { REPLY=$(curl "$@"); }
 | 
						|
fail() { echo "$1" >&2; return "${2-64}"; }
 | 
						|
loco_preconfig() {
 | 
						|
    LOCO_SCRIPT=$BASH_SOURCE
 | 
						|
    LOCO_SITE_CONFIG=/etc/gitea-cli/gitearc
 | 
						|
    LOCO_USER_CONFIG=$HOME/.config/gitearc
 | 
						|
    LOCO_NAME=gitea
 | 
						|
    LOCO_FILE=(.gitearc)
 | 
						|
    PROJECT_NAME="${PROJECT_NAME-$(basename "$PWD")}"
 | 
						|
}
 | 
						|
loco_findproject() {
 | 
						|
    findup "$LOCO_PWD" "${LOCO_FILE[@]}" && LOCO_PROJECT=$REPLY || LOCO_PROJECT=/dev/null
 | 
						|
}
 | 
						|
loco_findroot() { LOCO_ROOT=$LOCO_PWD; }
 | 
						|
if [[ $0 == "${BASH_SOURCE-}" ]]; then loco_main "$@"; fi
 |