Skip to content

Instantly share code, notes, and snippets.

@davidalger
Created November 9, 2018 15:51
Show Gist options
  • Save davidalger/3f1cebdd1d2d5a5ff9f2af7590da41be to your computer and use it in GitHub Desktop.
Save davidalger/3f1cebdd1d2d5a5ff9f2af7590da41be to your computer and use it in GitHub Desktop.
Pulls backups from all repositories in BitBucket only if changed since last run
#!/bin/bash
#
# backup.sh
#
# Created by David Alger on 2015-03-13
# Copyright 2015 David Alger. All rights reserved.
#
##################################################
## Initialize our environment
set -o pipefail;
set -o nounset;
set -o errexit;
# source credential file if present
if [[ -f ~/.bitbucket_backup ]]; then
source ~/.bitbucket_backup
fi
BASE_DIR="$(dirname $0)";
LOG_FILE=""; # this is to prevent an unset error... uncomment the following line to send output to a log file.
# LOG_FILE="$BASE_DIR/activity.log";
PHP_BIN=/usr/bin/php
API_ENDPOINT="https://bitbucket.org/api/1.0"
BAK_DEST=/server/backups/vcsdata/bitbucket-archive
##################################################
## Initialize our functions...
function log () {
if [[ "$1" = "CLEAR" ]]; then
if [[ ! "$LOG_FILE" = "" ]]; then
echo > "$LOG_FILE";
fi
return;
fi
if [[ "$(echo "$1" | tr -d [:blank:])" = "" && "$1" != "" ]]; then
return;
fi
if [[ "$LOG_FILE" = "" ]]; then
echo -e "$1";
else
echo -e "$1" >> "$LOG_FILE";
fi
return;
}
function assert_failure () {
echo "command failed with status of: $?";
exit $?;
}
function pre_run {
# log start time and header
log "############################################################
## START (backup.sh): $(date)
##
";
# creating directories
log "## creating $BAK_DEST directory";
log "$(mkdir -p "$BAK_DEST")"
}
function post_run {
#log finish time and footer
log "
##
## FINISH (backup.sh): `date`
############################################################
";
}
function hunt_repositories {
log "## hunting for repositories...";
REPO_LIST="$(curl -s --user "$BB_USER:$BB_PASS" "$API_ENDPOINT/user/repositories/")"
REPO_LIST="$(echo "$REPO_LIST" | $PHP_BIN -r '
$data = json_decode(file_get_contents("php://stdin"), true);
foreach ($data as $repo) {
echo "{$repo["owner"]}/{$repo["slug"]}/".str_replace(["+00:00", " ", ":"], ["", "_", ""], $repo["utc_last_updated"])."\n";
}
')"
log " found $(echo "$REPO_LIST" | wc -l | tr -d [:blank:]) repositories"
log ""
}
function loop_repositories {
log "## iterating repositories for backup"
log ""
for REPO_INFO in $REPO_LIST; do
REPO_ACCT=$(echo "$REPO_INFO" | cut -d / -f1)
REPO_NAME=$(echo "$REPO_INFO" | cut -d / -f2)
REPO_MODT=$(echo "$REPO_INFO" | cut -d / -f3)
REPO_DEST="$REPO_ACCT/$REPO_NAME.git"
REPO_TAR="$REPO_ACCT/${REPO_MODT}_${REPO_ACCT}_${REPO_NAME}.git.tar"
if [[ -f "$BAK_DEST/$REPO_TAR" ]]; then
log " # skipping $REPO_ACCT/$REPO_NAME\n"
log " utc_last_mod: $REPO_MODT"
log " backup_date: $(ls -l "$BAK_DEST/$REPO_TAR" | cut -d' ' -f9-11)"
log ""
else
backup_repository
# TODO: cleanup archives with previous modification date in filename
fi
done
}
function backup_repository {
log " # processing $REPO_ACCT/$REPO_NAME\n"
log " utc_last_mod: $REPO_MODT"
log " bare cloning to $REPO_DEST"
log " $(git clone --quiet --bare "[email protected]:$REPO_ACCT/$REPO_NAME.git" "$BAK_DEST/$REPO_DEST" 2>&1)"
log " creating tar archive at $REPO_TAR"
log " $(tar -cf "$BAK_DEST/$REPO_TAR" -C "$BAK_DEST" "$REPO_DEST")"
log " - archive size: $(ls -lh "$BAK_DEST/$REPO_TAR" | awk '{print $5}')"
log " cleaning up bare clone"
log " $(rm -rf "$BAK_DEST/$REPO_DEST")"
log ""
}
##################################################
## Begin the backup sequence...
function main {
pre_run
hunt_repositories
loop_repositories
post_run
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment