Construction Kit


an archlinux unofficial repository manager over the ftp transfer protocol

Just an unofficial tool written in bash, to help managing an archlinux repository over the ftp transfer protocol.

 

 

#!/bin/bash
#
#
#  CKIT - Construction Kit
#    Just an unofficial archlinux repository manager
#    over the ftp transfer protocol.
#
#  Copyright (C) 2009   Dario 'Dax' Vilardi <dax@deelab.org>
#
#
# 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 3 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 <http://www.gnu.org/licenses/>.
#

#################### SETTINGS ####################

# ftp account
ftpaddress="ftp.deelab.org"
foo=""
bar=""

# remote spot
httpaddress="http://www.deelab.org"
# structure: $httpaddress/arch/$arch/

# sources workspace
builddir="$HOME/pkg/yaourtbuild"

# packages workspace
repodir="$HOME/pkg/CKIT"

# cache
cachedir="$HOME/pkg/cache"

# repo
repo="deelab.db.tar.gz"

# arch
arch="i686"

# editor
editor="geany"

# usefull files
checklog="checklog"
buildlog="buildlog"
updatelog="updatelog"
deletelog="deletelog"

#################### /SETTINGS ####################





#################### PRIVATE INTERFACES ####################


wget_repo(){
    cd $repodir
    [[ -f $repo ]] && rm $repo
    printf "==> Getting $repo... "
    wget $httpaddress/arch/$arch/$repo &>/dev/null \
        && echo "done" \
        || echo "failed"
}

wget_tarball(){
    pkg=$1
    cd $builddir
    url="http://aur.archlinux.org/packages/$pkg/$pkg/PKGBUILD"
    if PKGBUILD=$(wget -q -O - "$url"); then
        printf "  -> Getting $pkg from AUR..."
        if wget http://aur.archlinux.org/packages/$pkg/$pkg.tar.gz &>/dev/null; then
            echo "done"
            tar -xf "$pkg.tar.gz"
            rm $pkg.tar.gz
        else
            echo "failed"
        fi
    else
        echo "  -> $pkg not found on AUR."
    fi
}


lftp_run(){
    lftp -u "$foo,$bar" $ftpaddress/arch/$arch -e "$1; exit"
}

lftp_glob_rm(){
    item=$(lftp_run "glob echo $1-*.pkg.tar.gz" 2>&1 | grep $1)
    RESULT=""
    lftp_run "glob rm -f $1-*.pkg.tar.gz" &>/dev/null && RESULT=$item
}

lftp_put_repo(){
    printf "==> Uploading db... "
    cp "$repo" "$repo"_prev
    lftp_run "put $repo" &>/dev/null \
        && echo "done!" \
        || echo "failed!"
    wget_repo
    i=$(stat -c%s "$repo")
    j=$(stat -c%s "$repo"_prev)
    [[ $i = $j ]] \
        && echo "  -> Size test ok ($i)."  \
        || echo "  -> Take care: $i ~ $j! restoredb maybe needed."
}


post_build(){
    pkg=($1*.pkg.tar.gz)
    if [[ -s "${pkg[0]}" ]]; then
   
        echo "==> Yo, $1 done :)"
        mv $builddir/$1/$1*.pkg.tar.gz $repodir
   
        echo $1 >> /tmp/CKIT
        cat /tmp/CKIT $repodir/$buildlog > /tmp/$buildlog
        rm /tmp/CKIT
        mv /tmp/$buildlog $repodir/$buildlog
 
    else
        echo "==> WTF, package $1 doesn't build :("
    fi
}


rmdirsrc(){
    [[ -d $builddir/$1/src ]] \
        && rm -rf $builddir/$1/src \
        && echo "  -> $builddir/$1/src removed"
}

rmsrc(){
    target=( "zip" "ZIP" "rar" "RAR" "bz2" "gz" "part" "jar" "Jar" "deb" "html" "bin")
    for i in "${target[@]}"; do
        rm $builddir/$1/*$i &>/dev/null && echo "  -> $i removed"
    done
}

die(){
    echo "$@"
    exit 1
}

copy_log_to_pkgs(){
    IFS=$'\n'
    [[ -s $repodir/$1 ]] && pkgs=($(< $repodir/$1)) || die "==> $1 empty"
}

#################### /PRIVATE INTERFACES ####################




#################### PUBLIC INTERFACES ####################




# DELETESRC
deletesrc(){
   
    if [[ $FROMLOG == 0 ]] && (( ${#pkgs[@]} == 0 )); then
        copy_log_to_pkgs $deletelog
    else
        (( ${#pkgs[@]} == 0 )) && die "==> Packages needed!"
    fi
   
    for pkg in "${pkgs[@]}"; do
        [[ -d $builddir/$pkg ]] \
            && echo "==> Cleaning $pkg directory" \
            && rmdirsrc $pkg \
            && rmsrc $pkg
    done
}
# /DELETESRC



# EDITPKG
editpkg(){
    read -p "==> Package to edit: " pkg
    if [[ -d $builddir/$pkg ]]; then
        echo "==> $pkg:"
        cd $builddir/$pkg
        for file in *; do
            [[ -f $file ]] && echo "  -> $file"
        done
        read -p "==> Which one want you edit? " file
        if [[ -f $builddir/$pkg/$file ]]; then
            echo "==> Editing $pkg/$file"
            $editor "$builddir/$pkg/$file" && echo "  -> Done."
        else
            echo "==> $file not found."
        fi
    else
        echo "==> $pkg not found."
    fi 
}
# /EDITPKG


# EDITLOG
editlog(){
    echo "==> Available logs:"
    cd $repodir
    for file in *log; do
        echo "  -> $file"
    done
    read -p "==> Which one to edit? " log
    if [[ -f $repodir/$log ]]; then
        echo "==> Editing $repodir/$log"
        $editor $repodir/$log && echo "  -> Done."
    else
        echo "==> $log not found."
    fi
}
# /EDITLOG



# OWNPKG
ownpkg(){
    read -p "==> Package to own: " pkg
    if [[ -d $builddir/$pkg ]]; then
        echo "  -> Owning $pkg "
        sudo chown -R $USER $builddir/$pkg && echo "  -> Done."
    else
        echo "  -> $pkg not found."
    fi
}
# /OWNPKG



# CLEARCACHE
clearcache(){
    rm $cachedir/*
}
# /CLEARCACHE



# RESTOREDB
restoredb(){

    cd $repodir
    echo "==> Restoring db from latest backup."
    cp "$repo"_prev "$repo"
    lftp_run "put $repo" &>/dev/null \
        && echo "  -> Done!" \
        || echo "  -> Failed!"

}
# /RESTOREDB



# CHECK
check(){

    [[ -f $repodir/$checklog ]] && rm $repodir/$checklog;
    touch $repodir/$checklog
    cd $repodir

    wget_repo
    echo "==> Checking for outdated's versions of packages."

    REGEX=".*-(svn|cvs|hg|git|bzr|darcs|devel)"

    while read -r line; do
       
        [[ $line = */ ]] || continue
        i="${line%/}"

        pkg=${i%-*-*}
        repover=${i#$pkg-}
       
        # AUR check
        url="http://aur.archlinux.org/packages/$pkg/$pkg/PKGBUILD"
        if PKGBUILD=$(wget -q -O - "$url"); then
            aurver="$(eval "$PKGBUILD" &>/dev/null; echo "$pkgver-$pkgrel")"
        else
            aurver="Null"
        fi
       
        # local check
        if pacman -Q $pkg &> /dev/null; then
            localver="$(LANG=C pacman -Qi "$pkg" | awk '/^Version/ {print $3}')"
        else
            localver="Null"
        fi
       
        # devel check
        if [[ "$pkg" =~ $REGEX && -d $builddir/$pkg ]]; then
            cd "$builddir/$pkg" || warn "==> $pkg not available."
            # awk -v foo=something  assigns an awk variable
            # $0 being the whole line, $1 being the first field
            develver=$(makepkg -o 2>&1 | awk -v "pkg=$pkg" '$0 ~ pkg {print $6}')
            cd ~-
            result=$(vercmp "$repover" "$develver")
        else
            develver="Null"
            result=$(vercmp "$repover" "$aurver")
        fi
               
        if [[ "$result" < 0 ]]; then
            echo "  -> $pkg REPO:$repover LOCAL:$localver AUR:$aurver DEVEL:$develver"
            echo $pkg >> /tmp/CKIT
            cat /tmp/CKIT $repodir/$checklog > /tmp/$checklog
            rm /tmp/CKIT
            mv /tmp/$checklog $repodir/$checklog
        fi
 
    done < <(tar ztf $repo)
   
}
# /CHECK



