1
0
Fork 0
mirror of https://github.com/clockfort/GitHub-Backup.git synced 2025-03-30 00:00:16 +01:00

use PyGitHub instead of pygithub3

This commit is contained in:
Steffen Vogel 2019-05-05 03:22:37 +02:00
parent 577298c25b
commit edf8db636b
2 changed files with 69 additions and 56 deletions

View file

@ -8,104 +8,117 @@ Created: Fri Jun 15 2012
""" """
from pygithub3 import Github from github import Github
from argparse import ArgumentParser from argparse import ArgumentParser
import subprocess import subprocess
import os import os, os.path
import logging
LOGGER = logging.getLogger('github-backup')
def main(): def main():
logging.basicConfig(level=logging.INFO)
parser = init_parser() parser = init_parser()
args = parser.parse_args() args = parser.parse_args()
if not args.git: if args.quiet:
args.git = [] LOGGER.setLevel(logging.WARN)
elif args.debug:
LOGGER.setLevel(logging.DEBUG)
# Process args # Process args
if args.cron: if args.quiet:
args.git.append("--quiet") args.git.append("--quiet")
# Make the connection to Github here.
config = {'user': args.username}
args.backupdir = args.backupdir.rstrip("/") args.backupdir = args.backupdir.rstrip("/")
if (args.token): # Make the connection to Github here.
config['token'] = args.token config = {'login_or_token': args.login_or_token}
if (args.password): if args.password:
config['password'] = args.password config['password'] = args.password
config['login'] = args.username
# if both password and token are specified, the token will be
# used, according to pygithub3 sources
# however, the username isn't required when using a token
if (args.token):
config['token'] = args.token
gh = Github(**config) gh = Github(**config)
# Get all repos # Check that backup dir exists
users = {} if not os.path.exists(args.backupdir):
user_repos = gh.repos.list(user=args.username).all() os.mkdir(args.backupdir)
for repo in user_repos:
if repo.owner.login not in users: # Get all repos
users[repo.owner.login] = gh.users.get(repo.owner.login) 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
repo.user = users[repo.owner.login]
fullrepo = gh.repos.get(repo.owner.login, repo.name)
is_fork = hasattr(fullrepo, 'parent') and hasattr(fullrepo, 'source')
if not (args.skip_forks and is_fork):
process_repo(repo, args) process_repo(repo, args)
import sys
sys.exit(0)
def init_parser(): def init_parser():
""" """Set up the argument parser."""
set up the argument parser
"""
parser = ArgumentParser(description="makes a backup of all of a github user's repositories") 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("login_or_token", help="A Github username or token")
parser.add_argument("backupdir", help="The folder where you want your backups to go") 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") 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")
parser.add_argument("-m", "--mirror", help="Create a bare mirror", action="store_true") 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") parser.add_argument("-f", "--skip-forks", help="Skip forks", action="store_true")
parser.add_argument("-g", "--git", nargs="+", help="Pass extra arguments to git", default="", metavar="ARGS") parser.add_argument("-g", "--git", nargs="+", help="Pass extra arguments to git", type=list, default=[], metavar="ARGS")
parser.add_argument("-S", "--ssh", help="Use SSH protocol", action="store_true") parser.add_argument("-t", "--type", help="Select the protocol for cloning", choices=['git', 'http', 'ssh'], default='ssh')
parser.add_argument("-s", "--suffix", help="Add suffix to repository directory names", default="") 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", "--password", help="Authenticate with Github API")
parser.add_argument("-P", "--prefix", help="Add prefix to repository directory names", default="") parser.add_argument("-P", "--prefix", help="Add prefix to repository directory names", default="")
parser.add_argument("-t", "--token", help="Authenticate with Github API using OAuth token", default="")
parser.add_argument("-o", "--organization", help="Backup Organizational repositories", metavar="ORG") parser.add_argument("-o", "--organization", help="Backup Organizational repositories", metavar="ORG")
return parser return parser
def process_repo(repo, args): def process_repo(repo, args):
if not args.cron: LOGGER.info("Processing repo: %s", repo.full_name)
print("Processing repo: %s" % (repo.full_name))
dir = "%s/%s" % (args.backupdir, repo.name + args.suffix) dir = args.backupdir + '/' + args.prefix + repo.name + args.suffix
config = "%s/%s" % (dir, "config" if args.mirror else ".git/config") config = "%s/%s" % (dir, "config" if args.mirror else ".git/config")
if not os.access(config, os.F_OK): if not os.access(config, os.F_OK):
if not args.cron: LOGGER.info("Repo doesn't exists, lets clone it")
print("Repo doesn't exists, lets clone it")
clone_repo(repo, dir, args) clone_repo(repo, dir, args)
else: else:
if not args.cron: LOGGER.info("Repo already exists, let's try to update it instead")
print("Repo already exists, let's try to update it instead")
update_repo(repo, dir, args) update_repo(repo, dir, args)
def clone_repo(repo, dir, args): def clone_repo(repo, dir, args):
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)]
if args.mirror: if args.mirror:
git("clone", ["--mirror", repo.git_url, dir], args.git, dir) git_args.insert(0, '--mirror')
else:
git("clone", [repo.git_url, dir], args.git, dir) git("clone", git_args, args.git, args.backupdir)
def update_repo(repo, dir, args): def update_repo(repo, dir, args):
@ -122,9 +135,9 @@ def update_repo(repo, dir, args):
git("config", ["--local", "gitweb.description", git("config", ["--local", "gitweb.description",
repo.description.encode("utf-8")], gdir=dir) repo.description.encode("utf-8")], gdir=dir)
if repo.user.name and repo.user.email: if repo.owner.name and repo.owner.email:
owner = "%s <%s>" % (repo.user.name.encode("utf-8"), owner = "%s <%s>" % (repo.owner.name.encode("utf-8"),
repo.user.email.encode("utf-8")) repo.owner.email.encode("utf-8"))
git("config", ["--local", "gitweb.owner", owner], gdir=dir) git("config", ["--local", "gitweb.owner", owner], gdir=dir)
git("config", ["--local", "cgit.name", str(repo.name)], gdir=dir) git("config", ["--local", "cgit.name", str(repo.name)], gdir=dir)
@ -135,12 +148,12 @@ def update_repo(repo, dir, args):
def git(gcmd, args=[], gargs=[], gdir=""): def git(gcmd, args=[], gargs=[], gdir=""):
cmd = ["git"] cmd = ["git"]
if gdir: if gdir:
cmd.append("--git-dir") cmd.extend(["-C", gdir])
cmd.append(gdir)
cmd.append(gcmd) cmd.append(gcmd)
cmd.extend(gargs) cmd.extend(gargs)
cmd.extend(args) cmd.extend(args)
print(cmd)
subprocess.call(cmd) subprocess.call(cmd)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -1 +1 @@
pygithub3 PyGitHub