aboutsummaryrefslogtreecommitdiff
path: root/src/gitsnapshot/gitbackup.sh
blob: 47dee97abcfad82a0518fb51e0b5fa29abb6cbd5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env bash
AWS=/usr/local/bin/aws
basedir=$1
bucket=$2
repos_found=$basedir/*.git
num_repos_found=0
completed=0
backup_log="${basedir}/gitbackup-log"
mkdir -p "${backup_log}"
echo "starting for: $basedir"

get_rev_list () {
    : '
    generates a rev list since the last checkpoint. provides a blank
    response if the checkpoint and the latest commit are one and the same
    output:
    "hash..hash2"
    return
    0: successfully created a revlist
    1: no revlist created
    '
    # last checkpoint in repo
    local last_hash=$(git rev-list -n 1 --all)
    # first commit in repo, or hash of last checkpoint
    if ! $(git rev-list -n 1 CHECKPOINT &> /dev/null);
    then
        # first commit in repo
        local checkpoint_hash=$(git rev-list --all | tail -n 1)
        echo "${checkpoint_hash}"
        return 0
    else
        local checkpoint_hash=$(git rev-list -n 1 CHECKPOINT)
    fi

    # if checkpoint and last hash are one and the same, offer nothing
    if [ "${checkpoint_hash}" = "${last_hash}" ];
    then
        # we provide nothing back
        echo ""
        return 1
    else
        echo "${checkpoint_hash}..${last_hash}"
        return 0
    fi
}

create_bundle () {
    : '
    Arguments:
    arg1: rev_list in proper revlist format hash..hash2
    arg2: bundle name/path to create
    creates a bundle for a given revlist
    output:
    none
    returns:
    0: created bundle
    1: could not create bundle
    '
    local rev_list=$1
    local bundle_path_name=$2
    if ! git bundle create "${bundle_path_name}" "${rev_list}" --all;
    then
        return 1
    else
        return 0
    fi
}
for repo in $repos_found;
do
    let num_repos_found++ || true
    cd "${repo}"
    repobase=$(basename $repo)
    current_time=$(date +%s%N)
    slug=${repobase%%.*}
    tx_log="${backup_log}/${slug}.tx.log"
    last_time=$(touch ${tx_log} && tail -n1 "${tx_log}" | cut -d " " -f 1)
    last_time="${last_time:-0}"
    bundle_name="${last_time}-${current_time}-${slug}.bundle"
    bundle_tmp_path="/tmp/${bundle_name}"
    s3_base="s3://${bucket}"
    s3_uri="${s3_base}/${repobase}"

    rev_list=$(get_rev_list)

    if [ -z "${rev_list}" ];
    then
        # we increase the counter, because not needing to update is ok
        echo "${slug} has no new commits, no bundle generated"
        let completed++ || true
        continue
    else
        if ! $(create_bundle "${rev_list}" "${bundle_tmp_path}");
        then
            echo "${bundle_name} failed to be created" >&2
            continue
        fi
    fi
    if ! $AWS s3 cp "${bundle_tmp_path}" "${s3_uri}/${bundle_name}"
    then
        echo "$bundle_name failed to upload S3" >&2
        continue
    else
        # set checkpoint to the last hash in revlist
        checkpoint="${rev_list:42}"
        checkpoint=${checkpoint:-"${rev_list}"}
        git tag -f CHECKPOINT "${checkpoint}"
        # transaction log
        echo "${current_time} ${rev_list}" >> "${tx_log}"
        $AWS s3 cp "${tx_log}" "${s3_base}/logs/${slug}.tx.log"
    fi
    echo "${slug} backedup"
    let completed++ || true
done
echo "${completed} of ${num_repos_found} repos backed up"