# UPDATEPKGBUILD
updatepkgbuild(){
   
    echo "==> Updating local PKGBUILD from AUR."
   
    (( ${#pkgs[@]} == 0 )) \
        && [[ $FROMLOG == 0 ]] \
        && copy_log_to_pkgs "$updatelog"
   
    if (( ${#pkgs[@]} == 0 )); then
   
        wget_repo
       
        IFS=$'\n' read -d '' -a lines < <(tar ztf "$repo")
        for line in "${lines[@]}"; do
        #for i in $(tar -tf $repo | sed -n '/\/$/s/.$//p'); do
            [[ $line = */ ]] || continue
            i="${line%/}"
            pkg=${i%-*-*}
            read -p "  -> $pkg: update? (y/n) " answer
            [[ "$answer" == "y" ]] && wget_tarball "$pkg"
        done
       
    else
   
        for pkg in "${pkgs[@]}"; do
            wget_tarball "$pkg"
        done
       
    fi
       
}
# /UPDATEPKGBUILD



# BUILD
build(){

    # filter & replace $pkgs from checklog if asked
    if (( ${#pkgs[@]} == 0 )); then
        if [[ $FROMLOG == "0" ]]; then
            copy_log_to_pkgs "$checklog"
        else
            die "==> Nothing to build."
        fi
    fi
   

    for pkg in "${pkgs[@]}"; do
       
        sudo=""
        asroot=""
        i=""
       
        echo "==> $pkg"
        cd $builddir
       
        if [[ $noconfirm == 0 ]]; then
            # aur
            [[ $aur == "0" ]] && wget_tarball $pkg
            # root
            [[ $root == "0" ]] && sudo="sudo" && asroot="--asroot"
            # install
            [[ $install == "0" ]] && i="-i"
            # skipmd5sums
            [[ $skipmd5sums == "0" ]] && skipinteg="--skipinteg"
            # makepkg
            cd $pkg && $sudo makepkg $i -s $asroot $skipinteg
            post_build $pkg
        else
            # build?
            read -p "  -> do you want upgrade? (y/n) " answer
            if [[ "$answer" == "y" ]]; then
           
                # aur
                if [[ $aur == "0" ]]; then
                    wget_tarball $pkg
                else
                    read -p "  -> Do you want get tarball from AUR? (y/n) " answer
                    [[ "$answer" == "y" ]] && wget_tarball $pkg
                fi
               
                # root
                if [[ $root == "0" ]]; then
                    sudo="sudo"
                    asroot="--asroot"
                else
                    read -p "  -> Do you want build as root? (y/n) " answer
                    [[ "$answer" == "y" ]] && sudo="sudo" && asroot="--asroot"
                fi
               
                # install
                if [[ $install == "0" ]]; then
                    i="-i"
                else
                    read -p "  -> Do you want install package after build? (y/n) " answer
                    [[ "$answer" == "y" ]] && i="-i"
                fi
               
                # skipmd5sums
                if [[ $skipmd5sums == "0" ]]; then
                    skipinteg="--skipinteg"
                else
                    read -p "  -> Do you want skip md5sums check? (y/n) " answer
                    [[ "$answer" == "y" ]] && skipinteg="--skipinteg"
                fi
               
                # makepkg
                cd $pkg && $sudo makepkg $i -s $asroot $skipinteg
               
                post_build $pkg
               
            fi
        fi
   
    done
   
   
    # show built packages
    copy_log_to_pkgs "$buildlog"
    echo "==> Packages waiting to be added:"
    for pkg in "${pkgs[@]}"; do
        echo "  -> $pkg"
    done
   
}
# /BUILD



# ADD
add(){

    cd $repodir
   
    # init
    [[ ! -s $repodir/$buildlog ]] \
        && die "==> Nothing to add, ckit -B packages needed!"
   
    wget_repo
   
    # repo-add
    echo "==> Adding packages queued"
    for file in *.pkg.tar.gz; do
        printf "  -> $file... "
        repo-add $repo $file &>/dev/null && \
            echo "done!" || \
            echo "failed!"
    done
   
    # db
    lftp_put_repo
   
    # delete previous packages
    echo "==> Deleting previous packages"
    copy_log_to_pkgs "$buildlog"
    for pkg in "${pkgs[@]}"; do
        lftp_glob_rm "$pkg" &>/dev/null
        [[ "$RESULT" != "" ]] && \
            echo "  -> $RESULT done!" || \
            echo "  -> $pkg not found."
    done
       
    rm $buildlog $checklog
   
    #invio i nuovi
    echo "==> Uploading packages"
    for file in *.pkg.tar.gz; do
        printf "  -> $file... "
        if lftp_run "put $file" &>/dev/null; then
            echo "done!"
            mv $file $cachedir
        else
            echo "failed!"
        fi
    done
   
    echo "==> Repository updated! Gj, see ya."

}
# /ADD



# REMOVE
remove(){

    # init
    (( ${#pkgs[@]} == 0 )) && die "==> Packages needed!"

    cd $repodir
   
    wget_repo
    echo "==> Removing from db"
    for pkg in "${pkgs[@]}"; do
        printf "  -> $pkg... "
        repo-remove $repo $pkg &>/dev/null \
            && echo "done!" \
            || echo "failed!"
    done
       
    lftp_put_repo
  
    echo "==> Removing from ftp"
    for pkg in "${pkgs[@]}"; do
        lftp_glob_rm "$pkg" &>/dev/null
        [[ "$RESULT" != "" ]] && \
            echo "  -> $RESULT done!" || \
            echo "  -> $pkg not found."
    done
       
}
# /REMOVE



# HELP
help(){
    echo "==> CKIT - Construction KIT!"
    echo "==> Preprocessing:"
    echo "  -> -D packages: delete sources from package's directory"
    echo "  -> -U[L]: Update tarball from AUR"
    echo "  -> -UL: Update tarball from AUR by updatelog"
    echo "  -> -O: Own package"
    echo "  -> -E: Edit a file from package"
    echo "  -> -h: This help"
    echo "==> Processing:"
    echo "  -> -B[b][a][r][i][s][n][L] packages: build packages."
    echo "  -> -Bb: build all packages, don't need with -n"
    echo "  -> -Ba: get tarball from AUR"
    echo "  -> -Br: build as root"
    echo "  -> -Bi: install packages after builds"
    echo "  -> -Bs: skip integrity check"
    echo "  -> -Bn: don't ask confirm"
    echo "  -> -BL: build from checklog"
    echo "  -> -L: edit log files"
    echo "  -> -C: check for newer version of packages"
    echo "  -> -R packages: remove packages from repository"
    echo "==> Postprocessing:"
    echo "  -> -A: add built packages"
    echo "  -> -H: clear cache"
    echo "  -> -T: restore remote db from a failed upload"
}
# /HELP



#################### /PUBLIC INTERFACES ####################





#################### MAIN ####################



logs=( "$buildlog" "$checklog" "$updatelog" "$deletelog" )
for log in "${logs[@]}"; do
    [[ ! -f $repodir/$log ]] && touch $repodir/$log
done
   
   

test -z "$1" && die "==> RTFM, see ya!"


# primary
ADD=1
BUILD=1
CHECK=1
REMOVE=1
BUILDFROMCHECK=1
UPDATEPKGBUILD=1
CLEARCACHE=1
RESTOREDB=1
OWNPKG=1
EDITPKG=1
DELETESRC=1
HELP=1
FROMLOG=1
# secondary
buildall=1
aur=1
root=1
install=1
skipmd5sums=1
noconfirm=1

   
x=1         # Avoids an error if we get no options at all.
while getopts "ABarisnCRUHLTOEDh" opt; do
    case "$opt" in
        A) ADD=0;;
        B) BUILD=0;;
        a) aur=0;;
        r) root=0;;
        i) install=0;;
        s) skipmd5sums=0;;
        n) noconfirm=0;;
        C) CHECK=0;;
        R) REMOVE=0;;
        U) UPDATEPKGBUILD=0;;
        H) CLEARCACHE=0;;
        L) FROMLOG=0;;
        T) RESTOREDB=0;;
        O) OWNPKG=0;;
        E) EDITPKG=0;;
        D) DELETESRC=0;;
        h) HELP=0;;
    esac
    x=$OPTIND
done
shift $(($x-1))
pkgs=("$@")



# rule
if [[ $REMOVE == "0" ]]; then
    [[ $BUILD == "0" ]] && die "==> Not allowed."
    [[ $RESTOREDB == "0" ]] && die "==> Not allowed."
    [[ $ADD == "0" ]] && die "==> Not allowed."
fi
[[ $DELETESRC == "0" ]] && [[ $UPDATEPKGBUILD == "0" ]] && die "==> Not allowed."


# preproccessing
[[ $FROMLOG == 0 ]] && [[ $UPDATEPKGBUILD == 1 ]] && [[ $BUILD == 1 ]] && [[ $DELETESRC == 1 ]] && editlog
[[ $UPDATEPKGBUILD == 0 ]] && updatepkgbuild
[[ $OWNPKG == 0 ]] && ownpkg
[[ $EDITPKG == 0 ]] && editpkg
[[ $DELETESRC == 0 ]] && deletesrc
[[ $HELP == 0 ]] && help


# processing
[[ $BUILD  == 0 ]] && build
[[ $CHECK == 0 ]] && check
[[ $REMOVE == 0 ]] && remove


# postprocessing
[[ $ADD  == 0 ]] && add
[[ $CLEARCACHE == 0 ]] && clearcache
[[ $RESTOREDB == 0 ]] && restoredb




#################### /MAIN ####################