#!/bin/bash # The purpose of this script is to automate the maintenance of a custom pacman (Arch Linux) repository, whose goal is to # provide package-ready AUR softs. # This script should NOT be run as root. # Dependencies # Make sure that AWK rules file is present, readable and correctly set in this script's parameters # Make sure the following packages are installed before running this script: # package-query aurutils git # Functions ################################################################## ascii_frag() { expr match "$1" "\([^[:digit:]]*\)" } ascii_remainder() { expr match "$1" "[^[:digit:]]*\(.*\)" } numeric_frag() { expr match "$1" "\([[:digit:]]*\)" } numeric_remainder() { expr match "$1" "[[:digit:]]*\(.*\)" } # return 1 for $1 > $2 # return 2 for $1 < $2 # return 0 for equal vercomp() { local WORK1="$1" local WORK2="$2" local NUM1="", NUM2="", ASCII1="", ASCII2="" while true; do ASCII1=`ascii_frag "${WORK1}"` ASCII2=`ascii_frag "${WORK2}"` WORK1=`ascii_remainder "${WORK1}"` WORK2=`ascii_remainder "${WORK2}"` if [ "${ASCII1}" \> "${ASCII2}" ]; then return 1 elif [ "${ASCII1}" \< "${ASCII2}" ]; then return 2 fi NUM1=`numeric_frag "${WORK1}"` NUM2=`numeric_frag "${WORK2}"` WORK1=`numeric_remainder "${WORK1}"` WORK2=`numeric_remainder "${WORK2}"` if [ -z "${NUM1}" -a -z "${NUM2}" ]; then return 0 elif [ -z "${NUM1}" -a -n "${NUM2}" ]; then return 2 elif [ -n "${NUM1}" -a -z "${NUM2}" ]; then return 1 fi if [ "${NUM1}" -gt "${NUM2}" ]; then return 1 elif [ "${NUM1}" -lt "${NUM2}" ]; then return 2 fi done } ################################################################## init() { # Only run if the user is not root if [[ $USER = 'root' ]] ; then echo "You cannot run this script as root!" exit 1 fi if [ -n "$(ls $run_directory_path)" ] ; then echo "The running directory is not empty!" exit 1 fi # TODO Check if required packages are installed echo "ArchRepo update script" } ftpFetch() { ftp fetch $remote_repository/$repo_db_file $run_directory_path # TODO use real syntax ^^' } checkUpdates() { echo "Checking for updates:" upgraded_packages="" #stream=$(tar xOf $repo_directory/$repo_db_file --wildcards */desc | awk -f $awk_rules_file) stream=$(tar xOf $run_directory_path/$repo_db_file --wildcards */desc | awk -f $awk_rules_file) OIFS=$IFS IFS='|' stream="${stream:1}" for package in $stream do IFS=' ' count=0 for line in $package; do if [ $count -eq 0 ]; then filename=$line elif [ $count -eq 1 ]; then name=$line elif [ $count -eq 2 ]; then version=$line fi ((count++)) done reg="(linux-lts).+-((docs)|(headers))" if [[ $name =~ $reg ]]; then echo -e "\nSkipping $name ($version, default exception)." continue 1 fi exlist="" if echo $exlist | grep -w $name > /dev/null; then echo -e "\nSkipping $name ($version, temporary exception)." continue 1 fi echo -e "\nChecking $name ($version)..." aur_version=$(package-query -A -f %v $name) vercomp $aur_version $version result=$? if [[ $result -eq 1 ]]; then echo "New version for $name: $version -> $aur_version" createPackage $name addPackageToRepo $name $aur_version upgraded_packages="$upgraded_packages $name" fi IFS='|' done IFS=$OIFS echo "All packages processed." if [[ $upgraded_packages != "" ]]; then echo "The following packages were upgraded:" echo $upgraded_packages fi } addPackage() { createPackage $1 addPackageToRepo $1 } createPackage() { # Create package $1 echo "Fetching $1 from AUR..." aur fetch $1 # TODO This could be replaced by a git clone or even a wget+tar thanks to package-query echo "Making $1 package..." cd $1 # if linux-lts{414,49} then download kernel source from local repo (saves ~100MB each time) # WARNING this onlys works because we already have said sources AND because PKBUILD follow this particular line # (not the same in 419 nor 54) reg="(linux-lts).+" if [[ $1 =~ $reg ]]; then sed -i -e "s/\"https:\/\/www.kernel.org\/pub\/linux\/kernel\/v4.x\/\${_srcname}.tar.xz\"/\"https:\/\/archlinux.kto.black\/resources\/\${_srcname}.tar.xz\"/g" ./PKGBUILD fi makepkg -s --noconfirm --noprogressbar cd $run_directory_path } ftpSend() { } # TODO: try manually: can we update db file before sending to remote repo? addPackageToRepo() { # Add package $1 echo "Adding $1 to repository..." #cp $run_directory_path/$1/$1-$2*.pkg.tar.xz $repo_directory repo-add $repo_db_file $1-$2*.pkg.tar.xz ftp send $repo_db_file $repo_db_file.old $remote_repository ftp send packages $remote_repository reg="(linux-lts).+" if [[ $name =~ $reg ]]; then echo "Adding $1-headers and $1-docs to repository..." cp $run_directory_path/$1/$1-headers-$2*.pkg.tar.xz $run_directory_path/$1/$1-docs-$2*.pkg.tar.xz $repo_directory repo-add $repo_directory/$repo_db_file $repo_directory/$1-headers-$2*.pkg.tar.xz $repo_directory/$1-docs-$2*.pkg.tar.xz fi } clean() { echo "Cleaning directory..." rm -rf $run_directory_path/* echo "Done." } clearRepo() { stream=$(tar xOf $repo_directory/$repo_db_file --wildcards */desc | awk -f $awk_rules_file) OIFS=$IFS IFS='|' stream="${stream:1}" current="" for package in $stream do IFS=' ' count=0 for line in $package; do if [ $count -eq 0 ]; then current="$current $line" else continue fi ((count++)) done IFS='|' done IFS=$OIFS cd $repo_directory reg="^($repo_name.).+" for filename in *; do if [[ $filename =~ $reg || $filename = 'sync' || $filename = 'local' || $filename = 'resources' ]]; then continue fi for package in $current; do if [ $filename = $package ]; then continue 2 fi done echo "Removing $filename..." rm $filename done } run_directory_path=$(pwd) # Set parameters repo_directory='/mnt/archrepo' repo_name='kto' repo_db_file=$repo_name.db.tar awk_rules_file='../parser.awk' #repo_db_file='kto.db.tar' # You can set db name manually here if different # Main process if [ "$1" = "" ]; then init checkUpdates elif [ "$1" = "add" ]; then init addPackage $2 elif [ "$1" = "clean" ]; then clean elif [ "$1" = "clear" ]; then read -r -p "Are you sure? [y/N] " response response=${response,,} # tolower if [[ "$response" =~ ^(yes|y)$ ]]; then clearRepo else echo "Cancelling... Perhaps did you mean 'clean', which empties the local build directory?" exit 1 fi else exit 1 fi exit 0