diff --git a/README.markdown b/README.markdown index 188d59f..3137ef2 100644 --- a/README.markdown +++ b/README.markdown @@ -1,13 +1,14 @@ GitHub-Backup ============= -By Chris Lockfort (devnull@csh.rit.edu) (Github username: Clockfort) +Idea By Chris Lockfort (devnull@csh.rit.edu) (Github username: Clockfort) +Python version By Anthony Gargiulo (anthony@agargiulo.com) (Github username: agargiulo) GitHub-Backup makes a local backup copy of all of a github user's (or github organization's) repositories. Usage ----- -"./github-backup.pl USERNAME BACKUP_DIRECTORY" +"./github-backup.py USERNAME BACKUPDIR [-c|--cron] [-h|--help]" Then, put it in a cron job somewhere and forget about it for eternity. diff --git a/github-backup.pl b/github-backup.pl deleted file mode 100755 index a2b097b..0000000 --- a/github-backup.pl +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/perl -# Usage: -# ./github-backup.pl USERNAME BACKUP_DIRECTORY - -# Copyright (c) 2010 Chris Lockfort -# -# Permission to use, copy, modify, and distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -use strict; -use warnings; -use LWP::Simple; - -die "Please supply a github username and backups directory\n" unless (@ARGV == 2); - -my $username = $ARGV[0]; -my $backupdir = $ARGV[1]; -my $page = get("http://github.com/api/v2/yaml/repos/show/$username"); -die "Could not complete github API query for $username\n" unless defined $page; - -my @list = split(/\n/, $page); -my @urls = grep { /url/ } @list; -my @giturls = grep s/ :url: http/git/, @urls; -@urls = @giturls; -my @reponames = grep s/.*$username\///, @giturls; - -for(my $i = 0; $i < @urls; ++$i){ - my $url = $urls[$i]; - my $name = $reponames[$i]; - unless(-e $backupdir){ - system("mkdir $backupdir") and die "Couldn't make $backupdir.\n"; - } - unless(-e "$backupdir/$name"){ #We haven't backed this up before, let's clone it - print "CLONING REPOSITORY: $url\n"; - system("cd $backupdir && git clone $url") and die "Encountered an error while git-cloning repository $name\n"; - } - else{ #We've backed it up before, just fetch the most recent copy - print "REPOSITORY EXISTED, FETCHING: $name\n"; - system("cd $backupdir/$name && git fetch -q") and die "Encountered an error while git-fetching repository $name\n"; - } -} diff --git a/github-backup.py b/github-backup.py new file mode 100755 index 0000000..53a9c87 --- /dev/null +++ b/github-backup.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# Author: Anthony Gargiulo (anthony@agargiulo.com) +# Created Fri Jun 15 2012 + +from pygithub3 import Github +from argparse import ArgumentParser +import os + +def main(): + # A sane way to handle command line args. + # Now actually store the args + parser = init_parser() + args = parser.parse_args() + + # Make the connection to Github here. + gh = Github() + + # Get all of the given user's repos + user_repos = gh.repos.list(args.username).all() + for repo in user_repos: + process_repo(repo, args) + +def init_parser(): + """ + set up the argument parser + """ + parser = ArgumentParser( + description="makes a backup of all of a github user's repositories") + parser.add_argument("username", help="A Github username") + parser.add_argument("backupdir", + help="The folder where you want your backups to go") + parser.add_argument("-c","--cron", help="Use this when running from a cron job", + action="store_true") + return parser + + +def process_repo(repo, args): + if args.cron: + git_args = "-q" + else: + git_args = "" + + if not args.cron: + print("Processing repo: {}".format(repo.full_name)) + + if os.access('{}/{}/.git'.format(args.backupdir,repo.name),os.F_OK): + if not args.cron: + print("Repo already exists, let's try to update it instead") + os.system('cd {}/{};git pull {}'.format(args.backupdir, repo.name, git_args)) + else: # Repo doesn't exist, let's clone it + os.system('git clone {} {} {}/{}'.format(git_args, repo.git_url, args.backupdir, repo.name)) + +if __name__ == "__main__": + main()