Last active
December 22, 2015 04:49
-
-
Save yunazuno/6419552 to your computer and use it in GitHub Desktop.
Backup own bitbucket repositories to the specific directory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Backup own bitbucket repositories to the specific directory | |
Usage: backup-bitbucket-repository.py USERNAME BACKUP_TARGET_DIR | |
""" | |
import urllib.request | |
import keyring | |
import json | |
import os | |
import subprocess | |
AUTH_USERNAME = "" | |
BACKUP_BASE = "" | |
API_BASE_URI = "https://api.bitbucket.org" | |
AUTH_REALM = "Bitbucket.org API" | |
def build_opener(realm: str, uri: str, user: str, passwd: str) -> urllib.request.OpenerDirector: | |
""" | |
Build a opener for BASIC auth on urllib.request | |
:param realm: Realm on BASIC auth | |
:param uri: URI for auth | |
:param user: Username | |
:param passwd: Password | |
:return: Opener for BASIC auth | |
""" | |
auth_handler = urllib.request.HTTPBasicAuthHandler() | |
auth_handler.add_password(realm, uri, user, passwd) | |
opener = urllib.request.build_opener(auth_handler) | |
return opener | |
def request_rest_api(path: str, urlopen: "Function for opening a uri"=urllib.request.urlopen) -> "Response in dict": | |
""" | |
Request to the REST API and return the JSON response in dict | |
:param path: API path | |
:param urlopen: Function for opening a URI. urllib.request.urlopen or its compatible function is needed. | |
:return: Response from REST API in dict | |
""" | |
response = urlopen("{0}{1}".format(API_BASE_URI, path)) | |
charset = response.info().get_content_charset() | |
response_str = response.readall().decode(charset) | |
response_dict = json.loads(response_str) | |
return response_dict | |
def backup_bitbucket_git_repository(slug: str, user: str, dst_dir: str): | |
""" | |
Backup the specified repository | |
:param slug: "slug" on repository | |
:param user: Username | |
:param dst_dir: Where to backup the repository | |
""" | |
repository_name = "{slug}.git".format(slug=slug) | |
remote_uri = "[email protected]:{user}/{repository_name}".format( | |
user=user, | |
repository_name=repository_name) | |
local_path = os.path.join(dst_dir, repository_name) | |
os.chdir(dst_dir) | |
if os.path.exists(local_path): | |
# Fetch update from remote repository | |
subprocess.call(["git", "--git-dir", repository_name, "fetch", "--all"]) | |
else: | |
# Clone as a mirror from remote repository | |
subprocess.call(["git", "clone", "--mirror", remote_uri]) | |
return | |
def main(): | |
passwd = keyring.get_password(API_BASE_URI, AUTH_USERNAME) | |
opener = build_opener(AUTH_REALM, API_BASE_URI, AUTH_USERNAME, passwd) | |
repositories = request_rest_api("/1.0/user/repositories/", opener.open) | |
for repository in repositories: | |
slug = repository["slug"] | |
backup_bitbucket_git_repository(slug, AUTH_USERNAME, BACKUP_BASE) | |
if __name__ == '__main__': | |
import sys | |
if len(sys.argv) == 3: | |
# FIXME: should use the argparse | |
AUTH_USERNAME = sys.argv[1] | |
BACKUP_BASE = sys.argv[2] | |
else: | |
print("Usage: {0} USERNAME BACKUP_TARGET_DIR".format(sys.argv[0]), | |
file=sys.stderr) | |
sys.exit() | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment