2012-06-23 14:59:50 -04:00
#!/usr/bin/env python
2012-06-16 02:24:45 -04:00
2013-08-02 01:21:55 +02:00
"""
Authors : Anthony Gargiulo ( anthony @agargiulo.com )
Steffen Vogel ( post @steffenvogel.de )
Created : Fri Jun 15 2012
"""
2012-06-16 02:24:45 -04:00
2019-05-05 01:56:22 +02:00
2019-05-05 03:22:37 +02:00
from github import Github
2012-06-16 02:24:45 -04:00
from argparse import ArgumentParser
2013-11-14 18:56:12 +01:00
import subprocess
2019-05-05 03:22:37 +02:00
import os , os . path
import logging
2012-06-16 02:24:45 -04:00
2019-05-05 03:22:37 +02:00
LOGGER = logging . getLogger ( ' github-backup ' )
2019-05-05 01:56:22 +02:00
2012-06-18 18:18:54 -04:00
def main ( ) :
2019-05-05 03:22:37 +02:00
logging . basicConfig ( level = logging . INFO )
2019-05-05 01:48:21 +02:00
parser = init_parser ( )
args = parser . parse_args ( )
2012-06-16 02:24:45 -04:00
2019-05-05 03:22:37 +02:00
if args . quiet :
LOGGER . setLevel ( logging . WARN )
elif args . debug :
LOGGER . setLevel ( logging . DEBUG )
2013-11-14 18:56:12 +01:00
2019-05-05 01:48:21 +02:00
# Process args
2019-05-05 03:22:37 +02:00
if args . quiet :
2019-05-05 01:48:21 +02:00
args . git . append ( " --quiet " )
2013-08-02 01:21:55 +02:00
2019-05-05 01:48:21 +02:00
args . backupdir = args . backupdir . rstrip ( " / " )
2013-10-25 10:58:22 +02:00
2019-05-05 03:22:37 +02:00
# Make the connection to Github here.
config = { ' login_or_token ' : args . login_or_token }
2013-10-25 10:58:22 +02:00
2019-05-05 03:22:37 +02:00
if args . password :
2019-05-05 01:48:21 +02:00
config [ ' password ' ] = args . password
2013-10-15 01:07:34 +11:00
2019-05-05 01:48:21 +02:00
gh = Github ( * * config )
2012-06-18 01:15:54 -04:00
2019-05-05 03:22:37 +02:00
# Check that backup dir exists
if not os . path . exists ( args . backupdir ) :
os . mkdir ( args . backupdir )
2019-05-05 01:48:21 +02:00
# Get all repos
2019-05-05 03:22:37 +02:00
filters = {
' affiliation ' : ' , ' . join ( args . affiliation ) ,
' visibility ' : args . visibility
}
if args . organization :
org = gh . get_org ( args . org )
repos = org . get_repos ( * * filters )
else :
user = gh . get_user ( )
repos = user . get_repos ( * * filters )
for repo in repos :
if args . skip_forks and repo . fork :
continue
2019-02-02 21:27:20 +01:00
2019-05-05 03:22:37 +02:00
process_repo ( repo , args )
2012-06-23 15:48:44 -04:00
def init_parser ( ) :
2019-05-05 03:22:37 +02:00
""" Set up the argument parser. """
2019-05-05 01:48:21 +02:00
parser = ArgumentParser ( description = " makes a backup of all of a github user ' s repositories " )
2019-05-05 03:22:37 +02:00
parser . add_argument ( " login_or_token " , help = " A Github username or token " )
2019-05-05 01:48:21 +02:00
parser . add_argument ( " backupdir " , help = " The folder where you want your backups to go " )
2019-05-05 03:22:37 +02:00
parser . add_argument ( " -v " , " --visibility " , help = " Filter repos by their visibility " , choices = [ ' all ' , ' public ' , ' private ' ] , default = ' all ' )
parser . add_argument ( " -a " , " --affiliation " , help = " Filter repos by their affiliation " , action = ' append ' , type = str , default = [ ' owner ' ] , choices = [ ' owner ' , ' collaborator ' , ' organization_member ' ] )
parser . add_argument ( " -d " , " --debug " , help = " Show debug info " , action = " store_true " )
parser . add_argument ( " -q " , " --quiet " , help = " Only show errors " , action = " store_true " )
2019-05-05 01:48:21 +02:00
parser . add_argument ( " -m " , " --mirror " , help = " Create a bare mirror " , action = " store_true " )
parser . add_argument ( " -f " , " --skip-forks " , help = " Skip forks " , action = " store_true " )
2019-05-05 03:22:37 +02:00
parser . add_argument ( " -g " , " --git " , nargs = " + " , help = " Pass extra arguments to git " , type = list , default = [ ] , metavar = " ARGS " )
parser . add_argument ( " -t " , " --type " , help = " Select the protocol for cloning " , choices = [ ' git ' , ' http ' , ' ssh ' ] , default = ' ssh ' )
2019-05-05 01:48:21 +02:00
parser . add_argument ( " -s " , " --suffix " , help = " Add suffix to repository directory names " , default = " " )
parser . add_argument ( " -p " , " --password " , help = " Authenticate with Github API " )
parser . add_argument ( " -P " , " --prefix " , help = " Add prefix to repository directory names " , default = " " )
parser . add_argument ( " -o " , " --organization " , help = " Backup Organizational repositories " , metavar = " ORG " )
return parser
2012-06-23 15:48:44 -04:00
2019-05-05 01:56:22 +02:00
2012-06-23 15:49:34 -04:00
def process_repo ( repo , args ) :
2019-05-05 03:22:37 +02:00
LOGGER . info ( " Processing repo: %s " , repo . full_name )
2012-06-23 15:49:34 -04:00
2019-05-05 03:22:37 +02:00
dir = args . backupdir + ' / ' + args . prefix + repo . name + args . suffix
2019-05-05 01:48:21 +02:00
config = " %s / %s " % ( dir , " config " if args . mirror else " .git/config " )
2013-08-02 00:43:49 +02:00
2019-05-05 01:48:21 +02:00
if not os . access ( config , os . F_OK ) :
2019-05-05 03:22:37 +02:00
LOGGER . info ( " Repo doesn ' t exists, lets clone it " )
2019-05-05 01:48:21 +02:00
clone_repo ( repo , dir , args )
else :
2019-05-05 03:22:37 +02:00
LOGGER . info ( " Repo already exists, let ' s try to update it instead " )
update_repo ( repo , dir , args )
2013-08-02 00:50:54 +02:00
2013-11-14 18:56:12 +01:00
2019-02-02 21:27:20 +01:00
def clone_repo ( repo , dir , args ) :
2019-05-05 03:22:37 +02:00
if args . type == ' http ' :
url = repo . clone_url
elif args . type == ' ssh ' :
url = repo . ssh_url
elif args . type == ' git ' :
url = repo . git_url
git_args = [ url , os . path . basename ( dir ) ]
2019-05-05 01:48:21 +02:00
if args . mirror :
2019-05-05 03:22:37 +02:00
git_args . insert ( 0 , ' --mirror ' )
git ( " clone " , git_args , args . git , args . backupdir )
2014-06-26 00:14:25 +02:00
2013-08-02 01:21:55 +02:00
def update_repo ( repo , dir , args ) :
2019-05-05 01:48:21 +02:00
# GitHub => Local
2019-05-05 01:56:22 +02:00
# TODO: use subprocess package and fork git into
# background (major performance boost expected)
2019-05-05 01:48:21 +02:00
if args . mirror :
git ( " fetch " , [ " --prune " ] , args . git , dir )
else :
git ( " pull " , gargs = args . git , gdir = dir )
# Fetch description and owner (useful for gitweb, cgit etc.)
if repo . description :
2019-05-05 01:56:22 +02:00
git ( " config " , [ " --local " , " gitweb.description " ,
repo . description . encode ( " utf-8 " ) ] , gdir = dir )
2019-05-05 03:22:37 +02:00
if repo . owner . name and repo . owner . email :
owner = " %s < %s > " % ( repo . owner . name . encode ( " utf-8 " ) ,
repo . owner . email . encode ( " utf-8 " ) )
2019-05-05 01:56:22 +02:00
git ( " config " , [ " --local " , " gitweb.owner " , owner ] , gdir = dir )
2019-05-05 01:48:21 +02:00
git ( " config " , [ " --local " , " cgit.name " , str ( repo . name ) ] , gdir = dir )
git ( " config " , [ " --local " , " cgit.defbranch " , str ( repo . default_branch ) ] , gdir = dir )
git ( " config " , [ " --local " , " cgit.clone-url " , str ( repo . clone_url ) ] , gdir = dir )
2013-11-14 18:56:12 +01:00
2019-05-05 01:56:22 +02:00
2013-11-14 18:56:12 +01:00
def git ( gcmd , args = [ ] , gargs = [ ] , gdir = " " ) :
2019-05-05 01:48:21 +02:00
cmd = [ " git " ]
if gdir :
2019-05-05 03:22:37 +02:00
cmd . extend ( [ " -C " , gdir ] )
2019-05-05 01:48:21 +02:00
cmd . append ( gcmd )
cmd . extend ( gargs )
cmd . extend ( args )
2013-11-14 18:56:12 +01:00
2019-05-05 03:22:37 +02:00
print ( cmd )
2019-05-05 01:48:21 +02:00
subprocess . call ( cmd )
2013-08-27 15:17:50 +02:00
2012-06-18 18:18:54 -04:00
if __name__ == " __main__ " :
2019-05-05 01:48:21 +02:00
main ( )