# Here is defined the program's recursive fetcher:
#
#     recursively_fetch [PATH0...]
#
# The recursive fetcher's recursion follows symlinks only. The fetcher
# creates directories as needed to receive fecthed objects but does not
# descend into any directories (such descent being a different kind
# of recursion).
#
# The recursive fetcher is meant to be called from phase C or D, where
# the variables
#
#     DIST1 MIRROR SNAPSHOT_SSDATE
#
# will already have been set (the last of these having been set during
# phase B). Admittedly, the practice is less than ideal from a data-flow
# perspective, but being documented here it works well enough for now.
#
# See 10function-definitions.bash for general notes that are relevant here.

# This variable, whose use is local to the script, should probably have
# been made an array -- as probably also should some other variables like
# it. However, because it stores PATH0 pathnames rather than full
# pathnames, and because the Debian archive brings no files whose names
# contain embedded spaces, it works as is for now. It's a single string
# in which spaces separate the pathnames.
declare F15_RF_FILES_TO_RSYNC=''

# (Here is a utility function for the use of the recursive fetcher. For the
# fetcher itself, see below.)
#
# usage: inform_of_intent_to_recursively_fetch PROTOCOL
readonly F15_IIRF_MSG=$(gettext 'preparing to fetch the following via %s')
function inform_of_intent_to_recursively_fetch {
    inform "$(printf "$F15_IIRF_MSG:" "$1")"
    print_bar
    local A
    for A in "$F15_RF_FILES_TO_RSYNC"; do printf '%s\n' "$A"; done
    print_bar
    return 0
}
readonly -f inform_of_intent_to_recursively_fetch

# In the recursive fetcher, these names have the following meanings:
#
#      RFP  Recursive Filepath
#      RFPS Recursive Filepaths
#      RRFP Relative Recursive Filepath
#      ZFP  Decompressible Filepath
#      ZFPS Decompressible Filepaths
#      FP   in general, Filepath
#
# Thus, for instance, "ROOTFPS" stands for "Root Filepaths."
#
# The function is recursive insofar as it
#
#   * fetches files and symlinks (making directories for them
#     as necessary),
#   * lists the files and symlinks at which the just-fetched symlinks
#     point, and then
#   * calls itself to fetch the files and symlinks the last list lists.
#
# The recursion's purpose is to follow symlinks. The recursion bottoms out
# after a cycle during which no symlinks but only files are fetched.
#
# example: recursively_fetch\
#  dists/$DIST_BACKPORTS/Release.gpg\
#  dists/$DIST/main/i18n/Translation-fr.bz2
#
readonly F15_RF_ERRMSG="$(printf "$(gettext\
 'impossible: %s called while %s is set')" 'recursively_fetch' '-s')"
