#!/bin/bash log() { echo $@ } goodbye() { : rm -f $tmp_mkdef_sh scm_status.tmp } quit() { goodbye exit $1 } usage() { cat << EOT | sed 's/^ |//' |usage: $myname cmd EOT [ "$1" ] && { quit $1 } } fatal() { log "$@" log "Giving up." quit 1 } os() { /bin/bash $MOD_SCRIPT_DIR/get_os.sh } scm_commit() { case $SCM in cvs) cvs commit "$@" ;; git) git commit -uno "$@" ;; *) fatal "tried to commit with unknown source code management tool $SCM" ;; esac } platform() { echo `os`/$RPM_ARCH } abspath() { (cd $1; /bin/pwd) } read_map() { cmd_version -p `platform` $@ read | sed 's/-dev//' } write_map() { cmd_version -p `platform` $1 write $2 } find_path() { local p for p in $@; do [ -e "$p" ] && { echo $p return 0 } done fatal "none of the paths \"$@\" exists" } scm_files() { ( cd $TOPDIR /bin/bash $MOD_SCRIPT_DIR/list-cvs-files.sh -f ) } calculate_hash() { ( cd $TOPDIR scm_files | \ grep -v "CHANGES\|VERSION\|HASH\|MD5SUMS\|_RPM_RUN" | \ xargs md5sum | md5sum | sed 's/ .*//' ) } check_scm() { if [ -d .git ]; then log + checking git git pull --no-edit || fatal "git pull failed, giving up" git status --porcelain | grep -v '^??' | grep -q . && { git status fatal "git has locally modified files, giving up" } else log + checking cvs cvs update -dP cvs status > scm_status.tmp 2>&1 if [ $? != 0 ]; then cat scm_status.tmp fatal "\n======== cvs status failed, giving up." fi grep -qi "locally modified" scm_status.tmp && \ fatal "cvs copy has locally modified files, giving up" grep -qi "needs" scm_status.tmp && \ fatal "+ cvs copy is out-of-date, giving up" fi } check_cwd() { pwd | grep -q $HOME/local/src } create_empty_dir() { [ $# != 2 ] && \ fatal "Unable to create empty directory \"$@\"." local dir="$1" shift local desc="$@" mkdir -p "$dir" [ -w "$dir" ] || fatal "No write-access to $desc \"$dir\"" [ `ls "$dir" | wc -l` -eq 0 ] || fatal "$desc \"$dir\" isn't empty" } increase_build_no() { local build_no=`echo $1 | sed 's/.*-\([0-9]\+\)\(-dev\)*/\1/'` build_no=`expr $build_no + 1` echo $1 | sed "s/-\([0-9]\+\)\(-dev\)*/-$build_no\2/" } check_next_version() { local v=`read_map $TOPDIR/VERSION | sed 's/-dev//'` local n=`read_map -n $TOPDIR/LAST_RPM_VERSION | sed 's/-dev//'` if [ "$n" != "$v" ]; then echo "+ $RPM_PROJECT version is already at $v, no need to increase for release" >&2 echo $v return fi local h=`calculate_hash` if [ ! -f $TOPDIR/HASH ]; then echo "+ $RPM_PROJECT has no HASH file, needs release" >&2 echo $v return fi if ! read_map $TOPDIR/HASH | grep -q $h; then echo "+ $RPM_PROJECT has no matching HASH value, needs release" >&2 increase_build_no $v return fi echo "+ $RPM_PROJECT has unchanged source" >&2 if [ "$reinstall_check_failed" = 1 ]; then echo "version $v is uninstallable, needs release" >&2 increase_build_no $v return fi if [ "$reinstall_check_succeeded" = 1 ]; then echo $v return fi if ! check_pkg_reinstall >&2; then echo "version $v is uninstallable, needs release" >&2 increase_build_no $v return fi echo "version $v doesn't match any release criteria, not releasing" >&2 echo $v } check_pkg_install() { [ "$1" = -c ] && { shift [ ! -f "$1" ] && return 0 } echo "+ installing $1" sudo $RPM -U $1 || { echo "failed to install $1" return 1 } } check_pkg_reinstall() { local v=`read_map $TOPDIR/VERSION` local s for s in devel run; do if $RPM -q $RPM_PROJECT-$s > /dev/null 2>&1 ; then echo + removing $RPM_PROJECT-$s sudo $RPM -e $RPM_PROJECT-$s --nodeps --allmatches || { echo "failed to uninstall $RPM_PROJECT-$s, ignored" } fi done local suffix case "$PKG_FORMAT" in rpm) suffix=-$v.$RPM_ARCH.rpm ;; *) suffix=_$v""_$RPM_ARCH.deb ;; esac check_pkg_install $TOPDIR/$DIST_PCKG_DIR/$RPM_PROJECT-run$suffix || return 1 check_pkg_install -c $TOPDIR/$DIST_PCKG_DIR/$RPM_PROJECT-devel$suffix || return 1; } check_release_is_current() { local reinstall_pkg= local next=`check_next_version` local v=`read_map $TOPDIR/VERSION` set -- `getopt 'r' $*` while [ "$1" != -- ] ; do case "$1" in -r) reinstall_pkg=1 ;; esac shift done shift if ! read_map -n $TOPDIR/LAST_RPM_VERSION | grep -Fq $next; then echo "next version $next is not in LAST_RPM_VERSION, needs release" >&2 return 1 fi if [ "$reinstall_pkg" ]; then if ! check_pkg_reinstall; then echo "version $v is uninstallable, needs release" >&2 reinstall_check_failed=1 return 1 fi reinstall_check_succeeded=1 fi return 0 } check_update_version() { ( cd $TOPDIR local v=`read_map VERSION` local next=`check_next_version` if [ "$next" != "$v" ]; then echo "$next-dev" > VERSION scm_commit -m "o $next" VERSION return 0 fi return 1 ) } cmd_version() { cmd_version_usage() { cat <<- EOT | sed 's/ |//' |usage: $myname version filename cmd [args] EOT [ "$1" ] && exit $1 } cmd_version_strip_dev_dummy() { cat } cmd_version_strip_dev_real() { sed 's/-dev//' } # -- here we go local strip_dev=cmd_version_strip_dev_dummy local platform_patt="\(^debian-[0-9.]\+\|^suse-[0-9.]\+\)/\(i.86\|x86_64\|amd64\): *" local no_compat= local platform=`platform` [ $# -lt 2 ] && cmd_version_usage 1 set -- `getopt 'hsnp:' "$@"` while [ "$1" != -- ] ; do case "$1" in -n) no_compat=true;; -s) strip_dev=cmd_version_strip_dev_real;; -p) platform="$2"; shift;; -h) cmd_version_usage 0;; *) cmd_version_usage 1;; esac shift done shift local file="$1" shift local cmd=$1 shift case $cmd in read) local p=`echo $platform | sed 's%/%\\\/%g'` local v=`sed "/$p:/ !d; s/$p: *//" $file` [ "$v" ] && { echo "$v" | $strip_dev return } [ "$no_compat" = true ] && { return } grep -q "$platform_patt" $file || { cat $file | $strip_dev return } local pp=`echo $platform_patt | sed 's%/%\\\/%g'` sed "/$pp/ !d; s/$pp//; 2,$ d" $file | $strip_dev ;; write) local val=$1 local p=$platform [ -f $file ] || { echo "$p: $val" > $file return } grep -q "$platform_patt" $file || { echo "$p: $val" > $file return } grep -q "^$p:" $file || { echo "$p: $val" >> $file return } p=`echo $p | sed 's%/%\\\/%g'` val=`echo $val | sed 's%/%\\\/%g'` sed "s/$p:.*/$p: $val/" $file > $file.tmp mv $file.tmp $file ;; *) echo unknown command $cmd >&2 cmd_version_usage 1;; esac } build_pkg() { set -e local version=`read_map $TOPDIR/VERSION | sed 's/-dev//'` local src_base=$RPM_PROJECT-$version local src_tree=$DIST_SRC_DIR/$src_base local tar_archive=$src_base.tar.bz2 local tar_archive_orig=$src_base.orig.tar.bz2 local distribution=`os` local RPM_REQUIRES_RUN=`echo $RPM_REQUIRES_RUN | sed "s/__NEXT_VERSION__/$version/g"` local RPM_REQUIRES_DEVEL=`echo $RPM_REQUIRES_DEVEL | sed "s/__NEXT_VERSION__/$version/g"` # --- create source directory tree create_empty_dir $src_tree "Source files compilation directory" # --- copy source files over scm_files | grep -v VERSION | cpio -o -H newc | ( cd $src_tree; cpio --make-directories -i) echo $version > $src_tree/VERSION local pkgfmt for pkgfmt in $PKG_FORMAT; do local deffmt case $pkgfmt in rpm) deffmt=spec;; debian|deb) deffmt=debian;; *) ;; esac # --- generate spec file local mkdef_sh=$TOPDIR/make/mk$deffmt.sh local mkdef_wrapper_sh=$MOD_SCRIPT_DIR/mkspec_wrapper.sh [ ! -r $mkdef_wrapper_sh ] && \ fatal "Failed to read package definition deffmt wrapper script \"$mkdef_wrapper_sh\"." scm_files | grep -q make/mk$deffmt.sh || { local create_mkdef_sh=$MOD_SCRIPT_DIR/create-mk$deffmt.sh [ ! -r "$PROJECT_DESCR_FILE" ] && \ fatal "Failed to read project description file \"$PROJECT_DESCR_FILE\"." [ ! -r "$create_mkdef_sh" ] && \ fatal "Failed to read package build definition creation script \"$create_mkdef_sh\"." /bin/bash $create_mkdef_sh $PROJECT_DESCR_FILE > $mkdef_sh.tmp mv $mkdef_sh.tmp $mkdef_sh tmp_mkdef_sh="$tmp_mkdef_sh $mkdef_sh" } mkdef_sh=`readlink -f $mkdef_sh` mkdef_wrapper_sh=`readlink -f $mkdef_wrapper_sh` ( cd $src_tree /bin/bash $mkdef_wrapper_sh $mkdef_sh \ -V $version \ -S $tar_archive \ -N $RPM_PROJECT \ -R "$RPM_REQUIRES_RUN" \ -D "$RPM_REQUIRES_DEVEL" \ -P $PROJECT \ -d $distribution \ > $RPM_PROJECT.$deffmt ) done # --- tar up source directory tree create_empty_dir $DIST_PCKG_DIR "Package directory" local excluded=`find $TOPDIR -name '*.in' | sed "s/\.in$//; s%$DIST_SRC_DIR%%; s%^[./]*%%; s/^/--exclude /g"` tar --anchored $addprefix $excluded \ -czvf $DIST_PCKG_DIR/$tar_archive -C $DIST_SRC_DIR `basename $src_tree` case "$PKG_FORMAT" in rpm) # --- build RPMs and copy them to source directory rpmbuild -ta $DIST_PCKG_DIR/$tar_archive cp $SRPMS_DIR/$src_base.src.rpm $DIST_PCKG_DIR/ cp $RPMS_DIR/$RPM_PROJECT-*-$version.$RPM_ARCH.rpm $DIST_PCKG_DIR/ ;; *) #exit #cp $DIST_PCKG_DIR/$tar_archive $src_tree/../$tar_archive_orig ( local mod_script_dir=`readlink -f $MOD_SCRIPT_DIR` cd $src_tree #export ENV_PREFIX=`readlink -f $TOPDIR`/$DIST_INST_DIR #export INSTALL_LOG=blah #strace -f -s 128 -o /tmp/strace.out debuild --no-tgz-check --prepend-path=$mod_script_dir -us -uc debuild --no-tgz-check --prepend-path=$mod_script_dir -us -uc ) cp $DIST_SRC_DIR/*.deb $DIST_PCKG_DIR/ ;; esac } upload_file() { local f=$1 local t=$2 local upload_spec=644:755:`id -un`.207 if [ ! -f $DIST_PCKG_DIR/$f ]; then echo "+ $DIST_PCKG_DIR/$f doesn't exit, skipping" >&2 return 1 fi local os_name=`os | sed 's/-.*//'` local os_version=`os | sed 's/[^-]\+-//'` local target_base=rsync_ssh://root@ftp.jannet.de:/srv/ftp/pub/packages/linux/$os_name/$os_version local target if [ "$t" = tgz ]; then target=$target_base/inst-source/$t/$f:$upload_spec else target=$target_base/inst-source/rpm/$t/$f:$upload_spec fi echo "+ uploading $target" sh $MOD_SCRIPT_DIR/upload.sh $DIST_PCKG_DIR/$f $target } upload_pkg() { local server set -e local p local v=`read_map $TOPDIR/VERSION | sed 's/-dev//'` local h=`calculate_hash` case $PKG_FORMAT in rpm) server=ftp.jannet.de upload_file $RPM_PROJECT-$v.tar.bz2 tgz upload_file $RPM_PROJECT-$v.src.rpm src upload_file $RPM_PROJECT-run-$v.$RPM_ARCH.rpm $RPM_ARCH upload_file $RPM_PROJECT-devel-$v.$RPM_ARCH.rpm $RPM_ARCH || true ;; debian|deb) server=apt.janware.com local conf=`mktemp "/tmp/$myname"_XXXXXX` cat <<-EOT > $conf [DEFAULT] default_host = janware-debian [janware-debian] fqdn = $server # login = incoming = /srv/ftp/pub/packages/all/debian/mini-dinstall/incoming/ method = rsync hash = sha allow_unsigned_uploads = yes distributions = debian-8 allowed_distributions = `os` delayed = run_lintian = no run_dinstall = no check_version = yes passive_ftp = yes #progress_indicator scp_compress = yes ssh_config_options = ForwardAgent=yes,Compression=yes,ServerAliveInterval=30,ConnectTimeout=120 #post_upload_command = #pre_upload_command = #default_host_main = EOT dput -c $conf janware-debian dist/src/"$RPM_PROJECT"_"$v"_"$RPM_ARCH".changes rm -f $conf ;; *) fatal "Tried to upload with unknown package format \"$PKG_FORMAT\"" ;; esac write_map $TOPDIR/LAST_RPM_VERSION $v $SCM add $TOPDIR/LAST_RPM_VERSION || true write_map $TOPDIR/HASH $h $SCM add $TOPDIR/HASH || true echo "+ scheduling rebuild" $SSH -l root $server /opt/packager-server/bin/packager-server schedule-rebuild scm_commit -m "o $v@`platform`" $TOPDIR/LAST_RPM_VERSION $TOPDIR/HASH if [ "$SCM" = git ]; then git push || true fi } cmd_build() { build_pkg } cmd_upload() { upload_pkg } cmd_log_install() { local args="$*" local c_format=rpm local c_logfile=install.log local c_mode_dir=false local c_group=`id -gn` local c_owner=`whoami` local c_suffix= local c_prefix= local c_opmode=opmode_install local c_absolute=0 set -- `getopt 'Li:a:f:l:bg:cdm:o:psS:vA' $*` cfgfile_macro() { if echo "$*" | grep -qe '/etc/\|\.conf$'; then echo "%config(noreplace) " fi } while [ "$1" != -- ]; do case $1 in -f) c_format=$2 shift;; -l) c_logfile=$2 shift;; -a) c_use_attr=true ;; -i) c_ignore_prefix=$2 shift ;; -b) ;; -c) ;; -d) c_mode_dir=true;; -D) ;; -g) c_group=$2 shift;; -m) c_mode=$2 shift;; -o) c_owner=$2 shift;; -p) ;; -s) ;; -S) c_suffix=$2 shift;; -v) ;; -L) c_opmode=opmode_link;; -A) c_absolute=1;; *) echo unknown option \"$1\". Exiting. >&2 exit 1;; esac shift done shift local args="`echo " $args" | sed -e 's/ -l *[^ ]*//g; s/ -f *[^ ]*//g; s/\b-a\b//g;'`" if [ -z "$c_use_attr" ]; then #args="`echo " $args" | sed -e 's/ -g *[^ ]*//g; s/ -m *[^ ]*//g; s/ -o *[^ ]*//g;'`" args="`echo " $args" | sed -e 's/ -g *[^ ]*//g; s/ -o *[^ ]*//g;'`" fi local c_target="`echo $* | rev | cut -d' ' -f1 | rev`" local c_source="`echo $* | rev | cut -d' ' -f2- | rev`" case $c_opmode in opmode_install) if [ -L "$c_source" ]; then cp -d $c_source $c_target || exit $? else install $args || exit $? fi ;; opmode_link) if [ "$c_mode_dir" = true ]; then echo "ignoring directory $c_source during link creation" exit 0 fi if [ "$c_absolute" != 0 ]; then c_logfile="" c_source=`readlink -f $c_source` else c_source=`basename $c_source` fi cd `dirname $c_target` ln -sf $c_source `basename $c_target` ;; *) echo "Mode \"$c_opmode\" not implemented. Exiting." >&2 exit 1 ;; esac [ "$c_logfile" ] || { exit 0 } local file mode installd_file cfgfile dir if [ "$c_mode_dir" = true ]; then for file in $*; do echo "%dir %attr($c_mode,$c_owner,$c_group) $file" >> $c_logfile done else if [ -d "$c_target" ]; then for file in $c_source; do installed_file="$c_target/`basename $file`" cfgfile="" mode if [ "$c_mode" ]; then mode=$c_mode cfgfile=`cfgfile_macro "$installed_file"` else if [ -d "$file" ]; then dir="%dir " mode=0755 else cfgfile=`cfgfile_macro "$installed_file"` dir="" mode=0644 fi fi echo "$dir%attr($mode,$c_owner,$c_group) $cfgfile$installed_file" | sed "s/^$c_ignore_prefix//" >> $c_logfile done else installed_file="$c_target" cfgfile="" if [ "$c_mode" ]; then mode=$c_mode cfgfile=`cfgfile_macro "$installed_file"` else if [ -d "$c_source" ]; then dir="%dir " mode=0755 else cfgfile=`cfgfile_macro "$installed_file"` dir="" mode=0644 fi fi echo "$dir%attr($mode,$c_owner,$c_group) $cfgfile$c_target" | sed "s/^$c_ignore_prefix//" >> $c_logfile fi fi } cmd_milk_install_log() { milk_install_log_usage() { echo "usage: $myname [-h] [-n pkg-name] [-t rpm|deb] [-p remove-prefix] install-log output-dir" [ "$1" ] && exit $1 } milk_install_log_spec_attr() { local attr=$1 shift #echo "extracting attribute $attr from \"$@\"" >&2 echo "$*" | sed "s/.*attr(\([0-9]\+\),\([^,]\+\),\([^,)]\+\)).*/\\$attr/" } milk_install_log_init_postinst() { cat <<- EOT > $1 #!/bin/sh EOT chmod 755 $1 } local type name prefix in out set -- `getopt ht:p:n: "$@"` while [ "$1" != -- ]; do case $1 in -h) usage 0;; -t) type="$2"; shift;; -n) name="$2"; shift;; -p) prefix="$2"; shift;; *) milk_install_log_usage 1;; esac shift done shift [ $# != 2 ] && milk_install_log_usage 1 in=$1 out=$2 local filter_devel='/include/.*.h$\|devel\|make\|lib.*\.a$\|lib.*\.so$\|.*\.exp$\|.*\.def$\|.*\.lib$\|.*\.pc$' # TODO: simplify this case $type in rpm) cat $in | sed "s% $prefix% %" | grep -ve $filter_devel > $in.$name-run cat $in | sed "s% $prefix% %" | grep -e $filter_devel > $in.$name-devel ;; deb) cat $in | grep -v "%dir" | sed "s% $prefix% %; s%//*%/%g; s/.*) *//" | grep -ve $filter_devel | sed 's/\(.*\)\/\([^/]\+\) *$/inst-root\1\/\2 \1/' > $out/$name-run.install cat $in | grep -v "%dir" | sed "s% $prefix% %; s%//*%/%g; s/.*) *//" | grep -e $filter_devel | sed 's/\(.*\)\/\([^/]\+\) *$/inst-root\1\/\2 \1/' > $out/$name-devel.install cat $in | grep "%dir" | sed "s% $prefix% %; s%//*%/%g; s/.*) *//" | grep -ve $filter_devel | sed 's/\(.*\)\/\([^/]\+\) *$/\1\/\2/; s%^/%%' | sort -u > $out/$name-run.dirs cat $in | grep "%dir" | sed "s% $prefix% %; s%//*%/%g; s/.*) *//" | grep -e $filter_devel | sed 's/\(.*\)\/\([^/]\+\) *$/\1\/\2/; s%^/%%' | sort -u > $out/$name-devel.dirs #cat $in | sed "/%config/ !d; s% $prefix% %; s%//*%/%g; s/.*) *//" | grep -ve $filter_devel > $out/conffiles cat $in | sed "/%config/ !d; s% $prefix% %; s%//*%/%g; s/.*) *//" | grep -ve $filter_devel > $out/conffiles.$name-run cat $in | sed "/%config/ !d; s% $prefix% %; s%//*%/%g; s/.*) *//" | grep -e $filter_devel > $out/conffiles.$name-devel for p in run devel; do postinst=$out/$name-$p.postinst milk_install_log_init_postinst $postinst cat $out/$name-$p.dirs $out/$name-$p.install | grep . | while read file dir; do #echo read file \"$file\" >&2 file=`echo /$file | sed 's/inst-root\///; s%^//*%/%'` #echo file is now \"$file\" >&2 #echo grep \"$prefix/*$file$\" $in >&2 line=`grep $file$ $in` perm=`milk_install_log_spec_attr 1 "$line"` owner=`milk_install_log_spec_attr 2 "$line"` group=`milk_install_log_spec_attr 3 "$line"` echo "chown $owner:$group $file" >> $postinst echo "chmod $perm $file" >> $postinst done done ;; *) milk_install_log_usage 1 ;; esac } # ---- here we go umask 0022 trap goodbye SIGINT SIGKILL # -- default values TOPDIR=. MOD_SCRIPT_DIR=/opt/ytools/bin CHECK_CVS_SYNC_BEFORE_RPM_RELEASE=false #LAST_RPM_VERSION=`read_map $TOPDIR/LAST_RPM_VERSION` myname=`basename $0` tmp_mkdef_sh="" PROJECT_DESCR_FILE=$TOPDIR/make/project.conf DIST_SRC_DIR=dist/src DIST_INST_DIR=dist/src DIST_PCKG_DIR=dist/pckg PROJECT=`abspath $TOPDIR | xargs basename` RPM_PROJECT="$PROJECT" RPM_REQUIRES_RUN="" RPM_REQUIRES_DEVEL="" RPM_ARCH=`arch` PKG_FORMAT=rpm SSH=ssh SCM=cvs [ "$RSYNC_RSH" ] && SSH=$RSYNC_RSH [ "$CVS_RSH" ] && SSH=$CVS_RSH [ -d .git ] && SCM=git opts='ht:p:m:N:R:D:P:a:F:' args=("$@") while [ "$1" ]; do [ ${#1} = 2 -a ${1:0:1} = - ] && echo $opts | grep -q "${1:1}" && { echo $opts | grep -q "${1:1}" && shift shift continue } break done cmd=$1 set -- "${args[@]}" set -- "${@/$cmd/--}" while [ "$1" != -- ] ; do case "$1" in -h) usage 0;; -t) eval DIST_SRC_DIR=\"$2\" shift ;; -p) eval DIST_PCKG_DIR=\"$2\" shift ;; -m) eval MOD_SCRIPT_DIR=\"$2\" shift ;; -N) eval RPM_PROJECT=\"$2\" shift ;; -R) eval RPM_REQUIRES_RUN=\"$2\" shift ;; -D) eval RPM_REQUIRES_DEVEL=\"$2\" shift ;; -P) eval PROJECT=\"$2\" shift ;; -a) eval RPM_ARCH=\"$2\" shift ;; -F) eval PKG_FORMAT=\"$2\" shift ;; esac shift done shift SRPMS_DIR=`find_path $HOME/rpmbuild/SRPMS /usr/src/packages/SRPMS` RPMS_DIR=`find_path $HOME/rpmbuild/RPMS/$RPM_ARCH /usr/src/packages/RPMS/$RPM_ARCH` # shift [ ! "$cmd" ] && usage 1 case $PKG_FORMAT in rpm) RPM=/bin/rpm ;; deb|debian) RPM="/bin/bash $MOD_SCRIPT_DIR/dpm.sh" ;; *) fatal "Unknown package format \"$PKG_FORMAT\"" ;; esac case $cmd in check-release) cmd_check_release ;; need-release) if check_release_is_current; then echo no >&2 exit 1 else echo yes >&1 exit 0 fi ;; update-version) check_update_version || exit 0 ;; version) eval cmd_version "$@" ;; build) check_cwd rm -rf ./$DIST_SRC_DIR ./$DIST_PCKG_DIR cmd_build ;; release-reinstall) check_update_version cmd_build cmd_upload ;; release) cd $TOPDIR check_scm check_release_is_current -r || { set -e check_cwd rm -rf ./$DIST_SRC_DIR ./$DIST_PCKG_DIR check_update_version || true cmd_build check_pkg_reinstall cmd_upload } ;; upload) cmd_upload ;; reinstall) check_pkg_reinstall ;; release) ;; hash) calculate_hash ;; log-install) eval cmd_log_install "$@" ;; milk-install-log) eval cmd_milk_install_log "$@" ;; *) usage 1 ;; esac goodbye