#!/bin/bash # (c) 2005, 2006, 2007, 2008, 2009, 2010 Miklos Vajna # repoman for Frugalware # distributed under GPL License usage() { man repoman } msg() { echo -e "\033[1;32m==>\033[1;0m \033[1;1m$1\033[1;0m" >&2 } dry_run() { if [ -z "$dryrun" ]; then eval "$*" return $? else echo $* fi } check_servers() { server=$(eval "echo \$${reponame}_servers") if [ "$F_makepkg_scm" = "git" ]; then _server=`GIT_DIR=$fst_root/$reponame/.git git config --get remote.origin.url 2>/dev/null` if echo $_server |grep -q :/[^/]; then server=$_server fi else if [ -f "$fst_root/$reponame/_darcs/prefs/defaultrepo" ]; then server="`cat $fst_root/$reponame/_darcs/prefs/defaultrepo`" fi fi if echo $server |grep -q :/[^/]; then host=${server%:*} path=${server#*:} else die "The first server in the $reponame repo is read-only, please update the list of servers." fi } check_sudo() { sudouser=$(eval "echo \$${reponame}_sudo") if [ -n "$sudouser" ]; then sudo_cmd="sudo -E -H -u $sudouser" else sudo_cmd="" fi } get_root() { local i if [ "$F_makepkg_scm" = "git" ]; then i=`git rev-parse --git-dir 2>/dev/null` echo `dirname $i` else i=`pwd` while true do if [ -e "$i/_darcs" ]; then break elif [ "$i" == "" ]; then break fi i=`echo $i|sed 's|\(.*\)/.*|\1|'` done echo $i fi } check_absolute_path() { if [ "${path:0:1}" != "/" ]; then echo "Please use absolute paths in repoman.conf!" exit 1 fi } server() { local i case "$1" in delete) shift if [ $# -lt 3 ]; then echo "Too few parameters!" echo "usage: repoman server delete opts path file1 [file2..]" return fi local verbose="$1" path="$2" shift 2 check_absolute_path cd $path if [ -e .git/lock ]; then echo "Couldn't get lock." return fi if [ -n "$verbose" ]; then rmopts="-v" else rmotps="" fi for i in "$@" do # strip leading / and any .. target=`echo $i|sed 's|^/||;s|\.\./||g'` if [ -d "$target" ]; then rmdir $rmopts $target else rm $rmopts $target fi done ;; mktemp) shift local tmp="`mktemp -p /var/tmp 2>/dev/null`" if [ -z "$tmp" ]; then echo "Failed to get a temporary file :-/" >&2 else chmod 664 $tmp echo $tmp fi ;; upload) shift if [ $# -lt 4 ]; then echo "Too few parameters!" echo "usage: repoman server upload path yourtmpfile sha1 targetfile" return fi local path="$1" tmp="$2" sha="$3" dest="$4" shift 4 check_absolute_path cd $path if [ -e .git/lock ]; then echo "Couldn't get lock." return fi if ! echo "$sha $tmp" |sha1sum -c - >/dev/null 2>&1; then echo "The uploaded file is corrupted :-/" rm $tmp return fi # strip leading / and any .. mv -f $tmp "`echo $dest|sed 's|^/||;s|\.\./||g'`" ;; list) shift if [ $# -lt 2 ]; then echo "Too few parameters!" echo "usage: repoman server list path file1 [file2..]" return fi local path="$1" shift check_absolute_path cd $path for i in "$@" do # strip leading / and any .. ls "`echo $i|sed 's|^/||;s|\.\./||g'`" done ;; changelog) shift if [ $# -lt 5 ]; then echo "Too few parameters!" echo "usage: repoman server changelog path fdb group pkg arch" return fi local path="$1" fdb="$2" group="$3" pkg="$4" arch="$5" shift 5 check_absolute_path cd $path if [ -e .git/lock ]; then echo "Couldn't get lock." return else touch .git/lock fi if ! cd source/$group/$pkg; then echo "There is no package with this group!" rm -f .git/lock return fi startdir=`pwd` if ! source FrugalBuild; then echo "Failed to parse the FrugalBuid!" rm -f $(git rev-parse --show-cdup)/.git/lock return fi cd - >/dev/null cd frugalware-$arch if ! _check_nobuild; then if [ ! -e $fdb ]; then if ! arch=$arch gensync ../source/$group/$pkg $fdb; then echo "gensync failed!" rm ../.git/lock return fi else if ! arch=$arch updatesync upd $fdb ../source/$group/$pkg/FrugalBuild; then echo "updatesync failed!" rm ../.git/lock return fi fi fi rm ../.git/lock cd ../source/$group/$pkg arch=$arch genchangelog ;; clean) shift if [ $# -lt 4 ]; then echo "Too few parameters!" echo "usage: repoman server clean path fdb group pkg" return fi local path="$1" fdb="$2" group="$3" pkg="$4" check_absolute_path cd $path if [ -e .git/lock ]; then echo "Couldn't get lock." return else touch .git/lock fi for i in frugalware-* do cd $i if ! _check_nobuild; then if [ ! -e $fdb ]; then echo "No package database to clean from!" cd - >/dev/null rm -f .git/lock return else if ! arch=$arch updatesync del $fdb $pkg; then echo "updatesync failed!" rm -f .git/lock return fi fi fi genchangelog --clean $pkg cd - >/dev/null done rm .git/lock if [ -d source/$group/$pkg ]; then if [ ! -f source/$group/$pkg/FrugalBuild ]; then rm -rfv source/$group/$pkg else git clean -x -d -f source/$group/$pkg fi fi ;; rsync) shift if [ $# -lt 3 ]; then echo "Too few parameters!" echo "usage: repoman server rsync path src arch" return fi local path="$1" srcurl="$2" arch="$3" shift 3 check_absolute_path cd $path cd frugalware-$arch rsync -avP `echo $srcurl|sed 's/^.*@//'`/frugalware-$arch/*.fpm ./ ;; *) echo "Unknown server command!" ;; esac } delete() { if ! ask "repoman del $*"; then return fi local files rmopts host verbose check_servers check_sudo if [ "$verbose" != 0 ]; then verbose="y" else verbose="" fi msg "Deleting file(s): $*" $repoman_ssh $host "$sudo_cmd repoman server delete '$verbose' '$path' $*" } upload() { if [ "$#" -lt 2 ]; then echo "Too few parameters!" usage exit 1 fi if ! ask "repoman upload $*"; then return fi check_servers check_sudo dest=${@:$#} for src in "${@:1:$#-1}" do if echo $src |grep -q fpm$ && ! LANG= LC_ALL= pacman-g2 -Qi -p $src |grep -q "^Build Type.*chroot$"; then echo "$src is not built in chroot. Remove the -H option" echo "from your makepkg commandline switches, rebuild your" echo "package and try again." exit 1 fi if echo $src | grep -q fpm$ && pacman-g2 -Ql -p $src | egrep -q ' lib64/| usr/lib64/'; then echo "$src has invalid lib64 path , refusing to upload!" echo "Please fix your package." exit 1 fi if echo $src | grep -q fpm$ && pacman-g2 -Ql -p $src | grep -q 'var/tmp/fst'; then echo "$src has broken DESTDIR , files are installed" echo "in DESTDIR/DESTDIR , refusing to upload!" echo "Please fix your package." exit 1 fi if echo $src | grep -q fpm$ && pacman-g2 -Ql -p $src | grep -q 'usr/etc'; then echo "$src has invalid etc path , files are installed" echo "in /usr/etc , refusing to upload!" echo "Please fix your package." exit 1 fi name=`basename $src` msg "Requesting a temporary file" tmp=`$repoman_ssh $host "$sudo_cmd repoman server mktemp"` [ -z "$tmp" ] && exit 1 if [ "$REPOMAN_USE_TUNNEL" == "yes" ]; then ## Fix me ? well since we use something like: ## local -> genesis ( genesis acts like tunnel for itself ) ## or remote_box -> genesis , local -> remote_box we are always ## using 127.0.0.1 .. scp -S really sucks and I get a lot problems ## with rsync -e with all this tunneling =) ## the other solution may be to force host when tunnel is used to be user@127.0.0.1 ## since -p user@local gives out user@genesis .. msg "Uploading file: $src (to $tmp) over local tunnel." $repoman_scp $src 127.0.0.1:$tmp else msg "Uploading file: $src (to $tmp)" $repoman_scp $src $host:$tmp fi sha=`sha1sum $src|sed 's/\(.*\) .*/\1/'` $repoman_ssh $host "$sudo_cmd repoman server upload '$path' '$tmp' '$sha' '$dest/$src'" done } fpmmerge() { if [ ! "`type -p rsync`" ]; then die "The rsync program is missing. Please install it with pacman-g2 -S rsync." elif [ -z "$1" ]; then echo "fpmmerge needs a parameter! (a repo name to pull in fpms from)" usage exit 1 fi check_servers check_sudo srcurl=$(eval "echo \$$1_servers") if [ -z "$srcurl" ]; then die "so such repo!" fi # for each arch mergearchs="`rsync -vP $srcurl/|grep ^d.*frugalware-|sed 's/.* //'`" for i in $mergearchs do $repoman_ssh $host "$sudo_cmd repoman server rsync '$path' '${srcurl#*:}' '${i//frugalware-}'" done # now push dg push -a # finally run repoman cl for each arch and pkg for i in $mergearchs do for j in `$0 -t $1 ls /$i/ 2>/dev/null|sed 's/-[^-]\+-[^-]\+-[^-]\+$//'` do cd `git rev-parse --git-dir`/../source/*/$j 2>/dev/null || continue arch=${i//frugalware-} $0 -t $reponame -k cl $j done done } list() { check_servers check_sudo msg "Fetching contents of: $*" $repoman_ssh $host "$sudo_cmd repoman server list '$path' $*" } split_group_pkg() { if echo $1 |grep -q '^[^/]\+/[^/]\+$'; then group=${1%/*} pkg=${1#*/} else group=$groups pkg=$1 fi } clean() { check_servers check_sudo fdb=$(eval "echo \$${reponame}_fdb") [ -z "$fdb" ] && fdb="$reponame.fdb" for i in $* do msg "Cleaning up $i" split_group_pkg $i $repoman_ssh $host "$sudo_cmd repoman server clean '$path' '$fdb' '$group' '$pkg'" done } changelog() { if ! ask "repoman changelog $*"; then return fi msg "Generating Changelog for $1" split_group_pkg $1 check_servers check_sudo fdb=$(eval "echo \$${reponame}_fdb") [ -z "$fdb" ] && fdb="$reponame.fdb" $repoman_ssh $host "$sudo_cmd repoman server changelog '$path' '$fdb' '$group' '$pkg' '$arch'" } _keypress() { local old=$(stty -g) stty -icanon c=$(head -c1) stty "$old" echo $c } ask() { if [ -z "$noask" ]; then echo $* echo -n "Is this ok? [Y/n] " c=`_keypress` echo fi if [ -n "$noask" ] || [[ "(y|Y)?" =~ "$c" ]]; then return 0 else return 1 fi } ask_and_eval() { if [ -z "$noask" ]; then echo $* echo -n "Is this ok? [Y/n] " c=`_keypress` echo fi if [ -n "$noask" ] || [[ "(y|Y)?" =~ "$c" ]]; then eval "$*" fi } _check_nobuild() { # trick: we require subpkgs not to be set. this is because this way: # 1) kde-i18n and such pkgs (only the main pkg is a nobuild one) is # recognized as a normal pkg # 2) opera and friends (where we use nobuild is there because of # license issues) will be recognized as a nobuild one if echo ${options[@]} | grep -q nobuild && [ -z "$subpkgs" ]; then return 0 else return 1 fi } _do_record() { if [ "$F_makepkg_scm" = "git" ]; then git add -u . echo -e "$pkgname-$pkgver-$pkgrel-$arch $@" | git commit -F - else root="`_get_root`" echo -e "`LANG= LC_ALL= date +"%a %b %d %H:%M:%S %Z %Y"` `cat $root/_darcs/prefs/author` $pkgname-$pkgver-$pkgrel-$arch $@" | darcs rec -a --pipe . fi } __pkg_commit_info() { local commitmsg commitmsg="$pkgname-$pkgver-$pkgrel-$arch" msg "Your git commit command is:" msg "git commit -a -e -m $commitmsg" } commit_info() { __pkg_commit_info } record() { echo -n "Checking FrugalBuild... " if fblint &>/dev/null; then echo "OK" else echo "Failed" exit 1 fi if [ -n "$*" ]; then _do_record "$*" else if [ "$F_makepkg_scm" = "git" ]; then if ! git symbolic-ref -q HEAD >/dev/null; then echo echo "WARNING: Your HEAD is detached. In most cases you get into this state by running 'git pull --rebase', getting a conflict, but not resolving it. Run 'git status' to see the list of files which have conflicts, resolve them, run 'git add [ ...]', finally 'git rebase --continue' before you try to commit again. Continue without the steps above only in case you know what you are doing." echo fi dg what -s . ask_and_eval "dg record --edit-long-comment -m '$pkgname-$pkgver-$pkgrel-$arch' ." else darcs what -s . ask_and_eval "darcs record --edit-long-comment -m '$pkgname-$pkgver-$pkgrel-$arch' ." fi fi } # returns true if the file is a build log for some other arch (we should not remove them) _is_log() { local i for i in ${archs[@]} do [ $i = $arch ] && continue if echo $1 |grep -q "$i\.log\.bz2$"; then return 0 fi done return 1 } srcdel() { mydir=$(pwd|sed "s|$(get_root)||") for i in ${archs[@]} $arch do export CARCH=$i unset pkgver source for j in `set|grep ^_F_|sed 's/\(=.*\| ()\)//'`; do unset $j; done export startdir=`pwd` . ./FrugalBuild srclocal=(${srclocal[@]} ${source[@]}) done srclocal=(${srclocal[@]} ${signatures[@]}) if [ "$F_makepkg_scm" = "git" ]; then check_servers for i in $($repoman_ssh $host "[ -d $path/$mydir ] && cd $path/$mydir && git ls-files --others --directory") do if ! echo ${srclocal[@]} |grep -q $i && ! _is_log $i && [ "$i" != "Changelog" ]; then dry_run delete $mydir/$i fi done else srckeep=$($mktemp_local) darcsdir="_darcs/pristine" if ! $0 -t $reponame ls $darcsdir &>/dev/null; then darcsdir="_darcs/current" fi $0 -t $reponame ls $darcsdir/$mydir 2>/dev/null >$srckeep for i in $($0 -t $reponame ls $mydir 2>/dev/null) do if ! grep -q $i $srckeep && ! _is_log $i && [ "$i" != "Changelog" ]; then if ! echo ${srclocal[@]} |grep -q $i; then dry_run delete $mydir/$i fi fi done rm -f $srckeep fi } fpmdel() { fpmkeep=$($mktemp_local) fpmserver=$($mktemp_local) for i in $pkgname ${subpkgs[@]} do echo $i-$pkgver-$pkgrel-$arch.fpm >> $fpmkeep $0 -t $reponame ls frugalware-$arch 2>/dev/null |grep "^$i-[^-]\+-[^-]\+-$arch.fpm" >> $fpmserver done for i in $(cat $fpmserver) do if ! grep -q $i $fpmkeep; then dry_run delete frugalware-$arch/$i fi done rm -f $fpmkeep $fpmserver } bzip() { ask_and_eval "bzip2 $*" } sync() { ls *-$arch.fpm &>/dev/null && srcdel if ls *-$arch.fpm &>/dev/null; then for i in *-$arch.fpm do _check_nobuild || dry_run upload $i frugalware-$arch/ done fi modpkgname=$(echo $pkgname | sed 's/\+/\\+/g') if [ -n "$noask" ]; then opts="-a" else opts="" fi if [ "$F_makepkg_scm" = "git" ]; then cmd="dg push $opts" else cmd="darcs push --match 'name $modpkgname' $opts" fi dry_run "$cmd" || die "push failed" # here we _could_ upload the new sources but that'll be done by changelog() buildlog="$pkgname-$pkgver-$pkgrel-$arch.log" if [ -f $buildlog -o -f $buildlog.bz2 ]; then [ -f $buildlog ] && dry_run bzip $buildlog _check_nobuild || dry_run upload $buildlog.bz2 source/$groups/$pkgname/ fi ls *-$arch.fpm &>/dev/null && fpmdel dry_run changelog $groups/$pkgname if [ "$1" == "-c" ]; then if [ "$F_makepkg_scm" = "git" ]; then git clean -x -d -f else rm -rvf *-$arch.fpm rm -vf *.log.bz2 rm -rf src fi fi } push() { if [ "$1" == "--clean" -o "$1" == "-c" ]; then clean="-c" shift 1 else clean="" fi dry_run record "$*" sync $clean } die() { echo -e "$0: $*" exit 1 } update() { if [ ! "`type -p git`" ]; then die "The git program is missing. Please install it with pacman-g2 -S git." fi for i in ${repos[@]} do pushonly=$(eval "echo \$${i}_pushonly") [ "$pushonly" = "y" ] && continue # Search for a server. eval "servers=(\${${i}_servers[@]})" if [ -z "$servers" ]; then echo -e "$0: Can't find any server!" if [ -e /etc/repoman.conf.pacnew ]; then echo -e "$0: HINT: merge the contents of /etc/repoman.conf.pacnew to /etc/repoman.conf!" fi exit 1 fi echo ":: Synchronizing source trees..." for j in ${servers[@]} do # check if we need to clone or pull if [ -d $fst_root/$i/.git ]; then cmd="cd $i && git pull" else cmd="git clone $j $i" fi mkdir -p $fst_root cd $fst_root echo -n "$i: " eval $cmd if [ $? != 0 ]; then echo "failed." else break fi done done } chk_updated() { if [ ! -d $1 ]; then echo "ERROR: Could not find FrugalBuild scripts in $1" echo " have you used 'repoman upd' yet?" exit 1 fi } search() { chk_updated $fst_root [ -z "$*" ] || grepcmd="|grep $*" for i in ${repos[@]} do eval "find $fst_root/$i/source -name FrugalBuild |xargs grep '\(options=(.*nobuild.*)\|^nobuild=\)' |sed 's|$fst_root/||;s|/source/[^/]*||;s|/FrugalBuild:.*||' $grepcmd" done } info() { chk_updated $fst_root for i in ${repos[@]} do if [ -d $fst_root/$i/source/*/$1 ]; then cd $fst_root/$i/source/*/$1 startdir=`pwd` source ./FrugalBuild [ ${#depends[*]} -eq 0 ] && depends="" || depends="${depends[@]} " [ ${#rodepends[*]} -gt 0 ] && depends="$depends${rodepends[@]}" echo "Repository : $i" echo "Name : $pkgname" echo "Version : $pkgver-$pkgrel" echo "Groups : ${groups[@]}" echo "Provides : ${provides[@]:-None}" echo "Depends On : ${depends[@]:-None}" echo "Removes : ${removes[@]:-None}" echo "Conflicts With : ${conflicts[@]:-None}" echo "Replaces : ${replaces[@]:-None}" echo "Description : $pkgdesc" cd - >/dev/null break fi done } upgrade() { chk_updated $fst_root echo ":: Searching for nobuild packages..." localpkgs=$(pacman-g2 -Qm|sed 's/ .*//') echo ":: Starting local database upgrade for nobuild packages..." targets="" targetstr="Targets:" for i in $localpkgs do remotever=$(info $i|grep ^Version|sed 's/.*: //') [ -z "$remotever" ] && continue localver=$(pacman-g2 -Qi $i|grep ^Version|sed 's/.*: //') diff=$(vercmp $remotever $localver) if [ $diff -le 0 ]; then [ $diff -lt 0 ] && "warning: $i-$localver: local version is newer" continue fi if echo $upgrade_ignore |grep -q $i; then echo "warning: $i-$localver: ignoring package upgrade ($remotever)" continue fi targets="$targets $i" targetstr="$targetstr $i-$remotever" done [ -n "$targets" ] && echo -e "\n$targetstr\n" if [ -z "$dryrun" ]; then for i in $targets do echo ":: Merging $i..." if ! $0 -f merge $i; then echo "Failed to merge $i." echo "Try merging the package manually then run 'repoman upgrade' again to merge the" echo "rest of the targets." exit 1 fi done else [ -n "$targets" ] && echo "Run 'repoman upgrade' to merge all target packages." fi } merge() { local i repo target if echo $1 |grep -q /; then repo=${1%/*} target=${1#*/} else repo="${repos[@]}" target=$1 fi if [ -z "$force" ]; then # install essential packages if necessary echo -n "checking for essential packages... " . /etc/makepkg.conf for i in "$COREPKGS" do missing="$missing `pacman -Sg $i |grep -v '^\w'` " done missdep=`pacman-g2 -T $missing| sed 's|.\+: ||'` if [ -n "$missdep" ]; then echo "failed" echo "Use the following command to install the missing packages:" echo "pacman-g2 -S `echo $missdep| sed 's|=.*$||;s|>.*$||;s|<.*$||'`" exit 1 else echo "done" fi fi found=0 for i in ${repo[@]} do # sanity checks chk_updated $fst_root/$i pushonly=$(eval "echo \$${i}_pushonly") [ "$pushonly" = "y" ] && continue dir=`find $fst_root/$i -maxdepth 4 -type d -name "$target"|sed -n '$ p'` if [ -z "$dir" ]; then continue else found=1 cd $dir makepkg $makepkg_opts exit $? fi done [ "$found" = 0 ] && die "package '$target' not found" } if [ "$1" != "upd" -a "$1" != "update" ]; then [ -e /usr/lib/frugalware/fwmakepkg ] && . /usr/lib/frugalware/fwmakepkg || \ die "Can't find /usr/lib/frugalware/fwmakepkg!" [ -e /etc/makepkg.conf ] && . /etc/makepkg.conf || \ die "Can't find /etc/makepkg.conf!" else [ -e /etc/repoman.conf ] && . /etc/repoman.conf || \ die "Can't find /etc/repoman.conf!" fi if [ -e FrugalBuild ]; then . ./FrugalBuild fi # Initializing variables. version='0.3.1' [ -z "$arch" ] && arch=`uname -m` mktemp_local="mktemp -p $HOME" sudo_env="sudo -E" unset LANG LC_ALL if [ "$F_makepkg_scm" = "git" ]; then # Checking for git. which git >/dev/null 2>&1 if [ $? != 0 ]; then echo "ERROR: Can't find git. You can install it with pacman-g2 -S git." exit 1 fi fi # Parsing parameters. if [ $# -le 0 ]; then usage exit 0 fi # default for the -t parameter reponame=${repos[0]} while [ "$1" != "" ]; do case "$1" in -h|--help) usage exit 0 ;; -v|--verbose) verbose=1 ;; --version) echo repoman $version exit 0 ;; -t|--tree) shift 1 reponame=$1 ;; -k) noask=1 ;; -d|--dry-run) dryrun=1 ;; -f|--force) force=1 ;; -*) echo "Unknown option: $1" usage exit 1 ;; *) break ;; esac shift done if [ "$1" != "" ]; then case "$1" in cl|changelog) shift 1 changelog $* ;; c|clean) shift 1 clean $* ;; del|delete) shift 1 delete $* ;; server) shift 1 server "$@" ;; ls|list) shift 1 list $* ;; m|merge) shift 1 merge $* ;; fpmmerge) shift 1 fpmmerge $* ;; up|upload) shift 1 upload $* ;; upd|update) shift 1 update $* ;; s|search) shift 1 search $* ;; rec|record) shift 1 record "$*" ;; push) shift 1 push $* ;; sync) shift 1 sync $* ;; info) shift 1 info $* ;; upgrade) shift 1 upgrade $* ;; ci) shift 1 commit_info $* ;; *) echo "Unknown command: $1" usage exit 1 ;; esac else echo "No command given" exit 1 fi exit 0