function recursively_fetch {
    (($OPT_SUMS)) && die "$F15_RF_ERRMSG"
    (($#)) || return 0
    pushd >/dev/null "$TARGET"
    # From this point, no 'return' is allowed until the 'popd' at the
    # the bottom has executed.
    local RF_ZZZDIR; readonly RF_ZZZDIR="zzz-dists/$DIST1"
    local RF_CHECKSUM RF_SHORTDIR RF_HASHDIR RF_FILEPATH RF_RRFP RF_RFPS
    local RF_IS_FIRST; declare -i RF_IS_FIRST
    F15_RF_FILES_TO_RSYNC="$(
        RF_IS_FIRST=1
        for RF_FILEPATH; do
            if (($IS_BACKPORTS)); then printf '%s '\
             "https://$MIRROR/$ARCHIVE_NAME/$SNAPSHOT_SSDATE/$RF_FILEPATH"
            else
                if (($RF_IS_FIRST)); then
                    printf '%s' "$MIRROR" && RF_IS_FIRST=0
                fi
                printf '%s ' "::$ARCHIVE_NAME/$RF_FILEPATH"
            fi
        done
    )"
    if [ -n "$F15_RF_FILES_TO_RSYNC" ]; then # test is probably superfluous
        if (($IS_BACKPORTS)); then
            inform_of_intent_to_recursively_fetch 'wget'
            # Transferring via https, wget apparently, unfortunately is
            # unable to preserve symlinks. Therefore, though the data is
            # transferred and safely stored, the recursion fails.
            #  -nc       do not clobber existing files
            #  -x        download not into current dir but into hierarchy
            #  -nH       do not generate hostname dirs
            #  -N [*]    update existing files if timestamps have changed
            # --cut-dirs cut leading dirs
            #  -P        root the target hierarchy
            # [*] The -N option is presently unused.
            # The --cut-dirs=5 strips five levels from the likes of
            # archive/debian/19700101T000000Z/dists/$DISTS_BACKPORTS/main/...
            # leaving just main/... -- or, in other words, leaving a PATH2.
            wget_insist\
             '-nc -x -nH --cut-dirs=5 -P '"dists/$DIST_BACKPORTS"\
             $F15_RF_FILES_TO_RSYNC
            #
            # The remainder of the action below fixes backports, recovering
            # the failed recursion. Because wget, upon which the retrieval
            # of backports relies, apparently cannot retrieve symlinks as
            # symlinks via http (presumably because http does not support
            # such retrieval), backports is made below to imitate the
            # symlink structure of stable.
            #
            # Following pattern, one might have expected
            # zzz-dists/stable-backports next but the archive does not
            # do that.
            mkdir -p$V -- "$RF_ZZZDIR"
            for FP1 in $(
                "$FINDX" '' '-maxdepth 1 -type f -printf '"'"'%P\n'"'"\
                "dists/$DIST1"
            ); do
                # Note the $DIST, rather than $DIST1, on the next line.
                if [ -h "dists/$DIST/$FP1" ]; then
                    mv $VV -- "dists/$DIST1/$FP1" "$RF_ZZZDIR/$FP1"
                    ln_touch "../../$RF_ZZZDIR/$FP1" "dists/$DIST1/$FP1"
                fi
            done
            for FP1 in $(
                "$FINDX" '' '-mindepth 2 -type f -printf '"'"'%P\n'"'"\
                "dists/$DIST1"
            ); do
                # Note the $DIST, rather than $DIST1, on the next line.
                if {
                    [ -h "dists/$DIST/$FP1" ] ||\
                    does_need_extra_zzz extra-zzz.list "$FP1"
                }; then
                    RF_CHECKSUM="$(
                        sha256sum -- "dists/$DIST1/$FP1"\
                        | sed -r -- 's/\s.*//'
                    )"
                    RF_SHORTDIR='by-hash/SHA256'
                    RF_HASHDIR="$(dirname --\
                     "dists/$DIST1/$FP1")/$RF_SHORTDIR"
                    mkdir -p$V -- "$RF_HASHDIR"
                    mv $VV -- "dists/$DIST1/$FP1"\
                     "$RF_HASHDIR/$RF_CHECKSUM"
                    ln_touch "$RF_SHORTDIR/$RF_CHECKSUM"\
                     "dists/$DIST1/$FP1"
                fi
            done
        else
            inform_of_intent_to_recursively_fetch 'rsync'
            # Unlike wget, rsync can preserve symlinks. (The below option
            # descriptions are verbatim from man 1 rsync.)
            #  -l        copy symlinks as symlinks
            #  -t        preserve modification times
            #  -p        preserve permissions
            #  -R        use relative path names
            #  -v        be verbose
            # --progress show progress during transfer
            # --stats    give some file-transfer stats
            until
                rsync -lKtRv --progress --stats --\
                $F15_RF_FILES_TO_RSYNC ./
            do pause_before_retrying; done
            RF_RFPS=''
            for RF_FILEPATH; do
                if [ -h "$RF_FILEPATH" ]; then
                    RF_RRFP="$(readlink -- "$RF_FILEPATH")"
                    if [[ "$RF_RRFP" = /* ]]; then
                        RF_RFPS+=" ${RF_RRFP#/}"
                    else
                        RF_RFPS+=" $(dirname -- "$RF_FILEPATH")/$RF_RRFP"
                    fi
                fi
            done
            [ -n "$RF_RFPS" ] && recursively_fetch $RF_RFPS
        fi
        print_bar
    fi
    popd >/dev/null
    return 0
}
readonly -f recursively_fetch
true

