|
#!/bin/bash |
|
# https://gist.github.com/87dc8fe5da16d585cd548ef85ff2daf5.git |
|
set -o pipefail |
|
|
|
CR=' |
|
' |
|
MYNAME="atx-rpm-build" |
|
DEFAULT_IMAGE="images:centos/7" |
|
DEFAULT_REMOTE="local" |
|
SNAPSHOT_PREFIX="atx-build/" |
|
|
|
VERBOSITY=${VERBOSITY:-0} |
|
TEMP_D="" |
|
|
|
error() { echo "$@" 1>&2; } |
|
fail() { local r=$?; [ $r -eq 0 ] && r=1; failrc "$r" "$@"; } |
|
failrc() { local r=$1; shift; [ $# -eq 0 ] || error "$@"; exit $r; } |
|
|
|
Usage() { |
|
cat <<EOF |
|
Usage: ${0##*/} [ options ] [package-dir] [-- rpmbuild args] |
|
|
|
build package inside lxc container. requires ctool in path. |
|
|
|
package-dir defaults to '.' if there is a SPECS and SOURCES dir in . |
|
|
|
If no args are given, '-ba' (build all) is used. |
|
|
|
options: |
|
-v | --verbose increase verbosity |
|
-R | --remote use lxc remote (default $DEFAULT_REMOTE) |
|
-i | --image X use lxc image X (default $DEFAULT_IMAGE) |
|
--name N name the container N - default is random |
|
|
|
|
|
subcmd: |
|
make-snapshot [--remote=remote] [-v] [image] [snapshot-name] |
|
|
|
This will start a container on 'remote' of 'image', |
|
and update and stop it. Then it will publish it to |
|
remote:snapshot-name |
|
|
|
if 'image' not given use $DEFAULT_IMAGE |
|
if 'snapshot-name' not provided, use |
|
$SNAPSHOT_PREFIX<image-name> |
|
|
|
after running 'make-snapshot' subsequent runs will by |
|
default use the published snapshot. |
|
EOF |
|
} |
|
|
|
bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; } |
|
cleanup() { |
|
[ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}" |
|
} |
|
|
|
debug() { |
|
local level=${1}; shift; |
|
[ "${level}" -gt "${VERBOSITY}" ] && return |
|
error "${@}" |
|
} |
|
|
|
inside() { |
|
local n="$1" |
|
shift |
|
debug 1 "[$n] running: $*" |
|
ctool execute "--container=$n" "--user=root" -- "$@" |
|
} |
|
|
|
has_cmd() { |
|
command -v "$1" >/dev/null 2>&1 |
|
} |
|
|
|
install_deps() { |
|
# install sudo and generic build-deps |
|
local cmd="" extra="" |
|
if has_cmd dnf; then |
|
cmd="dnf" |
|
extra="subscription-manager" |
|
else |
|
cmd="yum" |
|
extra="yum-utils" |
|
fi |
|
local vid="" epelurl="" |
|
|
|
vid=$( . /etc/os-release ; echo "$VERSION_ID" ) && { |
|
epelurl="https://dl.fedoraproject.org/pub/epel/epel-release-latest-$vid.noarch.rpm" |
|
} |
|
|
|
debug 1 "installing sudo spectool git $extra $epelurl" |
|
$cmd install --assumeyes sudo spectool git \ |
|
$extra ${epelurl:+"${epelurl}"} || { |
|
error "Failed to install deps." |
|
return 1 |
|
} |
|
|
|
if [ "$vid" = "8" ]; then |
|
dnf config-manager --set-enabled PowerTools || { |
|
error "Failed to enable power tools." |
|
return 1 |
|
} |
|
fi |
|
|
|
$cmd groupinstall --assumeyes "Development Tools" || { |
|
error "Failed to install Development Tools" |
|
return 1 |
|
} |
|
|
|
return 0 |
|
} |
|
|
|
disable_extras() { |
|
# https://bugs.centos.org/view.php?id=15615 |
|
# there is no repodata at http://vault.centos.org/centos/7/extras/Source/ |
|
# so yum-builddep would fail. |
|
# so we disable the 'extra-sources' repo. |
|
local f="/etc/yum.repos.d/CentOS-Sources.repo" |
|
if ! grep -q "^\[extras-source\]" "$f"; then |
|
return 0 |
|
fi |
|
mv "$f" "$f.dist" || return |
|
oifs="$IFS" |
|
IFS="$CR" |
|
# very hackily comment out the '[extras-source]' stanza |
|
while read line; do |
|
case "$line" in |
|
\[extras-source\]) |
|
echo "#$line" |
|
while read line; do |
|
echo "#$line" |
|
[ "$line" = "" ] && break |
|
done |
|
;; |
|
*) echo "$line";; |
|
esac |
|
done < "$f.dist" >"$f" |
|
} |
|
|
|
install_pkg_deps() { |
|
local d="$1" |
|
specdir_info "$d" || return 1 |
|
local topd="$_RET_TOPD" spec="$_RET_SPEC" |
|
|
|
if has_cmd dnf; then |
|
set -- dnf builddep |
|
else |
|
set -- yum-builddep |
|
disable_extras |
|
fi |
|
set -- sudo "$@" --define "_topdir $topd" --assumeyes "$spec" |
|
debug 1 "installing build dependencies with: $*" |
|
"$@" |
|
} |
|
|
|
one_file() { |
|
local found="" |
|
for f in "$@"; do |
|
[ -f "$f" ] || continue |
|
[ -n "$found" ] && return 1 |
|
found="$f" |
|
done |
|
_RET="$found" |
|
[ -n "$found" ] |
|
} |
|
|
|
dosum() { |
|
local file="$1" summer="$2" expected="$3" out="" found="" |
|
case ${summer%[Ss][Uu][Mm]} in |
|
[Mm][Dd]5) summer=md5sum;; |
|
[Ss][Hh][Aa]256) summer=sha256sum;; |
|
[Ss][Hh][Aa]512) summer=sha512sum;; |
|
[Ss][Hh][Aa]1) summer=sha1sum;; |
|
esac |
|
out=$("$summer" "$file") || return 1 |
|
found=${out% *} |
|
_RET="$found" |
|
[ $# -eq 2 ] && return 0 |
|
[ "$expected" = "$found" ] |
|
} |
|
|
|
download() { |
|
local url="$1" fname="$2" hashname="$3" sum="$4" tmp="" |
|
if [ ! -f "$fname" ]; then |
|
local dir=$(dirname $fname) tmp="$fname.tmp" |
|
[ -d "$dir" ] || mkdir -p "$dir" || return 1 |
|
debug 1 "downloading $url -> $fname" |
|
curl --fail "$url" > "$tmp" || { |
|
error "failed download of $url -> $tmp" |
|
rm "$tmp" |
|
return 1 |
|
} |
|
fi |
|
|
|
if [ -z "$sum" ]; then |
|
debug 1 "no expected sum for $fname" |
|
[ -z "$tmp" ] || mv "$tmp" "$fname" |
|
return |
|
fi |
|
|
|
if ! dosum "${tmp:-${fname}}" "$hashname" "$sum"; then |
|
error "$fname had incorrect $hashname: expected $sum found $_RET" |
|
[ -z "$tmp" ] || rm "$tmp" |
|
return 1 |
|
fi |
|
|
|
found=${_RET} |
|
[ -z "$tmp" ] || mv "$tmp" "$fname" || return 1 |
|
debug 1 "$fname had $hashname $sum" |
|
return 0 |
|
} |
|
|
|
get_fedora_sources() { |
|
# packages are in <surl>/<pkgname>/<filename>/<lowercase-hashname>/<hash>/<filename> |
|
# sources looks like: |
|
# SHA512 (LVM2.2.03.09.tgz) = <hash> |
|
local pkg="$1" sources="$2" out_d="$3" |
|
local surl="https://src.fedoraproject.org/repo/pkgs" |
|
local _ hashname fname hash url="" n="0" |
|
while read hashname fname _ hash; do |
|
n=$((n+1)) |
|
fname="${fname#[(]}" |
|
fname="${fname%[)]}" |
|
hashname=${hashname,,} # lower case |
|
url="$surl/$pkg/$fname/$hashname/$hash/$fname" |
|
debug 1 "source $fname from $url [$hash]" |
|
download "$url" "$out_d/$fname" "$hashname" "$hash" || return 1 |
|
done <"$sources" |
|
if [ $n -eq 0 ]; then |
|
debug 0 "empty sources file? $sources" |
|
fi |
|
return 0 |
|
} |
|
|
|
guess_current_centos_branch() { |
|
# generate a list of all branches containing current HEAD |
|
local remotename="" out="" remote="" |
|
if [ -n "$CENTOS_BRANCH" ]; then |
|
unset _RET |
|
_RET="$CENTOS_BRANCH" |
|
return |
|
fi |
|
|
|
if [ -n "${CENTOS_REMOTENAME}" ]; then |
|
remotename="${CENTOS_REMOTENAME}" |
|
else |
|
out=$(git remote -v) || { |
|
error "Failed to run 'git remote -v'" |
|
return 1 |
|
} |
|
remotename=$(echo "$out" | |
|
awk '$2 ~ /centos.org/ { print $1; exit(0); }') |
|
[ -n "$remotename" ] || { |
|
error "did not find any remotes that look like centos" |
|
error "set CENTOS_REMOTENAME" |
|
error "Guessing branches: c7 c8" |
|
_RET="c7 c8" |
|
return 0 |
|
} |
|
fi |
|
|
|
local brname mb="" |
|
unset _RET; _RET="" |
|
for brname in c7 c8; do |
|
if mb=$(git merge-base HEAD "$remotename/$brname" 2>/dev/null); then |
|
_RET="$brname $_RET" |
|
fi |
|
done |
|
_RET=${_RET% } |
|
[ -n "$_RET" ] || { |
|
error "Failed to find any branches on $remotename that look good." |
|
error "Guessing branches: c7 c8" |
|
_RET="c7 c8" |
|
return 0 |
|
} |
|
return 0 |
|
} |
|
|
|
get_centos_sources() { |
|
# centos lookaside looks like |
|
# https://git.centos.org/sources/<pkg>/<branchname>/<hash> |
|
# $ cat .lvm2.metadata |
|
# 7a3834ca1ddaa7c4edc3863f18ec604f45722c65 SOURCES/LVM2.2.02.186.tgz |
|
# dd96613e238f342641b5be8977ee8598662e8ab9 SOURCES/boom-0.9.tar.gz |
|
local pkg="$1" mdfile="$2" out_d="$3" branch="$4" fbranch="" |
|
local surl="https://git.centos.org/sources" |
|
local _ hashname fpath fname url="" n=0 |
|
[ -f "$mdfile" ] || { |
|
error "$mdfile: not a file" |
|
return 1 |
|
} |
|
if [ -n "$branch" ]; then |
|
branches=( $branch ) |
|
else |
|
guess_current_centos_branch || { |
|
error "Failed to determine centos branch" |
|
return 1 |
|
} |
|
local branches="" |
|
branches=( $_RET ) |
|
fi |
|
while read hash fpath; do |
|
n=$((n+1)) |
|
fname=${fpath##*/} |
|
case ${#hash} in |
|
128) hashname="sha512";; |
|
64) hashname="sha256";; |
|
40) hashname="sha1sum";; |
|
32) hashname="md5sum";; |
|
*) error "unknown hash $hash (len=${#hash})" \ |
|
"for $fpath in $sources"; |
|
return 1;; |
|
esac |
|
fbranch="" |
|
for branch in "${branches[@]}"; do |
|
url="$surl/$pkg/$branch/$hash" |
|
debug 1 "source $fname from $url [$hash]" |
|
download "$url" "$out_d/$fname" "$hashname" "$hash" && |
|
fbranch="$branch" && break |
|
done |
|
[ -n "$fbranch" ] || { |
|
debug 1 "Failed to get source for $pkg $hash from any of ${branches[*]}" |
|
return 1 |
|
} |
|
done <"$mdfile" |
|
if [ $n -eq 0 ]; then |
|
debug 0 "empty metadata file file? $mdfile" |
|
fi |
|
return 0 |
|
} |
|
|
|
get_sources() { |
|
local d="$1" pkg="" |
|
specdir_info "$d" || return 1 |
|
local sourced="$_RET_SOURCES" spec="$_RET_SPEC" topd="$_RET_TOPD" |
|
|
|
if [ -f "$topd/sources" ]; then |
|
# fedora style |
|
pkg=$(awk '$1 == "Name:" { print $2; exit(0); }' "$spec") |
|
[ -n "$pkg" ] || { |
|
error "could not get pkg from $spec"; |
|
return 1; |
|
} |
|
get_fedora_sources "$pkg" "$topd/sources" "$sourced" || { |
|
error "failed to download fedora sources." |
|
return 1 |
|
} |
|
elif one_file "$topd"/.*.metadata; then |
|
# centos style (.lvm2.metadata) |
|
local mdfile="$_RET" |
|
pkg=${_RET##*/} |
|
pkg=${pkg%.metadata} |
|
pkg=${pkg#.} |
|
echo "pkg=$pkg mdfile=$mdfile sourced=$sourced" |
|
get_centos_sources "$pkg" "$mdfile" "$sourced" || { |
|
error "failed to get centos source" |
|
return 1 |
|
} |
|
else |
|
spectool --get-files "--directory=$sourced" "$spec" || { |
|
error "Failed to get sources with spectool" |
|
return 1 |
|
} |
|
fi |
|
} |
|
|
|
specdir_info() { |
|
local d="$1" specd="" f="" topd="" |
|
[ -z "$d" ] && d="." |
|
topd=$(realpath "$d") || { |
|
error "failed to get realpath for $d" |
|
return 1 |
|
} |
|
if [ -d "$topd/SPECS" ]; then |
|
specd="$topd/SPECS" |
|
else |
|
specd="$topd" |
|
fi |
|
one_file "$specd"/*.spec || { |
|
error "did not find exactly one spec in $specd" "$specd"/*.spec |
|
return 1 |
|
} |
|
|
|
_RET_TOPD="$topd" |
|
_RET_SPEC="$_RET" |
|
_RET_SPECD="$specd" |
|
[ -d "$topd/SOURCES" ] && _RET_SOURCES="$topd/SOURCES" || |
|
_RET_SOURCES="$topd" |
|
} |
|
|
|
build() { |
|
[ $# -eq 0 ] && set -- . |
|
local d="$1" |
|
specdir_info "$d" || return 1 |
|
shift |
|
if [ $# -eq 0 ]; then |
|
set -- -ba |
|
fi |
|
local sourced="$_RET_SOURCES" topd="$_RET_TOPD" |
|
local spec="$_RET_SPEC" specd="$_RET_SPECD" |
|
if [ "$specd" = "$topd" ]; then |
|
ln -snf . SPECS || { |
|
error "failed to link SPECS to . in fedora style build" |
|
return 1 |
|
} |
|
fi |
|
if [ "$sourced" = "$topd" ]; then |
|
ln -snf . SOURCES || { |
|
error "failed to link SOURCES to . in fedora style build" |
|
return 1 |
|
} |
|
fi |
|
debug 0 "building: rpmbuild --define \"_topdir \$PWD\" $* $spec" |
|
set -- rpmbuild --define "_topdir $PWD" "$@" "$spec" |
|
"$@" | tee build.log |
|
} |
|
|
|
|
|
wait_for_boot() { |
|
local tests="0" |
|
while :; do |
|
is_system_up "$tests" && return 0 |
|
[ $tests -gt 20 ] && return 1 |
|
echo -n . |
|
sleep 1 |
|
tests=$((tests+1)) |
|
done |
|
} |
|
|
|
is_system_up() { |
|
local s="" num="$1" |
|
s=$(systemctl is-system-running 2>&1); |
|
_RET="$? $s" |
|
case "$s" in |
|
initializing|starting) return 1;; |
|
*[Ff]ailed*connect*bus*) |
|
# warn if not the first run. |
|
[ "$num" -lt 5 ] || |
|
error "Failed to connect to systemd bus [${_RET%% *}]"; |
|
return 1;; |
|
esac |
|
|
|
s=$(systemctl is-active network.service 2>&1) |
|
_RET="$? $s" |
|
|
|
case "$s" in |
|
initializing|starting|activating) return 1;; |
|
esac |
|
|
|
return 0 |
|
} |
|
|
|
get_image_name() { |
|
local remote="$1" image="$2" |
|
[ -n "$image" ] && { |
|
_RET="$image" |
|
return 0 |
|
} |
|
# check to see if a snapshot of default exists. |
|
local def="${DEFAULT_IMAGE}" snapname="" out="" |
|
# this ends up looking like atx-build/centos/7 |
|
snapname=${SNAPSHOT_PREFIX}${def##*:} |
|
|
|
_RET="$def" |
|
out=$(lxc image show "$remote:$snapname" 2>&1) && { |
|
debug 1 "using snapshot $remote:$snapname of $def" |
|
_RET="$remote:$snapname" |
|
} |
|
|
|
return 0 |
|
} |
|
|
|
start_container(){ |
|
# start a container, wait |
|
local out="" remote="$1" name="$2" image="$3" install_deps="${3:-true}" |
|
get_image_name "$remote" "$image" || { |
|
error "failed to get default image" |
|
return 1 |
|
} |
|
image="$_RET" |
|
local rname="$remote:$name" |
|
|
|
debug 1 "lxc init $image $rname" |
|
out=$(lxc init "$image" "$rname") || { |
|
error "failed: lxc init $image $rname" |
|
return 1 |
|
} |
|
if [ -z "$name" ]; then |
|
name=$(echo "$out" | sed -n 's/.*Instance name is: \([-a-z]*\).*/\1/p') |
|
[ -n "$name" ] || { |
|
error "failed to start container from '$image'" |
|
error "init output looked like '$out'" |
|
return 1 |
|
} |
|
rname="$remote:$name" |
|
fi |
|
debug 0 "container $rname started from $image" |
|
|
|
# push self inside |
|
lxc file push "$0" "$rname/usr/bin/$MYNAME" || { |
|
error "Failed to insert $0 into $name" |
|
return 1 |
|
} |
|
|
|
lxc start "$rname" || { |
|
error "failed to start container '$name'" |
|
return 1 |
|
} |
|
|
|
inside "$rname" "$MYNAME" wait-for-boot || { |
|
error "Failed to wait for $name to boot" |
|
return 1 |
|
} |
|
|
|
if [ "$install_deps" != "false" ]; then |
|
# install deps |
|
inside "$rname" "$MYNAME" install-deps || { |
|
error "Failed to install deps in $name." |
|
return 1 |
|
} |
|
fi |
|
|
|
_RET="$name" |
|
} |
|
|
|
main() { |
|
local short_opts="hi:r:v" |
|
local long_opts="help,name:,remote:,image:,verbose" |
|
local getopt_out="" |
|
getopt_out=$(getopt --name "${0##*/}" \ |
|
--options "${short_opts}" --long "${long_opts}" -- "$@") && |
|
eval set -- "${getopt_out}" || |
|
{ bad_Usage; return; } |
|
|
|
local cur="" next="" image="" buildu="build" |
|
local name="" remote="local" rname="" |
|
|
|
while [ $# -ne 0 ]; do |
|
cur="$1"; next="$2"; |
|
case "$cur" in |
|
-h|--help) Usage ; exit 0;; |
|
-i|--image) image="$next"; shift;; |
|
-R|--remote) remote="$next"; shift;; |
|
-v|--verbose) VERBOSITY=$((VERBOSITY+1));; |
|
--name) name="$next"; shift;; |
|
--) shift; break;; |
|
esac |
|
shift; |
|
done |
|
|
|
[ $# -eq 0 ] && set -- . |
|
|
|
assert_ctool || fail |
|
|
|
local pkg_d="$1" topd="" |
|
shift |
|
|
|
local build_args="" |
|
build_args=( "$@" ) |
|
|
|
specdir_info "${pkg_d}" || return 1 |
|
spec=${_RET_SPEC} |
|
topd=${_RET_TOPD} |
|
|
|
debug 0 "Building $spec in $topd" |
|
|
|
start_container "$remote" "$name" "$image" || { |
|
error "Failed to start container from $image on $remote" |
|
return 1 |
|
} |
|
name="$_RET" |
|
rname="$remote:$name" |
|
|
|
# if we can get sources externally... just try |
|
local gotsource=false |
|
"$0" get-sources "$topd" && gotsource=true || |
|
debug 0 "failed to get sources outside. will try again inside." |
|
|
|
# add the user ('build'). it gets sudo access also. |
|
ctool add-user "--container=$rname" "$buildu" || { |
|
error "Failed to add user $buildu" |
|
return 1 |
|
} |
|
|
|
# copy source in from topd |
|
local bname="${topd##*/}" |
|
debug 1 "copying source to $rname" |
|
tar -C "$topd/.." -cf - "${bname}/" | |
|
ctool execute "--container=$rname" "--user=$buildu" tar -xf - || { |
|
error "Failed to copy source into $name from $topd" |
|
return |
|
} |
|
|
|
local ctopd="/home/$buildu/$bname" |
|
|
|
# install per-package build-deps |
|
inside "$rname" "$MYNAME" install-pkg-deps "$ctopd" || { |
|
error "Failed to install package deps" |
|
return 1 |
|
} |
|
|
|
local msg="to enter: ctool execute --container=$rname" |
|
msg="$msg --user=$buildu --dir=$ctopd" |
|
|
|
if [ "$gotsource" != "true" ]; then |
|
# get source files |
|
ctool execute "--container=$rname" "--user=$buildu" -- \ |
|
"$MYNAME" get-sources "$ctopd" || { |
|
error "Failed to get sources inside $name" |
|
error "$msg" |
|
return 1 |
|
} |
|
fi |
|
|
|
ctool execute "--container=$rname" "--user=$buildu" "--dir=$ctopd" -- \ |
|
"$MYNAME" build . "${build_args[@]}" || { |
|
error "Failed to build inside $name as $buildu in $ctopd" |
|
error "$msg" |
|
return 1 |
|
} |
|
|
|
ctool execute "--container=$rname" "--user=$buildu" "--dir=$ctopd" -- \ |
|
"$MYNAME" "copy-out" | tar -xf - || { |
|
error "Failed to copy build info out." |
|
return 1 |
|
} |
|
|
|
debug 0 "$msg" |
|
} |
|
|
|
copy_out() { |
|
local d="$1" |
|
specdir_info "$d" || return 1 |
|
local sourced="$_RET_SOURCES" spec="$_RET_SPEC" topd="$_RET_TOPD" |
|
local dirs="" f="" |
|
dirs=() |
|
for f in "$topd/"{SRPMS,RPMS,build.log}; do |
|
[ -e "$f" ] && dirs[${#dirs[@]}]="${f#$topd/}" |
|
done |
|
if [ "${#dirs[@]}" -eq 0 ]; then |
|
error "No build ouput found in $topd" |
|
return 1 |
|
fi |
|
|
|
tar -C "$topd" -cf - "${dirs[@]}" |
|
} |
|
|
|
make_snapshot() { |
|
local short_opts="hR:v" |
|
local long_opts="help,remote:,verbose" |
|
local getopt_out="" |
|
getopt_out=$(getopt --name "${0##*/}" \ |
|
--options "${short_opts}" --long "${long_opts}" -- "$@") && |
|
eval set -- "${getopt_out}" || |
|
{ bad_Usage; return; } |
|
|
|
local cur="" next="" buildu="build" |
|
local name="" remote="local" |
|
|
|
while [ $# -ne 0 ]; do |
|
cur="$1"; next="$2"; |
|
case "$cur" in |
|
-h|--help) Usage ; exit 0;; |
|
-R|--remote) remote=$next; shift;; |
|
-v|--verbose) VERBOSITY=$((${VERBOSITY}+1));; |
|
--) shift; break;; |
|
esac |
|
shift; |
|
done |
|
|
|
[ $# -lt 2 ] || { |
|
bad_Usage "got $# args, expected 0 or 1 ($*)" |
|
return 1 |
|
} |
|
|
|
local image="${1:-${DEFAULT_IMAGE}}" snapname="$2" |
|
local out="" rname="" |
|
[ -z "$snapname" ] && snapname="${SNAPSHOT_PREFIX}${image#*:}" |
|
|
|
assert_ctool || fail |
|
|
|
debug 0 "creating snapshot of $image -> $remote:$snapname" |
|
|
|
if out=$(lxc image show "$remote:$snapname" 2>&1); then |
|
error "image $remote:snapname exists, remove it first:" |
|
error " lxc image alias delete $remote:$snapname" |
|
return 1 |
|
fi |
|
|
|
start_container "$remote" "" "$image" || { |
|
error "Starting container failed (image=$image)" |
|
return 1 |
|
} |
|
name="$_RET" |
|
rname="$remote:$name" |
|
|
|
lxc stop "$rname" || { |
|
error "Failed to stop $name" |
|
return 1 |
|
} |
|
|
|
debug 1 "publishing $rname -> $remote as $snapname" |
|
lxc publish "$rname" "$remote:" "--alias=$snapname" || { |
|
error "failed: lxc publish $name --alias=$snapname" |
|
return 1 |
|
} |
|
|
|
debug 0 "Published updated image of $image as $remote:$snapname" |
|
lxc delete --force "$rname" |
|
} |
|
|
|
assert_ctool() { |
|
command -v ctool >/dev/null || { |
|
local url="https://github.com/canonical/uss-tableflip/blob/master/doc/ctool.md" |
|
error "no ctool. Get it. its useful." |
|
error "$url" |
|
return 1 |
|
} |
|
} |
|
|
|
case "$1" in |
|
copy-out|\ |
|
install-deps|install-pkg-deps|get-sources|wait-for-boot|build|make-snapshot) |
|
fn=${1//-/_} |
|
shift |
|
"$fn" "$@" |
|
;; |
|
*) main "$@";; |
|
esac |
|
|
|
# vi: ts=4 expandtab |