#!/bin/bash APP_SVNID='$HeadURL$ $LastChangedRevision$' . $(ade-config ade_share_prefix)/include/ade.sh || { echo "${0##*/}: INTERNAL ERROR: failed to load ade.sh" >&2; exit 3; } . $(paa-config paa_share_prefix)/include/directives-all.sh || { echo "${0##*/}: INTERNAL ERROR: failed to load directives-all.sh" >&2; exit 3; } . $(paa-config paa_share_prefix)/include/directives-deb.sh || { echo "${0##*/}: INTERNAL ERROR: failed to load directives-deb.sh" >&2; exit 3; } . $(paa-config paa_share_prefix)/include/directives-rpm.sh || { echo "${0##*/}: INTERNAL ERROR: failed to load directives-rpm.sh" >&2; exit 3; } . $(paa-config paa_share_prefix)/include/upgrades.sh || { echo "${0##*/}: INTERNAL ERROR: failed to load upgrades.sh" >&2; exit 3; } PAA_DEFINED_ERRORS=( "KEY=PAA_ERR_UNSET; FMT=\"%s: not set (%s)\"" # : not set () "KEY=PAA_ERR_MISC; FMT=\"%s\"" ) # Globals # Ordered directives (according to apply_directives()'s needs) DIRECTIVES="release port section layout compat mirror_cmd path url freeze_dir indirect_dir mirror_dir distro origin label signer" CURRENT_EXT="current" SQLITE_CMD=sqlite3 SEPARATOR="@@@" EXCLUSIVE_TIMEOUT=10000 PAA_STATE_PREFIX=$(paa-config paa_state_prefix) CODE_SCHEMA_CONFORMANCY=4 REPO_FMTSTR="%-22.22s" PKGTYPE_FMTSTR="%-7.7s" # wider to allow room for column header REPOTYPE_FMTSTR="%-8.8s" DISTRO_FMTSTR="%-10.10s" STATUS_FMTSTR="%-10.10s" HOST_FMTSTR="%-20.20s" ORIGIN_FMTSTR="%-10.10s" LABEL_FMTSTR="%-10.10s" SIGNER_FMTSTR="%-10.10s" SECTIONS_FMTSTR="%-60.60s" FREEZE_FMTSTR="%-14.14s" RELEASE_FMTSTR="%-10.10s" PORT_FMTSTR="%-7.7s" PID_FMTSTR="%5.5s" LOGICAL_FMTSTR="%-7.7s" DIR_FMTSTR="%-40.40s" DATE_FMTSTR="%-30.30s" CMD_FMTSTR="%-80.80s" URL_FMTSTR="%-25.25s" BLOB_FMTSTR="%-10.10s" UNDERLINE="-----------------------------------------------------------------------------------------------------------" WORD_REGEXP='[a-zA-Z_]([-a-zA-Z0-9_]*)[a-zA-Z0-9]' GPG_CMD=gpg loading() { : echo "loading $1() ..."; } loading paa paa() { local ERRSTACK_REF="$1"; shift local -a NEW_DOLLAR_AT local RC LABEL FUNCTION FORCE_FLAG PROGNAME ade_global RCDIR THIS_HOST # Register application-specific errors ade_register_error_types PAA_DEFINED_ERRORS # Defaults for options ade_get_progname "$ERRSTACK_REF" PROGNAME RCDIR=${PAA_RCDIR:-$HOME/.$PROGNAME} ROOTDIR=${PAA_ROOTDIR:-/} THIS_HOST=${PAA_HOSTNAME:-$(uname -n)} FORCE_FLAG=false # Register paa options ade_register_options "$ERRSTACK_REF" --longoptions=rcdir:,rootdir:,hostname:,force --callback-template="paa_opt_handler_%s" || return $? ade_set_callbacks "$ERRSTACK_REF" paa_usage_help paa_version paa_paths || return $? # Process options ade_process_options "$ERRSTACK_REF" NEW_DOLLAR_AT "$@" || return $? set -- "${NEW_DOLLAR_AT[@]}" # Argument processing [ "X$1" != X ] || ade_show_bad_usage "$ERRSTACK_REF" # better arg checking done on per-opmode basis FUNCTION=$1 shift case $FUNCTION in repo|unrepo|editrepo|listrepos|mirror|unmirror|listmirrors|host|unhost|listhosts|freeze|unfreeze|listfreezes|indirect|unindirect|listindirects|share|unshare|listshares|access|unaccess|listaccesses|insert|control|editdb|showtbl|upgrade|listobsolete) : ;; *) ade_show_bad_usage "$ERRSTACK_REF" ;; esac # Guts db_prologue "$ERRSTACK_REF" || return $? [[ $FUNCTION =~ ^(upgrade|editdb|showtbl)$ ]] || check_schema_conformancy "$ERRSTACK_REF" || return $? $FUNCTION "$ERRSTACK_REF" "$@" || return $? db_epilogue "$ERRSTACK_REF" || return $? return $ADE_OK } db_prologue() { local ERRSTACK_REF="$1"; shift local PROGNAME ade_inherit RCDIR SEPARATOR EXCLUSIVE_TIMEOUT # Sanity checks and derivations ade_get_progname "$ERRSTACK_REF" PROGNAME DB_FILE=$RCDIR/$PROGNAME.sqlite umask 022 # Guts # Determine if table creation needed before starting database. { [ -f $DB_FILE ] && NEEDCREATETABLES_FLAG=false; } || NEEDCREATETABLES_FLAG=true ade_debug "$ERRSTACK_REF" 10 "db_prologue: NEEDCREATETABLES_FLAG=$NEEDCREATETABLES_FLAG" mkdir -p $RCDIR # Start the database ade_register_exit_function "$ERRSTACK_REF" ade_disconnect_sqlite || return $? ade_connect_sqlite "$ERRSTACK_REF" "$SEPARATOR" "$EXCLUSIVE_TIMEOUT" || return $? # Create tables and perform other one-time-only initialisation ! $NEEDCREATETABLES_FLAG || init "$ERRSTACK_REF" ade_debug "$ERRSTACK_REF" 10 "db_prologue: eof" return $ADE_OK } db_epilogue() { local ERRSTACK_REF="$1"; shift # Stop the database ade_disconnect_sqlite || return $? ade_deregister_exit_function "$ERRSTACK_REF" ade_disconnect_sqlite || return $? return $ADE_OK } loading paa_opt_handler_rcdir paa_opt_handler_rcdir() { local ERRSTACK_REF="$1"; shift ade_inherit RCDIR RCDIR="$1" return $ADE_OK } loading paa_opt_handler_hostname paa_opt_handler_hostname() { local ERRSTACK_REF="$1"; shift ade_inherit THIS_HOST THIS_HOST="$1" return $ADE_OK } loading paa_opt_handler_rootdir paa_opt_handler_rootdir() { local ERRSTACK_REF="$1"; shift ROOTDIR="$1" return $ADE_OK } loading paa_opt_handler_force paa_opt_handler_force() { local ERRSTACK_REF="$1"; shift FORCE_FLAG=true return $ADE_OK } loading paa_usage_help paa_usage_help() { local ERRSTACK_REF="$1"; shift local USAGE_TEXT_SHORT_REF="$1"; shift local USAGE_TEXT_LONG_REF="$1"; shift eval "$USAGE_TEXT_SHORT_REF=\" [ ]\"" eval "$USAGE_TEXT_LONG_REF=\"\ --rcdir= change rc directory --force force dangerous operations Functions: repo editrepo unrepo listrepos [ ... ] mirror unmirror listmirrors [ ... ] host [ ] unhost listhosts [ ... ] freeze unfreeze listfreezes [ ... ] indirect unindirect listindirects [ ... ] share unshare listshares [ ... ] access unaccess listaccesses [ ... ] insert [,...]
... insert [,...] ... control upgrade listobsolete Notes: 'rpm' or 'deb' repo name or '' 'owned', 'mirrored' or 'accessed' 'true' or 'false' distribution name (e.g. 'debian', 'centos') release number (for RPM-based) or release name (for DEB-based) CPU architecture (according to distributors) hostname, '' or '' freeze, '', '' or ''\"" return $ADE_OK } paa_paths() { local ERRSTACK_REF="$1"; shift local PATHLIST_REF=$1; shift local DB_SCHEMA_CONFORMANCY ade_inherit CODE_SCHEMA_CONFORMANCY || return $? db_prologue "$ERRSTACK_REF" || return $? get_db_schema_conformancy "$ERRSTACK_REF" DB_SCHEMA_CONFORMANCY || return $? db_epilogue "$ERRSTACK_REF" || return $? eval "$PATHLIST_REF=\"Code-Schema-Conformancy: $CODE_SCHEMA_CONFORMANCY Database-Schema-Conformancy: $DB_SCHEMA_CONFORMANCY\"" return $ADE_OK } paa_version() { local ERRSTACK_REF="$1"; shift local VERSION_REF=$1; shift ade_extract_version "$ERRSTACK_REF" "$APP_SVNID" "$VERSION_REF" return $ADE_OK } import_repo_config() { local ERRSTACK_REF="$1"; shift local REPO FILENAME BLOB # Process arguments REPO=$1 FILENAME=$2 # Sanity checks and derivations BLOB=$(gzip < $FILENAME | xxd -p | tr -d '\n') #BLOB=$(gzip < $FILENAME | base64 --wrap=0) ade_debug "$ERRSTACK_REF" 10 "import_repo_config: REPO=$REPO, FILENAME=$FILENAME, BLOB=$BLOB" # Guts ade_write_sql "$ERRSTACK_REF" "update repos set config_gz = X'$BLOB' where repo == '$REPO';" || return $? return $ADE_OK } export_repo_config() { local ERRSTACK_REF="$1"; shift local REPO FILENAME BLOB # Process arguments REPO=$1 FILENAME=$2 # Sanity checks and derivations ade_debug "$ERRSTACK_REF" 10 "export_repo_config: REPO=$REPO, FILENAME=$FILENAME" # Guts ade_write_sql "$ERRSTACK_REF" "select quote(config_gz) from repos where repo == '$REPO';" BLOB || return $? echo "$BLOB" | sed -e 's/^..//' -e 's/.$//' | xxd -r -p | gunzip > $FILENAME return $ADE_OK } detokenise() { local ERRSTACK_REF="$1"; shift local TEXT LOCAL_EXPANDED_TEXT EXPANDED_TEXT_REF # Process arguments [ $# -ge 3 ] || ade_internal "$ERRSTACK_REF" "detokenise: usage error (arg count $#)" SPECIFIED_TEXT="$1" SPECIFIED_EXPANDED_TEXT_REF=$2 shift 2 # Sanity checks and derivations # Guts LOCAL_EXPANDED_TEXT="$SPECIFIED_TEXT" for ASSIGNMENT in "$@"; do [[ $ASSIGNMENT =~ ^([A-Z]+)=(.*)$ ]] || ade_internal "$ERRSTACK_REF" "detokenise: $ASSIGMNENT: invalid assignment" ade_lower_case "$ERRSTACK_REF" ${BASH_REMATCH[1]} TOKEN || return $? TOKEN="<$TOKEN>" VALUE="${BASH_REMATCH[2]}" ade_debug "$ERRSTACK_REF" 10 "detokenise: ASSIGNMENT=$ASSIGNMENT, TOKEN=$TOKEN, VALUE=$VALUE" LOCAL_EXPANDED_TEXT="${LOCAL_EXPANDED_TEXT//$TOKEN/$VALUE}" done ade_debug "$ERRSTACK_REF" 10 "detokenise: SPECIFIED_TEXT=$SPECIFIED_TEXT, LOCAL_EXPANDED_TEXT=$LOCAL_EXPANDED_TEXT" eval "$SPECIFIED_EXPANDED_TEXT_REF=\"\$LOCAL_EXPANDED_TEXT\"" return $ADE_OK } write_test_dir() { local ERRSTACK_REF="$1"; shift local DIR PROGNAME [ $# = 1 ] || ade_internal "$ERRSTACK_REF" "write_test_dir: bad arg count ($#)" DIR=$1 # Sanity checks and derivations ade_get_progname "$ERRSTACK_REF" PROGNAME # Create and test writability of $DIR if ! mkdir -p $DIR/.$PROGNAME.$$.write-test 2>/dev/null; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$DIR: can't write" return $ADE_FAIL fi rmdir $DIR/.$PROGNAME.$$.write-test return $ADE_OK } write_test_file() { local ERRSTACK_REF="$1"; shift local FILE [ $# = 1 ] || ade_internal "$ERRSTACK_REF" "write_test_file: bad arg count ($#)" FILE=$1 if [ -f $FILE ] && [ ! -w $FILE ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$FILE: can't write" elif [ ! -f $FILE ]; then write_test_dir "$ERRSTACK_REF" "$(dirname "$FILE")" || return $? fi return $ADE_OK } reload_apache() { local ERRSTACK_REF="$1"; shift local COUNT PKGTYPE PROGNAME ade_global THIS_HOST # Process arguments [ $# = 0 ] || ade_internal "$ERRSTACK_REF" "reload_apache: bad arg count ($#)" # Sanity checks and derivations ade_get_progname "$ERRSTACK_REF" PROGNAME [ -w $ROOTDIR ] || { ade_warning "$ERRSTACK_REF" PAA_ERR_MISC "you are not root so apache config will not be reloaded now; you should do it later"; return $ADE_OK; } ade_write_sql "$ERRSTACK_REF" "select count(*) from hosts where host == '$THIS_HOST';" COUNT || return $? if [ $COUNT != 1 ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "don't know how to reload apache configuration (you need to register this host with '$PROGNAME host THIS-HOST')" return $ADE_FAIL fi ade_write_sql "$ERRSTACK_REF" "select pkgtype from hosts where host == '$THIS_HOST';" PKGTYPE || return $? # Guts reload_apache_$PKGTYPE "$ERRSTACK_REF" || return $? return $ADE_OK } compile_config() { local ERRSTACK_REF="$1"; shift local SPECIFIED_REPO SPECIFIED_FILENAME SPECIFIED_COMPLETEFLAG_REF local SECTIONS REAL_RELEASES PORTS COMPATIBILITIES LAYOUTS DISTRO REPOPATH FREEZE_DIR INDIRECT_DIR URL local DB_MIRROR_CMD DB_REPOPATH DB_MIRROR_DIR DB_FREEZE_DIR DB_INDIRECT_DIR DB_URL DB_ORIGIN DB_LABEL DB_SIGNER DB_DISTRO local SH_OUTPUT REQUIRED_DIRECTIVES REQUIRED_DIRECTIVE REQUIRED_VARIABLE TUPLES TUPLE # Process arguments [ $# = 3 ] || ade_internal "$ERRSTACK_REF" "compile_config: bad arg count ($#)" SPECIFIED_REPO=$1 SPECIFIED_FILENAME=$2 SPECIFIED_COMPLETEFLAG_REF=$3 ade_debug "$ERRSTACK_REF" 10 "compile_config: SPECIFIED_REPO=$SPECIFIED_REPO, SPECIFIED_FILENAME=$SPECIFIED_FILENAME, SPECIFIED_COMPLETEFLAG_REF=$SPECIFIED_COMPLETEFLAG_REF" # Sanity checks and derivations # Assume compilation fails until proven otherwise. eval "$SPECIFIED_COMPLETEFLAG_REF=\"false\"" # Guts # Check loadable ade_debug "$ERRSTACK_REF" 10 "compile_config: checking loadable ..." check_loadable "$ERRSTACK_REF" $SPECIFIED_REPO $SPECIFIED_FILENAME || return $? # Load for real. # # This is done by copying all directives and parameters to a staging # area (STAGING_WHATEVER_INDEX[]) and then, once sourcing the config # file has finished, reading the staging area and processing the settings # therein. This delay is done because errors during processing cannot # be easily trapped if done during a sourcing (search bash(1) for 'posix # mode' for details). # # The saving to the staging area and the procesing are done by the # directive-handling functions, which are refined during these two # phases. ade_debug "$ERRSTACK_REF" 10 "compile_config: telling directives to save their parameters to staging area ..." tell_directives_to_save_their_parameters_to_staging "$ERRSTACK_REF" || return $? ade_debug "$ERRSTACK_REF" 10 "compile_config: loading to staging area ..." . $SPECIFIED_FILENAME || true ade_debug "$ERRSTACK_REF" 10 "compile_config: loading to staging area completed" # Load up the real directives, 'cos we're about to call them. ade_debug "$ERRSTACK_REF" 10 "compile_config: telling directives to save staged parameters to real area ..." tell_directives_to_transfer_parameters_from_stating_to_real "$ERRSTACK_REF" || return $? # Blank all the variables we expect the applying to fill. REAL_RELEASES=() REAL_MIRROR_CMD= REAL_REPOPATH= REAL_URL= REAL_FREEZE_DIR= REAL_INDIRECT_DIR= REAL_MIRROR_DIR= REAL_DISTRO= REAL_ORIGIN= REAL_LABEL= REAL_SIGNER= ade_debug "$ERRSTACK_REF" 10 "compile_config: loading from staging to real area ..." apply_directives "$ERRSTACK_REF" $SPECIFIED_REPO || return $? # If we get this far then tell the caller that compilation was successful. eval "$SPECIFIED_COMPLETEFLAG_REF=\"true\"" # Unlocking (making available and updating timestamp) will be done in caller. return $ADE_OK } check_loadable() { local ERRSTACK_REF="$1"; shift local REPO FILENAME local SH_OUTPUT SH_RC ade_inherit DIRECTIVES # Process arguments [ $# = 2 ] || ade_internal "$ERRSTACK_REF" "check_loadable: bad arg count ($#)" REPO=$1 FILENAME=$2 ade_debug "$ERRSTACK_REF" 10 "check_loadable: REPO=$REPO, FILENAME=$FILENAME" SH_OUTPUT=$(bash -c "for DIRECTIVE in $DIRECTIVES; do eval \"\$DIRECTIVE(){ :; }\"; done; . $FILENAME" 2>&1) SH_RC=$? [ "X$SH_OUTPUT" = X ] || echo "$SH_OUTPUT" >&2 if [ $SH_RC != 0 ] || [ "X$SH_OUTPUT" != X ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: syntax error (see above output for hints)" return $ADE_FAIL fi return $ADE_OK } tell_directives_to_save_their_parameters_to_staging() { local ERRSTACK_REF="$1"; shift local DIRECTIVE DIRECTIVE_UC ade_inherit DIRECTIVES for DIRECTIVE in $DIRECTIVES; do ade_debug "$ERRSTACK_REF" 10 "tell_directives_to_save_their_parameters_to_staging: resetting $DIRECTIVE() directive to save its parameters to staging area ..." # Reset staging area counter. ade_upper_case "$ERRSTACK_REF" $DIRECTIVE DIRECTIVE_UC || return $? eval "STAGING_${DIRECTIVE_UC}_IDX=0" # Define function to save directive's parameters to staging area. # Note: no error stack because caller won't pass on and nothing # can go wrong here (famous last words). eval "$DIRECTIVE() { # Staging directives (the ones the user uses) are not # passed an error stack (because the user calls them) # so they must inherit. ade_inherit ERRSTACK_REF ade_debug \"\$ERRSTACK_REF\" 10 \"$DIRECTIVE: saving parameters to staging area (\$*) ...\" eval \"STAGING_${DIRECTIVE_UC}_\$STAGING_${DIRECTIVE_UC}_IDX=( \\\"\\\$@\\\" )\" ((++STAGING_${DIRECTIVE_UC}_IDX)) }" done return $ADE_OK } apply_directives() { local ERRSTACK_REF="$1"; shift local DIRECTIVE REQUIRED_DIRECTIVES REQUIRED_DIRECTIVE I J local PKGTYPE REPOTYPE IS_DISTRO local REPO local LAYOUTS PORTS SECTIONS COMPATS_PKGTYPE COMPATS_DISTRO COMPATS_DISTRO_RELEASE DIRECTIVE_UC REQUIRED_DIRECTIVE_UC ade_inherit SEPARATOR # Process arguments REPO="$1" # Sanity checks and derivations # For each directive, invoke the real handler passing the parameters # saved to the staging area, one batch at a time. # Note: the real handlers *do* have an error stack. for DIRECTIVE in $DIRECTIVES; do ade_upper_case "$ERRSTACK_REF" $DIRECTIVE DIRECTIVE_UC || return $? ade_debug "$ERRSTACK_REF" 10 "apply_directives: calling real '$DIRECTIVE' directive with staged parameters ..." eval "for ((I=0; I<\$STAGING_${DIRECTIVE_UC}_IDX; I++)); do # Move $STAGING_WHATEVER_I[] to $@ to avoid too much eval-ing. eval \"set -- \\\"\\\${STAGING_${DIRECTIVE_UC}_\$I[@]}\\\"\" $DIRECTIVE \"\$ERRSTACK_REF\" \"\$@\" || return \$? done" done # At this point, the staging area could be destroyed. # To work out what extended attributes need to be provided, we need to # get some core attributes. ade_write_sql "$ERRSTACK_REF" "select pkgtype, repotype, is_distro from repos where repo == '$REPO';" TUPLE || return $? ade_split_string "$ERRSTACK_REF" "$TUPLE" "$SEPARATOR" PKGTYPE REPOTYPE IS_DISTRO || return $? ade_debug "$ERRSTACK_REF" 10 "compile_config: PKGTYPE=$PKGTYPE, REPOTYPE=$REPOTYPE, IS_DISTRO=$IS_DISTRO" # Work out what, based on the core repo parameters, should have # been provided in the extended repo parameters. ade_debug "$ERRSTACK_REF" 10 "apply_directives: working out what should have been provided ..." REQUIRED_DIRECTIVES="url" [ $REPOTYPE != owned ] || REQUIRED_DIRECTIVES="$REQUIRED_DIRECTIVES path" [ $REPOTYPE != owned -o $PKGTYPE != deb ] || REQUIRED_DIRECTIVES="$REQUIRED_DIRECTIVES origin label signer" [ $REPOTYPE != mirrored ] || REQUIRED_DIRECTIVES="$REQUIRED_DIRECTIVES mirror_cmd mirror_dir freeze_dir indirect_dir" [ "X$IS_DISTRO" != Xtrue ] || REQUIRED_DIRECTIVES="$REQUIRED_DIRECTIVES distro" ade_debug "$ERRSTACK_REF" 10 "compile_config: REQUIRED_DIRECTIVES=\"$REQUIRED_DIRECTIVES\"" # Check that everything that is required was provided. ade_debug "$ERRSTACK_REF" 10 "apply_directives: checking for unprovided required directives ..." for REQUIRED_DIRECTIVE in $REQUIRED_DIRECTIVES; do ade_upper_case "$ERRSTACK_REF" $REQUIRED_DIRECTIVE REQUIRED_DIRECTIVE_UC || return $? if [ $REQUIRED_DIRECTIVE != path ]; then REQUIRED_VARIABLE=REAL_$REQUIRED_DIRECTIVE_UC else REQUIRED_VARIABLE=REAL_REPOPATH fi if eval "[ \"X\$$REQUIRED_VARIABLE\" = X ]"; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: $REQUIRED_DIRECTIVE: missing directive" return $ADE_FAIL fi done if [ ${#REAL_RELEASES[*]} = 0 ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: release: missing directive" return $ADE_FAIL fi for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do # Check deb repos have sections but not layouts and that rpm repos have layouts but # not sections. (Fake sections and layouts will be added in a moment.) if [ $PKGTYPE = deb ] && eval "[ \${#REAL_SECTIONS_$I[*]} = 0 ]"; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: section: missing directive for release ${REAL_RELEASES[$I]}" return $ADE_FAIL elif [ $PKGTYPE = rpm ] && eval "[ \${#REAL_SECTIONS_$I[*]} != 0 ]"; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: section: superfluous directive" return $ADE_FAIL elif [ $PKGTYPE = deb ] && eval "[ \"X\$REAL_LAYOUT_$I\" != X ]"; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: layout: superfluous directive" return $ADE_FAIL elif [ $PKGTYPE = rpm ] && eval "[ \"X\$REAL_LAYOUT_$I\" = X ]"; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: layout: missing directive for release ${REAL_RELEASES[$I]}" return $ADE_FAIL elif eval "[ \${#REAL_PORTS_$I[*]} = 0 ]"; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: port: missing directive for release ${REAL_RELEASES[$I]}" return $ADE_FAIL # Don't bother checking *all* attributes of a compat; one is enough. elif ! $IS_DISTRO && eval "[ \${#REAL_COMPATS_${I}_PKGTYPE[*]} = 0 ]"; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: compat: missing directive for release ${REAL_RELEASES[$I]}" return $ADE_FAIL elif $IS_DISTRO && eval "[ \${#REAL_COMPATS_${I}_PKGTYPE[*]} != 0 ]"; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: compat: superfluous directive for release ${REAL_RELEASES[$I]}" return $ADE_FAIL fi done if [ $REPOTYPE = mirrored -a "X$REAL_REPOPATH" != X ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: path: superfluous directive" return $ADE_FAIL elif [ \( $REPOTYPE = owned -o $REPOTYPE = accessed \) -a "X$REAL_MIRROR_CMD" != X ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: mirror_cmd: superfluous directive" return $ADE_FAIL elif [ $REPOTYPE = accessed -a "X$REAL_FREEZE_DIR" != X ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: freeze_dir: superfluous directive" return $ADE_FAIL elif [ $REPOTYPE = accessed -a "X$REAL_INDIRECT_DIR" != X ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: indirect_dir: superfluous directive" return $ADE_FAIL elif [ $REPOTYPE = accessed -a "X$REAL_MIRROR_DIR" != X ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPO: mirror_dir: superfluous directive" return $ADE_FAIL fi # Seed deb repos' layouts and rpm repos' sections. These are release-specific. for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do if [ $PKGTYPE = deb ]; then eval "REAL_LAYOUT_$I=\"pool\"" elif [ $PKGTYPE = rpm ]; then push "$ERRSTACK_REF" REAL_SECTIONS_$I "universal-section" || return $? fi done # Sort out quoting/nullifying. ade_debug "$ERRSTACK_REF" 10 "apply_directives: sorting out quoting/nullifying ..." if [ $REPOTYPE = owned ]; then DB_PATH="'$REAL_REPOPATH'" else DB_PATH="NULL" fi if [ $REPOTYPE = owned -a $PKGTYPE = deb ]; then DB_ORIGIN="'$REAL_ORIGIN'" DB_LABEL="'$REAL_LABEL'" DB_SIGNER="'$REAL_SIGNER'" else DB_ORIGIN="NULL" DB_LABEL="NULL" DB_SIGNER="NULL" fi if [ $REPOTYPE = mirrored ]; then # Quote the string in single quotes and change any single quotes in the string # to be *two* single quotes (this is the SQLite way to get a single quote). # Note that this gets vim's syntax highlighting out of sync. DB_MIRROR_CMD="'${REAL_MIRROR_CMD//\'/''}'" else DB_MIRROR_CMD="NULL" fi if [ $REPOTYPE = owned -o $REPOTYPE = mirrored ]; then DB_MIRROR_DIR="'$REAL_MIRROR_DIR'" DB_FREEZE_DIR="'$REAL_FREEZE_DIR'" DB_INDIRECT_DIR="'$REAL_INDIRECT_DIR'" else DB_MIRROR_DIR="NULL" DB_FREEZE_DIR="NULL" DB_INDIRECT_DIR="NULL" fi if [ "X$IS_DISTRO" = Xtrue ]; then DB_DISTRO="'$REAL_DISTRO'" else DB_DISTRO="NULL" fi ade_debug "$ERRSTACK_REF" 10 "apply_directives: regenerating extended info ..." # Update extendeds ade_write_sql "$ERRSTACK_REF" "insert into extendeds (repo,path,mirror_cmd,mirror_dir,freeze_dir,indirect_dir,url,distro,origin,label,signer) values ('$REPO', $DB_PATH, $DB_MIRROR_CMD, $DB_MIRROR_DIR, $DB_FREEZE_DIR, $DB_INDIRECT_DIR, '$REAL_URL', $DB_DISTRO, $DB_ORIGIN, $DB_LABEL, $DB_SIGNER);" || return $? # Update releases for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do eval "LAYOUT=\"\$REAL_LAYOUT_$I\"" ade_write_sql "$ERRSTACK_REF" "insert into releases (repo, release, layout) values ('$REPO', '${REAL_RELEASES[$I]}', '$LAYOUT');" || return $? done # Update ports for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do eval "PORTS=( \"\${REAL_PORTS_$I[@]}\" )" for ((J=0; J<${#PORTS[*]}; J++)); do ade_write_sql "$ERRSTACK_REF" "insert into ports (repo, release, port) values ('$REPO', '${REAL_RELEASES[$I]}', '${PORTS[$J]}');" || return $? done done # Update sections for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do eval "SECTIONS=( \"\${REAL_SECTIONS_$I[@]}\" )" for ((J=0; J<${#SECTIONS[*]}; J++)); do ade_write_sql "$ERRSTACK_REF" "insert into sections (repo, release, section) values ('$REPO', '${REAL_RELEASES[$I]}', '${SECTIONS[$J]}');" || return $? done done # Update compats for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do eval "COMPATS_PKGTYPE=( \"\${REAL_COMPATS_${I}_PKGTYPE[@]}\" )" eval "COMPATS_DISTRO=( \"\${REAL_COMPATS_${I}_DISTRO[@]}\" )" eval "COMPATS_DISTRO_RELEASE=( \"\${REAL_COMPATS_${I}_DISTRO_RELEASE[@]}\" )" for ((J=0; J<${#COMPATS_PKGTYPE[*]}; J++)); do # In the database store '*' as NULL. { [ "X${COMPATS_PKGTYPE[$J]}" != X -a "X${COMPATS_PKGTYPE[$J]}" != "X*" ] && DB_PKGTYPE="'${COMPATS_PKGTYPE[$J]}'"; } || DB_PKGTYPE=NULL { [ "X${COMPATS_DISTRO[$J]}" != X -a "X${COMPATS_DISTRO[$J]}" != "X*" ] && DB_DISTRO="'${COMPATS_DISTRO[$J]}'"; } || DB_DISTRO=NULL { [ "X${COMPATS_DISTRO_RELEASE[$J]}" != X -a "X${COMPATS_DISTRO_RELEASE[$J]}" != "X*" ] && DB_DISTRO_RELEASE="'${COMPATS_DISTRO_RELEASE[$J]}'"; } || DB_DISTRO_RELEASE=NULL ade_write_sql "$ERRSTACK_REF" "insert into compatibilities (repo, release, pkgtype, distro, distro_release) values ('$REPO', '${REAL_RELEASES[$I]}', $DB_PKGTYPE, $DB_DISTRO, $DB_DISTRO_RELEASE);" || return $? done done return $ADE_OK } tell_directives_to_transfer_parameters_from_stating_to_real() { local ERRSTACK_REF="$1"; shift local DIRECTIVE DIRECTIVE_UC ade_inherit DIRECTIVES DIRECTIVE=release ade_debug "$ERRSTACK_REF" 10 "tell_directives_to_transfer_parameters_from_stating_to_real: resetting $DIRECTIVE() directive to save its parameters to real area ..." release() { local ERRSTACK_REF="$1"; shift local RELEASE I [ $# = 1 ] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "release: bad argument count (expected 1, got $#)"; return $ADE_FAIL; } RELEASE=$1 ade_debug "$ERRSTACK_REF" 10 "release: RELEASE=$RELEASE" # Sanity checks and derivations validate_release "$ERRSTACK_REF" "$RELEASE" || return $? ade_inherit --allow-empty REAL_RELEASES # Guts ade_debug "$ERRSTACK_REF" 10 "release: saving parameters to real area ($*) ..." push "$ERRSTACK_REF" REAL_RELEASES "$RELEASE" || return $? ade_debug "$ERRSTACK_REF" 10 "release: REAL_RELEASES=( ${REAL_RELEASES[*]} )" # Initialise associated arrays (no need to scan REAL_RELEASES for RELEASE; it's at the end) I=$((${#REAL_RELEASES[*]} - 1)) eval "REAL_PORTS_$I=()" eval "REAL_SECTIONS_$I=()" eval "REAL_LAYOUT_$I=" eval "REAL_COMPATS_${I}_PKGTYPE=()" eval "REAL_COMPATS_${I}_DISTRO=()" eval "REAL_COMPATS_${I}_DISTRO_RELEASE=()" return $ADE_OK } DIRECTIVE=port ade_debug "$ERRSTACK_REF" 10 "tell_directives_to_transfer_parameters_from_stating_to_real: resetting $DIRECTIVE() directive to save its parameters to real area ..." port() { local ERRSTACK_REF="$1"; shift local RELEASE PORT I [ $# = 2 ] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "port: bad argument count (expected 2, got $#)"; return $ADE_FAIL; } RELEASE=$1 PORT=$2 ade_debug "$ERRSTACK_REF" 10 "port: RELEASE=$RELEASE, PORT=$PORT" # Sanity checks and derivations validate_release "$ERRSTACK_REF" "$RELEASE" || return $? validate_port "$ERRSTACK_REF" "$PORT" || return $? # Find ID of release ade_debug "$ERRSTACK_REF" 10 "port: scanning RELEASES for $RELEASE ..." for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do [ $RELEASE != ${REAL_RELEASES[$I]} ] || break done if [ $I = ${#REAL_RELEASES[*]} ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$RELEASE: invalid release" return $ADE_FAIL fi ade_debug "$ERRSTACK_REF" 10 "port: found it; release index is $I" ade_inherit --allow-empty REAL_PORTS_$I # Guts ade_debug "$ERRSTACK_REF" 10 "port: saving parameters to real area ($*) ..." push "$ERRSTACK_REF" REAL_PORTS_$I "$PORT" || return $? eval "ade_debug \"\$ERRSTACK_REF\" 10 \"port: REAL_PORTS_$I=( \${REAL_PORTS_$I[*]} )\"" return $ADE_OK } DIRECTIVE=section ade_debug "$ERRSTACK_REF" 10 "tell_directives_to_transfer_parameters_from_stating_to_real: resetting $DIRECTIVE() directive to save its parameters to real area ..." section() { local ERRSTACK_REF="$1"; shift local RELEASE SECTION I [ $# = 2 ] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "section: bad argument count (expected 2, got $#)"; return $ADE_FAIL; } RELEASE=$1 SECTION=$2 ade_debug "$ERRSTACK_REF" 10 "section: RELEASE=$RELEASE, SECTION=$SECTION" # Sanity checks and derivations validate_release "$ERRSTACK_REF" "$RELEASE" || return $? validate_section "$ERRSTACK_REF" "$SECTION" || return $? # Find ID of release for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do [ $RELEASE != ${REAL_RELEASES[$I]} ] || break done if [ $I = ${#REAL_RELEASES[*]} ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$RELEASE: invalid release" return $ADE_FAIL fi ade_inherit --allow-empty REAL_SECTIONS_$I # Guts ade_debug "$ERRSTACK_REF" 10 "section: saving parameters to real area ($*) ..." push "$ERRSTACK_REF" REAL_SECTIONS_$I "$SECTION" || return $? eval "ade_debug \"\$ERRSTACK_REF\" 10 \"section: REAL_SECTIONS_$I=( \${REAL_SECTIONS_$I[*]} )\"" return $ADE_OK } DIRECTIVE=layout ade_debug "$ERRSTACK_REF" 10 "tell_directives_to_transfer_parameters_from_stating_to_real: resetting $DIRECTIVE() directive to save its parameters to real area ..." layout() { local ERRSTACK_REF="$1"; shift local RELEASE LAYOUT I [ $# = 2 ] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "layout: bad argument count (expected 2, got $#)"; return $ADE_FAIL; } RELEASE=$1 LAYOUT=$2 ade_debug "$ERRSTACK_REF" 10 "layout: RELEASE=$RELEASE, LAYOUT=$LAYOUT" # Sanity checks and derivations validate_release "$ERRSTACK_REF" "$RELEASE" || return $? validate_layout "$ERRSTACK_REF" "$LAYOUT" || return $? # Find ID of release for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do [ $RELEASE != ${REAL_RELEASES[$I]} ] || break done if [ $I = ${#REAL_RELEASES[*]} ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$RELEASE: invalid release" return $ADE_FAIL fi ade_inherit --ensure-empty REAL_LAYOUT_$I # Guts ade_debug "$ERRSTACK_REF" 10 "layout: saving parameters to real area ($*) ..." eval "REAL_LAYOUT_$I=\"$LAYOUT\"" eval "ade_debug \"\$ERRSTACK_REF\" 10 \"layout: REAL_LAYOUT_$I=\$REAL_LAYOUT_$I )\"" return $ADE_OK } DIRECTIVE=compat ade_debug "$ERRSTACK_REF" 10 "tell_directives_to_transfer_parameters_from_stating_to_real: resetting $DIRECTIVE() directive to save its parameters to real area ..." compat() { local ERRSTACK_REF="$1"; shift local RELEASE PKGTYPE DISTRO DISTRO_RELEASE I [ $# = 4 ] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "compat: bad argument count (expected 4, got $#)"; return $ADE_FAIL; } RELEASE=$1 PKGTYPE=$2 DISTRO=$3 DISTRO_RELEASE=$4 ade_debug "$ERRSTACK_REF" 10 "compat: RELEASE=$RELEASE, PKGTYPE=$PKGTYPE, DISTRO=$DISTRO, DISTRO_RELEASE=$DISTRO_RELEASE" # Sanity checks and derivations validate_release "$ERRSTACK_REF" "$RELEASE" || return $? # Allow '*' else sanity check as normal. for VAR in PKGTYPE DISTRO DISTRO_RELEASE; do ade_lower_case "$ERRSTACK_REF" $VAR VAR_LC || return $? eval "[ \"X\$$VAR\" = \"X*\" ] || validate_$VAR_LC \"\$ERRSTACK_REF\" \"\$$VAR\"" || return $? done # Find ID of release for ((I=0; I<${#REAL_RELEASES[*]}; I++)); do [ $RELEASE != ${REAL_RELEASES[$I]} ] || break done if [ $I = ${#REAL_RELEASES[*]} ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$RELEASE: invalid release" return $ADE_FAIL fi ade_inherit --allow-empty REAL_COMPATS_${I}_PKGTYPE ade_inherit --allow-empty REAL_COMPATS_${I}_DISTRO ade_inherit --allow-empty REAL_COMPATS_${I}_DISTRO_RELEASE # Guts ade_debug "$ERRSTACK_REF" 10 "compat: saving parameters to real area ($*) ..." push "$ERRSTACK_REF" REAL_COMPATS_${I}_PKGTYPE "$PKGTYPE" || return $? push "$ERRSTACK_REF" REAL_COMPATS_${I}_DISTRO "$DISTRO" || return $? push "$ERRSTACK_REF" REAL_COMPATS_${I}_DISTRO_RELEASE "$DISTRO_RELEASE" || return $? eval "ade_debug \"\$ERRSTACK_REF\" 10 \"compat: REAL_COMPATS_${I}_PKGTYPE=( \${REAL_COMPATS_${I}_PKGTYPE[*]} )\"" eval "ade_debug \"\$ERRSTACK_REF\" 10 \"compat: REAL_COMPATS_${I}_DISTRO=( \${REAL_COMPATS_${I}_DISTRO[*]} )\"" eval "ade_debug \"\$ERRSTACK_REF\" 10 \"compat: REAL_COMPATS_${I}_DISTRO_RELEASE=( \${REAL_COMPATS_${I}_DISTRO_RELEASE[*]} )\"" return $ADE_OK } for DIRECTIVE in $DIRECTIVES; do # Some directives have non-standard handlers, which we've defined above. [ $DIRECTIVE != compat ] || continue [ $DIRECTIVE != port ] || continue [ $DIRECTIVE != section ] || continue [ $DIRECTIVE != layout ] || continue [ $DIRECTIVE != release ] || continue ade_upper_case "$ERRSTACK_REF" $DIRECTIVE DIRECTIVE_UC || return $? ade_debug "$ERRSTACK_REF" 10 "tell_directives_to_transfer_parameters_from_stating_to_real: resetting $DIRECTIVE() directive to save its parameters to real area ..." eval "$DIRECTIVE() { local ERRSTACK_REF=\"\$1\"; shift local THING VARIABLE [ \$# = 1 ] || { ade_error \"\$ERRSTACK_REF\" PAA_ERR_MISC \"$DIRECTIVE: bad argument count (expected 1, got \$#)\"; return \$ADE_FAIL; } THING=\"\$1\" ade_debug \"\$ERRSTACK_REF\" 10 \"$DIRECTIVE: THING=\$THING\" # Sanity checks and derivations validate_$DIRECTIVE \"\$ERRSTACK_REF\" \$THING || return \$? if [ $DIRECTIVE = path ]; then VARIABLE=REAL_REPOPATH else VARIABLE=REAL_$DIRECTIVE_UC fi ade_inherit --ensure-empty \$VARIABLE # Guts ade_debug \"\$ERRSTACK_REF\" 10 \"$DIRECTIVE: saving parameters to real area (\$*) ...\" eval \"\$VARIABLE=\\\"\\\$THING\\\"\" return \$ADE_OK }" done return $ADE_OK } generate_config_template() { local ERRSTACK_REF="$1"; shift local SPECIFIED_REPO SPECIFIED_IS_DISTRO SPECIFIED_PKGTYPE SPECIFIED_REPOTYPE local ORIGIN LABEL SIGNER ade_inherit LOGNAME THIS_HOST || return $? # Process arguments [ $# = 4 ] || ade_internal "$ERRSTACK_REF" "generate_config_template: bad arg count ($#)" SPECIFIED_REPO=$1 SPECIFIED_IS_DISTRO=$2 SPECIFIED_PKGTYPE=$3 SPECIFIED_REPOTYPE=$4 ade_debug "$ERRSTACK_REF" 10 "generate_config_template: SPECIFIED_IS_DISTRO=$SPECIFIED_IS_DISTRO, SPECIFIED_PKGTYPE=$SPECIFIED_PKGTYPE, SPECIFIED_REPOTYPE=$SPECIFIED_REPOTYPE" # Sanity checks and derivations if [ $LOGNAME != root ]; then ORIGIN="$(getent passwd $LOGNAME | cut -f5 -d: | cut -f1 -d,)" LABEL="$ORIGIN" SIGNER="$LOGNAME" else ORIGIN="$THIS_HOST Superuser" LABEL="$ORIGIN" SIGNER="$LOGNAME" fi # Guts { echo "##############################################################################" echo "#" echo "# Internal variables (defined for convenience and referenced only from within" echo "# this file)" echo "#" echo "##############################################################################" echo if [ $SPECIFIED_PKGTYPE = deb ]; then echo "#_RELEASES=\"squeeze\"" echo "#_PORTS=\"i386 amd64\"" else echo "#_RELEASES=\"4 5 6\"" echo "#_PORTS=\"i386 x86_64\"" fi if [ $SPECIFIED_PKGTYPE = deb ]; then if $SPECIFIED_IS_DISTRO; then echo "#_SECTIONS=\"main contrib non-free main/debian-installer\"" else echo "#_SECTIONS=\"main\"" fi elif [ $SPECIFIED_PKGTYPE = rpm ]; then echo "# Local repos look like this:" echo "#_LAYOUT=\"/\"" echo "# EPEL repos look like this:" echo "#_LAYOUT=\"/\"" echo "# Scientific Linux looks like this:" echo "#_LAYOUT=\"//os\"" echo "# CentOS looks like this:" echo "#_LAYOUT=\"/os/\"" echo "# Fedora looks like this:" echo "#_LAYOUT=\"/Fedora//os\"" fi echo echo "##############################################################################" echo "#" echo "# Repository contents (defines what is in or may be inserted into this repo)" echo "#" echo "##############################################################################" echo if [ $SPECIFIED_PKGTYPE = deb ]; then echo "# The set of *all* releases, ports and sections this repository will contain." else echo "# The set of *all* releases and ports this repository will contain." fi echo "for _RELEASE in \$_RELEASES; do" echo " release \$_RELEASE" echo " for _PORT in \$_PORTS; do" echo " port \$_RELEASE \$_PORT" echo " done" if [ $SPECIFIED_PKGTYPE = deb ]; then echo " for _SECTION in \$_SECTIONS; do" echo " section \$_RELEASE \$_SECTION" echo " done" # layout will be hard-coded after config file is loaded. elif [ $SPECIFIED_PKGTYPE = rpm ]; then # section will be hard-coded after config file is loaded. echo " layout \$_RELEASE \$_LAYOUT" fi echo "done" echo if ! $SPECIFIED_IS_DISTRO; then echo "##############################################################################" echo "#" echo "# Compatibility (defines on which distros each release in this non-distro" echo "# repo may be installed)" echo "#" echo "##############################################################################" echo "" echo "# Each release in this repository is compatible with which distros?" echo "#for _RELEASE in \$_RELEASES; do" if [ $SPECIFIED_PKGTYPE = deb ]; then echo "# compat \$_RELEASE deb debian \$_RELEASE" echo "#done" echo "#compat squeeze deb ubuntu \*" else echo "# compat \$_RELEASE rpm rhel \$_RELEASE" echo "# compat \$_RELEASE rpm scientificlinux \$_RELEASE" echo "# compat \$_RELEASE rpm centos \$_RELEASE" echo "#done" echo "#compat 6 rpm fedora \*" echo "#compat 6 rpm sles \*" fi echo fi echo "##############################################################################" echo "#" echo "# Misc settings" echo "#" echo "##############################################################################" echo "" echo "# URL to access the repo" echo "#url \"http://install.pasta.net/./\"" if [ $SPECIFIED_REPOTYPE != accessed ]; then echo "# The path to your mirror" echo "#mirror_dir \"/pub/mirrors/\"" echo "# The path to your freezes" echo "#freeze_dir \"/pub/freezes/.\"" echo "# The path to your indirects" echo "#indirect_dir \"/pub/indirects/.\"" echo "# What IP mask should be used for sharing?" fi if [ $SPECIFIED_REPOTYPE = mirrored -a $SPECIFIED_PKGTYPE = deb ] && $SPECIFIED_IS_DISTRO; then echo "# The command to update the mirror in the current directory." echo "#mirror_cmd \"debmirror --rsync-options=\\\"-aIL --partial --no-motd\\\" --ignore-release-gpg --i18n --getcontents --nosource --method=rsync --host=ftp2.de.debian.org --root=:debian --arch=\${_PORTS// /,} --dist=\${_RELEASES// /,} --section=\${_SECTIONS// /,} --di-dist=dists --di-arch=arches .\"" elif [ $SPECIFIED_REPOTYPE = mirrored -a $SPECIFIED_PKGTYPE = deb ]; then echo "# The command to update the mirror in the current directory." echo "#mirror_cmd \"debmirror --rsync-options=\\\"-aIL --partial --no-motd\\\" --ignore-release-gpg --getcontents --nosource --method=rsync --host=ftp2.de.debian.org --root=:debian --arch=\${_PORTS// /,} --dist=\${_RELEASES// /,} --section=\${_SECTIONS// /,} --di-dist=dists --di-arch=arches .\"" elif [ $SPECIFIED_REPOTYPE = mirrored -a $SPECIFIED_PKGTYPE = rpm ]; then echo "# The command to update the mirror in the current directory." echo "#mirror_cmd \"rpmmirror --releases=\${_RELEASES// /,} --ports=\${_PORTS// /,} --layout=\\\"\$_LAYOUT\\\" rsync://rsync.scientificlinux.org/scientific .\"" elif [ $SPECIFIED_REPOTYPE = owned ]; then echo "# Path to the repository (not the mirror of the repository)" echo "#path /pub/local-repos/$SPECIFIED_REPO" fi if $SPECIFIED_IS_DISTRO; then echo "# Which distribution is this repo for?" echo "#distro debian" fi if [ $SPECIFIED_PKGTYPE = deb -a $SPECIFIED_REPOTYPE = owned ]; then echo "# Debian repositories need to know a few other things." echo "origin \"$ORIGIN\"" echo "label \"$LABEL\"" echo "signer \"$SIGNER\"" fi } return $ADE_OK } validate_origin() { local ERRSTACK_REF="$1"; shift local ORIGIN ORIGIN="$1" ade_debug "$ERRSTACK_REF" 10 "validate_origin: ORIGIN=$ORIGIN" # Guts validate_word "$ERRSTACK_REF" "$ORIGIN" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$ORIGIN: invalid origin" return $ADE_FAIL } return $ADE_OK } validate_label() { local ERRSTACK_REF="$1"; shift local LABEL LABEL="$1" ade_debug "$ERRSTACK_REF" 10 "validate_label: LABEL=$LABEL" # Guts validate_word "$ERRSTACK_REF" "$LABEL" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$LABEL: invalid label" return $ADE_FAIL } return $ADE_OK } validate_signer() { local ERRSTACK_REF="$1"; shift local SIGNER SIGNER="$1" ade_debug "$ERRSTACK_REF" 10 "validate_signer: SIGNER=$SIGNER" # Guts validate_word "$ERRSTACK_REF" "$SIGNER" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$SIGNER: invalid signer" return $ADE_FAIL } return $ADE_OK } validate_distro_release() { local ERRSTACK_REF="$1"; shift local DISTRO_RELEASE DISTRO_RELEASE="$1" ade_debug "$ERRSTACK_REF" 10 "validate_distro_release: DISTRO_RELEASE=$DISTRO_RELEASE" # Guts validate_release "$ERRSTACK_REF" "$DISTRO_RELEASE" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$DISTRO_RELEASE: invalid DISTRO release" return $ADE_FAIL } return $ADE_OK } validate_mirror_cmd() { local ERRSTACK_REF="$1"; shift local MIRROR_CMD MIRROR_CMD="$1" ade_debug "$ERRSTACK_REF" 10 "validate_mirror_cmd: MIRROR_CMD=$MIRROR_CMD" # Guts : return $ADE_OK } validate_path() { local ERRSTACK_REF="$1"; shift local REPOPATH REPOPATH="$1" ade_debug "$ERRSTACK_REF" 10 "validate_path: REPOPATH=$REPOPATH" # Guts validate_dir "$ERRSTACK_REF" "$REPOPATH" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$REPOPATH: invalid path" return $ADE_FAIL } return $ADE_OK } validate_pkgtype() { local ERRSTACK_REF="$1"; shift local PKGTYPE PKGTYPE="$1" ade_debug "$ERRSTACK_REF" 10 "validate_pkgtype: PKGTYPE=$PKGTYPE" # Guts validate_word "$ERRSTACK_REF" "$PKGTYPE" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$PKGTYPE: invalid pkgtype" return $ADE_FAIL } return $ADE_OK } validate_release() { local ERRSTACK_REF="$1"; shift local RELEASE RELEASE="$1" ade_debug "$ERRSTACK_REF" 10 "validate_release: RELEASE=$RELEASE" # Guts while :; do # this is a setjmp()-type loop, giving us somewhere to 'break' ahead to. # Either (like RHEL major releases) it is an integer ... ! [[ $RELEASE =~ ^[1-9][0-9]*$ ]] || break # ... or (like RHEL minor releases) an FP number ... ! [[ $RELEASE =~ ^[1-9][0-9]*\.[0-9]+$ ]] || break # ... or (like Debian and Ubuntu) it is a word ... ! validate_word "$ERRSTACK_REF" "$RELEASE" || break ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" # or (like Debian security) it is of the format word-slash-word ! [[ $RELEASE =~ ^$WORD_REGEXP/$WORD_REGEXP$ ]] || break # or (like local-sl5.4 is 'sl5.4) is of format letter-anythingexceptspace ! [[ $RELEASE =~ ^[a-z0-9][^\ ]*$ ]] || break ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$RELEASE: invalid release" return $ADE_FAIL done return $ADE_OK } validate_port() { local ERRSTACK_REF="$1"; shift local PORT PORT="$1" ade_debug "$ERRSTACK_REF" 10 "validate_port: PORT=$PORT" # Guts validate_word "$ERRSTACK_REF" "$PORT" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$PORT: invalid port" return $ADE_FAIL } return $ADE_OK } validate_section() { local ERRSTACK_REF="$1"; shift local SECTION SECTION="$1" ade_debug "$ERRSTACK_REF" 10 "validate_section: SECTION=$SECTION" # Guts # a-b/c-d/d-e (sensible words, possibly slash-separated) [[ $SECTION =~ ^[a-zA-Z]([-a-zA-Z0-9_]*[a-zA-Z0-9])*(/[a-zA-Z]([-a-zA-Z0-9_]*[a-zA-Z0-9])*)*$ ]] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$SECTION: invalid section" return $ADE_FAIL } return $ADE_OK } validate_url() { local ERRSTACK_REF="$1"; shift local URL URL="$1" ade_debug "$ERRSTACK_REF" 10 "validate_url: URL=$URL" # Guts # Next line deliberately split to avoid confusing svn, which sees a replacable token in the line. [[ $URL =~ ^(http|file|ftp)://.*$ ]] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$URL: invalid \ URL"; $ADE_FAIL; } return $ADE_OK } validate_freeze_dir() { local ERRSTACK_REF="$1"; shift local FREEZE_DIR FREEZE_DIR="$1" ade_debug "$ERRSTACK_REF" 10 "validate_freeze_dir: FREEZE_DIR=$FREEZE_DIR" # Guts validate_dir "$ERRSTACK_REF" "$FREEZE_DIR" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$FREEZE_DIR: invalid freeze_dir" return $ADE_FAIL } return $ADE_OK } validate_indirect_dir() { local ERRSTACK_REF="$1"; shift local INDIRECT_DIR INDIRECT_DIR="$1" ade_debug "$ERRSTACK_REF" 10 "validate_indirect_dir: INDIRECT_DIR=$INDIRECT_DIR" # Guts validate_dir "$ERRSTACK_REF" "$INDIRECT_DIR" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$INDIRECT_DIR: invalid indirect_dir" return $ADE_FAIL } return $ADE_OK } validate_existing_dir() { local ERRSTACK_REF="$1"; shift local DIR DIR="$1" ade_debug "$ERRSTACK_REF" 10 "validate_existing_dir: DIR=$DIR" # Guts [ -d "$DIR" ] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$DIR: invalid directory"; return $ADE_FAIL; } return $ADE_OK } validate_dir() { local ERRSTACK_REF="$1"; shift local DIR DIR="$1" ade_debug "$ERRSTACK_REF" 10 "validate_dir: DIR=$DIR" # Guts : return $ADE_OK } validate_mirror_dir() { local ERRSTACK_REF="$1"; shift local MIRROR_DIR MIRROR_DIR="$1" ade_debug "$ERRSTACK_REF" 10 "validate_mirror_dir: MIRROR_DIR=$MIRROR_DIR" # Guts validate_dir "$ERRSTACK_REF" "$MIRROR_DIR" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$MIRROR_DIR: invalid mirror_dir" return $ADE_FAIL } return $ADE_OK } validate_layout() { local ERRSTACK_REF="$1"; shift local LAYOUT LAYOUT="$1" ade_debug "$ERRSTACK_REF" 10 "validate_layout: LAYOUT=$LAYOUT" # Guts # This allows normal path-like characters, but checks that if '<' is supplied # then it pairs with a '>'. [[ $LAYOUT =~ [-a-zA-Z0-9_/]*(<[-a-zA-Z0-9_/]*>)*[-a-zA-Z0-9_/]* ]] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$LAYOUT: invalid layout" return $ADE_FAIL } return $ADE_OK } validate_distro() { local ERRSTACK_REF="$1"; shift local DISTRO DISTRO="$1" ade_debug "$ERRSTACK_REF" 10 "validate_distro: DISTRO=$DISTRO" # Guts validate_word "$ERRSTACK_REF" "$DISTRO" || { # Replace delegation's error message. ade_set_messaging_parameters "$ERRSTACK_REF" "stack=$ERRSTACK_REF" ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$DISTRO: invalid DISTRO" return $ADE_FAIL } return $ADE_OK } validate_word() { local ERRSTACK_REF="$1"; shift local WORD WORD="$1" ade_debug "$ERRSTACK_REF" 10 "validate_word: WORD=$WORD" # Guts [[ $WORD =~ ^$WORD_REGEXP$ ]] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$WORD: invalid word"; return $ADE_FAIL; } return $ADE_OK } push() { local ERRSTACK_REF="$1"; shift local ARRAY_REF VALUE [ $# = 2 ] || ade_internal "$ERRSTACK_REF" "push: usage error (arg count $#)" ARRAY_REF=$1 VALUE=$2 ade_debug "$ERRSTACK_REF" 10 "push: ARRAY_REF=$ARRAY_REF, VALUE=$VALUE" eval "$ARRAY_REF[\${#$ARRAY_REF[*]}]=\"\$VALUE\"" return $ADE_OK } convert_abssymlink_to_relsymlink() { local ERRSTACK_REF="$1"; shift local VAR SRC DST LOCAL_TGT SRC_SET DST_SET TGT_SET I [ $# = 3 ] || ade_internal "$ERRSTACK_REF" "convert_abssymlink_to_relsymlink: usage error (arg count $#)" SRC="$1" DST="$2" TGT_REF="$3" ade_debug "$ERRSTACK_REF" 4 "convert_abssymlink_to_relsymlink: SRC=$SRC, DST=$DST" for VAR in SRC DST; do # Check absolute eval "[[ \"\$$VAR\" =~ ^/ ]] || error \"\$$VAR: not absolute\"" # Strip trailing slashes eval "[ \"\$$VAR\" = / ] || $VAR=\"\${$VAR%/}\"" # Prepend . eval "$VAR=.\$$VAR" # Convert to set eval "${VAR}_SET=( \${$VAR//\// } )" done # Strip common prefix but ensuring a minimum of one element left on each list while :; do for VAR in SRC DST; do eval "ade_debug \"\$ERRSTACK_REF\" 10 \"convert_abssymlink_to_relsymlink: ${VAR}_SET=( \${${VAR}_SET[*]} )\"" done for VAR in SRC DST; do eval "[ \${#${VAR}_SET[*]} != 1 ]" || { ade_debug "$ERRSTACK_REF" 10 "convert_abssymlink_to_relsymlink: ${VAR}_SET has one element; stopping stripping ..." break } done [ ${SRC_SET[0]} = ${DST_SET[0]} ] || { ade_debug "$ERRSTACK_REF" 10 "convert_abssymlink_to_relsymlink: first elements differ; stopping stripping ..." break } for VAR in SRC DST; do eval "${VAR}_SET=(\"\${${VAR}_SET[@]:1:100}\")" done done # If source set down to one element and that is the same as the first element # in the target set then this is not possible because the symlink needs to be # created in a position already occupied by a directory (/a --> /a/b/c) # or by the target of the link (/a/b --> /a/b). [ ${#SRC_SET[*]} != 1 ] || [ ${SRC_SET[0]} != ${DST_SET[0]} ] || { ade_error "$ERRSTACK_REF" PAA_ERR_MISC "$SRC -> $DST: not possible" return $ADE_FAIL } # Reassemble (one less ".." than the source set now contains, plus what the # destination set contains, all joined with "/"). TGT_SET=() for ((I=0; I<${#SRC_SET[*]}-1; I++)); do push "$ERRSTACK_REF" TGT_SET ".." || return $? done for ((I=0; I<${#DST_SET[*]}; I++)); do push "$ERRSTACK_REF" TGT_SET "${DST_SET[$I]}" || return $? done # This rather sneaky things comes from # http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array. # Unfortunately, it uses I_F_S (which both in this comment and in the code # has been written thus to avoid tripping an ADE standard test, which is there # to ensure I_F_S is not left in a bad state. I_F_S=/ read LOCAL_TGT <<< "${TGT_SET[*]}" # Alteratively: LOCAL_TGT="${TGT_SET[0]}" for ((I=1; I<${#TGT_SET[*]}; I++)); do LOCAL_TGT+="/${TGT_SET[$I]}" done ade_debug "$ERRSTACK_REF" 4 "convert_abssymlink_to_relsymlink: TGT=$LOCAL_TGT" eval "$TGT_REF=\"\$LOCAL_TGT\"" return $ADE_OK } get_db_schema_conformancy() { local ERRSTACK_REF="$1"; shift local DB_SCHEMA_CONFORMANCY_REF [ $# = 1 ] || ade_internal "$ERRSTACK_REF" "get_db_schema_conformancy: usage error (arg count $#)" DB_SCHEMA_CONFORMANCY_REF="$1" ade_write_sql "$ERRSTACK_REF" "pragma user_version;" $DB_SCHEMA_CONFORMANCY_REF || return $? return $ADE_OK } check_schema_conformancy() { local ERRSTACK_REF="$1"; shift local DB_SCHEMA_CONFORMANCY PROGNAME # Process arguments [ $# = 0 ] || ade_internal "$ERRSTACK_REF" "check_schema_conformancy: usage error (arg count $#)" # Sanity checks and derivations get_db_schema_conformancy "$ERRSTACK_REF" DB_SCHEMA_CONFORMANCY || return $? ade_get_progname "$ERRSTACK_REF" PROGNAME # Guts if [ $DB_SCHEMA_CONFORMANCY -lt $CODE_SCHEMA_CONFORMANCY ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "database schema is too old (do you need to run '$PROGNAME upgrade'?)" return $ADE_FAIL elif [ $DB_SCHEMA_CONFORMANCY -gt $CODE_SCHEMA_CONFORMANCY ]; then ade_error "$ERRSTACK_REF" PAA_ERR_MISC "database schema is too new (do you need to upgrade $PROGNAME?)" return $ADE_FAIL fi return $ADE_OK } sleep_if_sleep_defined() { local ERRSTACK_REF="$1"; shift ade_global SLEEP_PID [ $# = 0 ] || ade_internal "$ERRSTACK_REF" "sleep_if_sleep_defined: bad arg count ($#)" if [ "X$SLEEP" != X ]; then ade_debug "$ERRSTACK_REF" 10 "sleep_if_sleep_defined[$$]: sleeping $SLEEP seconds ..." kill_sleep() { kill $SLEEP_PID; wait $SLEEP_PID; ade_debug "$ERRSTACK_REF" 10 "kill_sleep[$$]: sleep was killed and has exited"; } ade_register_exit_function "$ERRSTACK_REF" kill_sleep || return $? sleep $SLEEP & SLEEP_PID=$! wait $SLEEP_PID || true # If, during that sleep, paa itself is sent a signal (aka killed) # then we'll never reach this point, which is why we needed to # register a handler to kill the sleep off. Alternatively, if # we do reach here then the handler is no longer needed. ade_deregister_exit_function "$ERRSTACK_REF" kill_sleep || return $? ade_debug "$ERRSTACK_REF" 10 "sleep_if_sleep_defined[$$]: sleep completed normally" fi return $ADE_OK } save_old_dir_contents() { local ERRSTACK_REF="$1"; shift local DIR CP_OR_MV PROGNAME # Process arguments [ $# = 2 ] || ade_internal "$ERRSTACK_REF" "save_old_dir_contents: bad arg count ($#)" CP_OR_MV=$1 DIR=$2 # Sanity checks and derivations [ $CP_OR_MV = cp -o $CP_OR_MV = mv ] || ade_internal "$ERRSTACK_REF" "save_old_dir_contents: $CP_OR_MV: invalid copy or move" ade_get_progname "$ERRSTACK_REF" PROGNAME # Guts ade_warning "$ERRSTACK_REF" PAA_ERR_MISC "saving old contents of $DIR to /tmp/$PROGNAME.$$.${DIR//\//-} (you should review them!) ..." mkdir /tmp/$PROGNAME.$$.${DIR//\//-} $CP_OR_MV $DIR/* /tmp/$PROGNAME.$$.${DIR//\//-} return $ADE_OK } ade_main paa "$@"