#!/usr/bin/env bash # Copyright (C) 2012-2013 Pacman Development Team # Copyright (C) 2012-2013 Luke Shumaker # # License: GNU GPLv2+ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . . libremessages # from makepkg dir_is_empty() { ( shopt -s dotglob nullglob files=("$1"/*) (( ${#files} == 0 )) ) } # from makepkg cd_safe() { if ! cd "$1"; then error "Failed to change to directory %s" "$1" plain "Aborting..." exit 1 fi } # from makepkg download_git_checkout() { local url=$1 local ref=$2 local dir=$3 local name=$4 local push=${5:-} if [[ ! -d "$dir/.git" ]] ; then msg2 "Cloning %s %s repo..." "${name}" "git" if ! git clone "$url" "$dir"; then error "Failure while downloading %s %s repo" "${name}" "git" plain "Aborting..." exit 1 fi cd_safe "$dir" if [[ -n $push ]]; then git config remote.origin.pushUrl "$push" fi git checkout "$ref" else cd_safe "$dir" # Make sure we are fetching the right repo if [[ "$url" != "$(git config --get remote.origin.url)" ]] ; then if $FORCE; then git config remote.origin.url "$url" else error "%s is not a clone of %s" "$dir" "$url" plain "Aborting..." exit 1 fi fi if [[ -n $push ]] ; then if $FORCE; then git config remote.origin.pushUrl "$push" else local curpush="$(git config --get remote.origin.pushUrl)" if [[ $? != 0 ]] ; then error "%s does not have a %s configured" pushUrl "$name" plain "Aborting..." exit 1 elif [[ $curpush != "$push" ]]; then error "%s has %s configured, but it doesn't match %s" "$name" pushUrl "$push" plain "Aborting..." exit 1 fi fi fi msg2 "Updating %s %s repo..." "${name}" "git" if ! { git fetch --all -p && git checkout "$ref" && git pull origin "$ref"; } ; then # only warn on failure to allow offline builds warning "Failure while updating %s %s repo" "${repo}" "git" fi fi } # from makepkg download_git_bare() { local url=$1 local dir=$2 local name=$3 local push=${4:-} if [[ ! -d "$dir" ]] || dir_is_empty "$dir" ; then msg2 "Cloning %s %s repo..." "${name}" "git" if ! git clone --mirror "$url" "$dir"; then error "Failure while downloading %s %s repo" "${name}" "git" plain "Aborting..." exit 1 fi if [[ -n $push ]]; then cd_safe "$dir" git config remote.origin.pushUrl "$push" fi else cd_safe "$dir" # Make sure we are fetching the right repo if [[ "$url" != "$(git config --get remote.origin.url)" ]] ; then error "%s is not a clone of %s" "$dir" "$url" plain "Aborting..." exit 1 fi if [[ -n $push ]] ; then if $FORCE; then git config remote.origin.pushUrl "$push" else local curpush="$(git config --get remote.origin.pushUrl)" if [[ $? != 0 ]] ; then error "%s does not have a %s configured" pushUrl "$name" plain "Aborting..." exit 1 elif [[ $curpush != "$push" ]]; then error "%s has %s configured, but it doesn't match %s" "$name" pushUrl "$push" plain "Aborting..." exit 1 fi fi fi msg2 "Updating %s %s repo..." "${name}" "git" if ! git fetch --all -p; then # only warn on failure to allow offline builds warning "Failure while updating %s %s repo" "${name}" "git" fi fi } usage() { print 'Usage: %s [OPTIONS] [bare|checkout] URL DIRECTORY' "${0##*/}" print 'A URL-handler for git urls. Capable of updating or cloning.' echo prose "Clones or pulls from the git URL, to a local DIRECTORY. If \`bare\` is specified, it will create a bare repository; if \`checkout\` is specified, it will create or update a working tree." echo prose 'For a checkout, the tree to checkout is specified by appending `#ANYTHING=TREE-ISH` to the URL. For example, `#branch=stable`, or `#tag=v12.3`. Whatever is on the left side of the equal sign is ignored, this is for compatibility with `makepkg` source URLs.' echo prose "The URL may be prefixed with \`git+\`. This is also for compatibility with \`makepkg\` source URLs." echo prose "It does safety checks, figures out whether to clone or pull, and other helpful things. This exists because the same \`download_git\` function from makepkg was being copied and pasted again and again." echo print "Options:" flag '-f' \ 'Instead of checking to make sure configured URLs match, force the update, and set the URLs.' flag "-p $(_ URL)" \ 'In addition to setting or checking `remotes.origin.url`, also set or check `remotes.origin.pushUrl`' flag "-n $(_ NAME)" \ 'In messages, instead of using the basename of DIRECTORY as the repository name, use NAME' flag '-h' 'Show this message' } FORCE=false main() { local push='' local name='' while getopts 'fp:n:h' flag; do case "${flag}" in f) FORCE=true;; p) push=$OPTARG;; n) name=$OPTARG;; h) usage; return 0;; *) usage >&2; return 1;; esac done shift $(($OPTIND - 1)) [[ $# == 3 ]] || { usage >&2; return 1; } local mode=$1 local url=${2#git+} local dir=$3 local urlmain=${url%%#*} local urlfrag=${url#*#} if [[ "$urlfrag" == "$urlmain" ]]; then urlfrag='' fi local ref=${urlfrag#*=} if [[ -z $ref ]]; then ref=master fi name=${name:-${dir##*/}} case "$mode" in checkout) download_git_checkout "$urlmain" "$ref" "$dir" "$name" "$push";; bare) download_git_bare "$urlmain" "$dir" "$name" "$push";; *) usage >&2; return 1;; esac } main "$@"