#!/bin/sh

# copyright, licensing and documentation at the end

set -e
set -u

usage() {
    perl -MPod::Usage=pod2usage -e"pod2usage(-input => '$0', -verbose=>99, -sections=>[qw(SYNOPSIS DESCRIPTION)])"
    exit 1
}

STATS=
VERBOSE=
HAVE_BC=
PARALLEL=

while getopts vshp opt; do
    case $opt in
        h) usage;;
        s) STATS=1
           if which bc > /dev/null 2>&1; then
               HAVE_BC=1
           else
               echo "W: 'bc' not available, stats will use byte units" >&2
           fi
        ;;
        p)
            if which parallel > /dev/null ; then
                if parallel --will-cite < /dev/null > /dev/null 2>&1; then
                    PARALLEL=GNU
                else
                    PARALLEL="moreutils"
                fi
            else
                echo "W: 'parallel' not available, will run sequentially" >&2
                echo "W: you may want to install 'parallel' or 'moreutils'" >&2
            fi
        ;;
        v) VERBOSE=1;;
        ?) usage;;
    esac
done

shift `expr $OPTIND - 1`

[ -z "${1:-}" ] || usage

cd "${DPT_PACKAGES:?}"

if [ -n "$HAVE_BC" ]; then
    calc() {
        ( echo "scale=1"; echo "$@" ) | LC_ALL=C bc
    }
else
    calc() {
        echo $(( "$@" ))
    }
fi

human() {
    local K_DIV=1024
    local M_DIV=$(( $K_DIV * $K_DIV ))
    local G_DIV=$(( $M_DIV * $K_DIV ))

    if [ -n "$HAVE_BC" ]; then
        if [ `calc  "$1 / $G_DIV >= 1.1"` = "1" ]; then
            echo `calc "$1 / $G_DIV"`G
        elif [ `calc "$1 / $M_DIV > 1.1"` = "1" ]; then
            echo `calc "$1 / $M_DIV"`M
        elif [ `calc "$1 / $K_DIV > 1.1"` = "1" ]; then
            echo `calc "$1 / $K_DIV"`K
        else
            echo $1
        fi
    else
        echo $1
    fi
}

if [ -n "$STATS" ]; then
    TOTAL_BEFORE=$(find . -maxdepth 2 -type d -name .git -print0 | du -sbP --total --files0-from=- | tail -1 | cut -f1)
fi

if [ -n "$PARALLEL" ]; then
    if [ "$PARALLEL" = "GNU" ]; then
        find . -maxdepth 2 -type d -name .git | \
            parallel --will-cite sh -c "GIT_DIR='{}' git gc --quiet"
    else
        find . -maxdepth 2 -type d -name .git -print0 | \
            xargs -r0 parallel -i sh -c "GIT_DIR='{}' git gc --quiet" --
    fi
else
    for d in `find . -maxdepth 1 -type d`; do
        [ -d "$d/.git" ] || continue

        if [ -n "$VERBOSE" ]; then
            echo -n "`basename $d`"
        fi
        if [ -n "$STATS" ]; then
            BEFORE=`du -sbP $d/.git | cut -f1`
        fi
        GIT_DIR="$d/.git" git gc --quiet
        if [ -n "$STATS" ]; then
            AFTER=`du -sbP $d/.git | cut -f1`
        fi
        if [ -n "$VERBOSE" ]; then
            echo -n " done."
            if [ -n "$STATS" ]; then
                printf " %s -> %s (-%s, %0.1f%%)"  \
                    `human $BEFORE` `human $AFTER` \
                    `human $(( $BEFORE - $AFTER ))` \
                    `calc "100*($BEFORE-$AFTER)/$BEFORE"`
            fi
            echo
        fi
    done
fi

if [ -n "$STATS" ]; then
    TOTAL_AFTER=$(find . -maxdepth 2 -type d -name .git -print0 | du -sbP --total --files0-from=- | tail -1 | cut -f1)
    GAIN=$(( $TOTAL_BEFORE - $TOTAL_AFTER ))
    printf "Total disk usage: %s -> %s (-%s, %0.1f%%)\n"  \
        `human $TOTAL_BEFORE` `human $TOTAL_AFTER` \
        `human $GAIN` \
        `calc "100*($GAIN)/$TOTAL_BEFORE"`
fi

exit 0

POD=<<'EOF'
=head1 NAME

dpt-gc - swipe pkg-perl working directories

=head1 SYNOPSIS

B<dpt gc> [I<option>...]

=head1 DESCRIPTION

B<dpt gc> runs L<git(1)> garbage collection in cloned pkg-perl's repositories. It is suitable to be run from L<cron(1)>, e.g. weekly.

=head1 CONFIGURATION

B<dpt gc> uses the C<DPT_PACKAGES> environment variable. If
C<DPT_PACKAGES> is not defined, the command fails.

See L<dpt-config(5)> for details.

=head1 OPTIONS

=over

=item B<-h>

Display usage information.

=item B<-p>

Run in parallel, utilizing all CPUs.

=item B<-s>

Display statistics about disk usage before and after garbage collection.

=item B<-v>

Verbose operation. Let L<git-gc(1)> emit progress messages. Doesn't display
per-repository stats when B<-p> is used.

=back

=head1 COPYRIGHT & LICENSE

Copyright 2013, 2017 Damyan Ivanov L<dmn@debian.org>
Copyright 2017 gregor herrmann L<gregoa@debian.org>

This program is free software, licensed under the same term as perl.

=cut
EOF
