Sindbad~EG File Manager
#!/bin/bash
set -f
VERBOSITY=0
SUPPORTED_VCS="bzr hg git url"
RET_UNCLAIMED=3
RET_SUCCESS=0
RET_FAIL=1
DEF_COMMAND="vcs_run"
Usage() {
cat <<EOF
Usage: ${0##*/} [ options ] repo-url [command [arguments]]
obtain repository from repo-url, and execute 'command' with 'arguments'
Command will default to '$DEF_COMMAND' in the top level of the repository.
options:
-t | --target DIR checkout branch to DIR [./(basename repo)]
--vcs-type V repo-url is of type 'V' [auto]
supported: auto $SUPPORTED_VCS
-v | --verbose increase verbosity
-D | --deps attempt to install dependencies if necessary
Example:
* run 'stack.sh' in git://github.com/openstack-dev/devstack.git
vcs-run --deps git://github.com/openstack-dev/devstack.git stack.sh
* build cloud-utils
vcs-run --deps lp:cloud-utils -- ./tools/build-deb -us -uc
EOF
}
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
error() { echo "$@" 1>&2; }
debug() {
local level=${1}; shift;
[ "${level}" -gt "${VERBOSITY}" ] && return
error "${@}"
}
has_cmd() {
command -v "$1" >/dev/null 2>&1
}
get_cmd() {
# get_cmd(cmd, get_deps, packages)
# get command 'cmd' if necessary by installing 'packages'
# if 'get_deps' is false, then return error.
local cmd="$1" deps="$2"
shift 2
has_cmd "$1" && return 0
$deps || { error "No cmd '$cmd', but nodeps specified"; return 1; }
apt_install "$@"
}
apt_install() {
local cmd=""
cmd=( env DEBIAN_FRONTEND=noninteractive apt-get --quiet
--assume-yes install "$@" )
[ "$(id -u)" = "0" ] ||
cmd=( sudo "${cmd[@]}" )
debug 1 "installing dependencies:" "${cmd[@]}"
"${cmd[@]}"
}
vcsget_bzr() {
# deps type src target cmd
local deps="$1" rtype="$2" src="$3" target="$4" tmp=""
if [ "$rtype" = "auto" ]; then
case "$src" in
*.bzr|bzr:*|lp:*) :;;
*)
if ! [ -d "$src" -a -d "$src/.bzr" ]; then
return $RET_UNCLAIMED
fi
src=$(cd "$src" && pwd) || return $RET_FAIL
;;
esac
fi
get_cmd bzr "$deps" bzr || return $RET_FAIL
if [ -z "$target" ]; then
case "$src" in
*/*) tmp="${src##*/}";;
*:*) tmp="${src#*:}";;
*) tmp="$src"
esac
target="${tmp%.bzr}"
fi
local cmd="" q="--quiet"
[ $VERBOSITY -gt 1 ] && q=""
if [ -d "$target/.bzr" ]; then
debug 1 "updating $target: bzr pull ${q:+$q }$src"
( cd "$target" && bzr pull $q "$src" )
else
debug 1 "branching to $target: bzr branch ${q:+$q }$src"
bzr branch $q "$src" "$target"
fi
[ $? -eq 0 ] || return $RET_FAIL
_RET="$target"
return 0
}
vcsget_git() {
# deps type src target cmd
local deps="$1" rtype="$2" src="$3" target="$4" tmp=""
if [ "$rtype" = "auto" ]; then
case "$src" in
*.git|git:*) :;;
*)
if ! [ -d "$src" -a -d "$src/.git" ]; then
return $RET_UNCLAIMED
fi
src=$(cd "$src" && pwd) || return $RET_FAIL
;;
esac
fi
get_cmd git "$deps" git || return $RET_FAIL
if [ -z "$target" ]; then
tmp="${src##*/}"
target="${tmp%.git}"
fi
local q="--quiet"
[ $VERBOSITY -gt 1 ] && q=""
if [ -d "$target/.git" ]; then
debug 1 "updating $target: git pull ${q:+$q }${src}"
( cd "$target" && git pull $q "$src" )
else
debug 1 "cloning to $target: git clone ${q:+$q }$src $target"
git clone $q "$src" "$target" || return $RET_FAIL
fi
[ $? -eq 0 ] || return $RET_FAIL
_RET="$target"
return 0
}
vcsget_hg() {
# deps type src target cmd
local deps="$1" rtype="$2" src="$3" target="$4" tmp=""
if [ "$rtype" = "auto" ]; then
case "$src" in
*.hg|hg:*) :;;
*) return $RET_UNCLAIMED;;
esac
fi
get_cmd hg "$deps" mercurial || return $RET_FAIL
if [ -z "$target" ]; then
tmp="${src##*/}"
target="${tmp%.hg}"
fi
local quiet="--quiet"
[ $VERBOSITY -gt 1 ] && quiet=""
hg clone $quiet "$src" "$target" || return $RET_FAIL
_RET="$target"
return 0
}
vcsget_url() {
# deps type src target cmd
# if target is not specified, target directory is md5sum
# of the url. If cmd does not start with a /, then use it
# as the output filename. If it does start with a /, then
# store the url in DEF_COMMAND in this directory.
local deps="$1" rtype="$2" src="$3" target="$4" cmd="$5" tmp=""
if [ "$rtype" = "auto" ]; then
case "$src" in
http://*|https://*) :;;
*) return $RET_UNCLAIMED;;
esac
fi
get_cmd wget "$deps" wget || return $RET_FAIL
if [ -z "$target" ]; then
target=$(echo "$src" | md5sum)
target=${target% -}
fi
local cmdname="$cmd"
if [ "${cmd#/}" != "$cmd" ]; then
cmdname="./$DEF_COMMAND"
fi
local quiet="--quiet"
[ $VERBOSITY -gt 1 ] && quiet=""
mkdir -p "$target" ||
{ error "failed mkdir -p '$target'"; return $RET_FAIL; }
debug 1 "wget -O '$target/$cmdname' '$src'"
wget $quiet -O "$target/$cmdname" "$src" || {
error "failed wget -O '$target/$cmdname' '$src'"
return $RET_FAIL
}
_RET="$target"
return 0
}
main() {
local short_opts="hDt:v"
local long_opts="help,deps,target:,vcs-type:,verbose"
local getopt_out=$(getopt --name "${0##*/}" \
--options "${short_opts}" --long "${long_opts}" -- "$@") &&
eval set -- "${getopt_out}" ||
{ bad_Usage; return; }
local cur="" next="" target="" rtype="auto" tmp=""
local def_target="" deps="" getdeps=false arg0=""
while [ $# -ne 0 ]; do
cur="$1"; next="$2";
case "$cur" in
-h|--help) Usage ; exit 0;;
-D|--deps) getdeps=true;;
-t|--target) target=$next; shift;;
--vcs-type) rtype=$next; shift;;
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
--) shift; break;;
esac
shift;
done
[ $# -gt 0 ] || { bad_Usage "must provide at least repo"; return; }
src_repo="$1"
shift
[ -n "$src_repo" ] || { error "empty source repo?"; return 1; }
if [ -n "$target" ]; then
tmp=$(dirname "${target}")
[ -d "$tmp" ] || mkdir -p "$tmp" ||
{ error "failed to create $tmp for '$target'"; return 1; }
fi
if [ $# -eq 0 ]; then
set -- "$DEF_COMMAND"
fi
arg0="$1"
local vcs vcslist="${SUPPORTED_VCS}"
[ "$rtype" = "auto" ] || vcslist="$rtype"
local workd=""
for vcs in $vcslist; do
has_cmd "vcsget_$vcs" ||
{ error "unknown vcs type '$vcs'"; return 1; }
"vcsget_$vcs" "$getdeps" "$rtype" "$src_repo" "$target" "$arg0"
ret=$?
case "$ret" in
$RET_UNCLAIMED) :;; # not claimed
$RET_SUCCESS) workd="$_RET"; break;;
*) error "failed to get '$src_repo' of type '$vcs'";
return $ret;;
esac
done
[ -d "$workd" ] ||
{ error "unknown source repo '$src_repo'"; return 1; }
cd "$workd" ||
{ error "failed to enter target dir '$workd'"; return 1; }
if [ -f "./$1" ]; then
if [ ! -x "./$1" ]; then
debug 1 "adding execute to ./$1"
chmod ugo+x "./$1" ||
{ error "failed add execute to ./$1"; return 1; }
fi
tmp="./$1"
shift
set -- "$tmp" "$@"
elif ! has_cmd "$1"; then
error "command '$1' not available anywhere"
return 1
fi
debug 1 "executing command in $PWD:" "$@"
exec "$@"
}
main "$@"
# vi: ts=4 noexpandtab
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists