Skip to content

Instantly share code, notes, and snippets.

@YuriyGuts
Last active February 26, 2024 05:32
Show Gist options
  • Save YuriyGuts/f13383478d8bad9ac148 to your computer and use it in GitHub Desktop.
Save YuriyGuts/f13383478d8bad9ac148 to your computer and use it in GitHub Desktop.
Clones all GitHub Gists for the specified user.
#!/usr/bin/env python
"""
Clone all GitHub Gists for the specified user.
Copyright (c) 2018 Yuriy Guts
usage: gist-clone-all.py [-h] user token
positional arguments:
user Which user's Gists to clone.
token Command line token for GitHub authentication.
optional arguments:
-h, --help show this help message and exit
"""
from __future__ import division, print_function
import argparse
import os
import requests
import subprocess
import sys
import traceback
class HelpOnFailArgumentParser(argparse.ArgumentParser):
"""
Prints help whenever the command-line arguments could not be parsed.
"""
def error(self, message):
sys.stderr.write('error: %s\n\n' % message)
self.print_help()
sys.exit(2)
class RepoEnumerationException(Exception):
pass
def parse_command_line_args(args):
"""
Parse command-line arguments and organize them into a single structured object.
"""
program_desc = 'Clone all GitHub Gists for the specified user.'
parser = HelpOnFailArgumentParser(description=program_desc)
parser.add_argument('user', help="Which user's Gists to clone.")
parser.add_argument('token', help='Command line token for GitHub authentication.')
# Try parsing the arguments and fail properly if that didn't succeed.
return parser.parse_args(args)
def fetch_json(url, auth_token):
print('> HTTP fetch:', url)
headers = {
'Accept': 'application/vnd.github.v3+json',
'Authorization': "token " + auth_token,
'User-Agent': "YuriyGuts/gist-clone-all.py"
}
response = requests.get(url, headers=headers)
return response.json()
def get_command_output(command):
print('> Running:', command)
return subprocess.check_output(command, shell=True).decode('utf-8')
def is_repo_already_cloned(repo_name):
return os.path.exists(repo_name) and os.path.exists(os.path.join(repo_name, '.git'))
def clone_gist(gist):
"""
Clone a single Gist.
"""
gist_id = gist['id']
gist_name = gist['name']
repo_url = 'https://gist.github.com/{}.git'.format(gist_id)
# Clone the Gist.
print()
print('-------- Cloning {} [{}] --------'.format(gist_name, gist_id))
if is_repo_already_cloned(gist_name):
print('SKIP: repo already cloned')
return
clone_path = '{}-{}'.format(gist_name, gist_id)
get_command_output('git clone {} "{}"'.format(repo_url, clone_path))
def clone_all_gists(args):
"""
Discover all Gists for the user and clone them.
"""
print('Querying GitHub API...')
list_repos_url = 'https://api.github.com/users/{}/gists?per_page=200'.format(args.user)
gists = fetch_json(list_repos_url, args.token)
if not isinstance(gists, list):
raise RepoEnumerationException(gists)
# Print out all Gists.
print()
print('Will clone the following Gists:')
for gist in gists:
gist['name'] = list(gist['files'].values())[0]['filename']
print(' * {}'.format(gist['name']))
for gist in gists:
try:
clone_gist(gist)
except Exception:
print()
print('ERROR while cloning a repo.')
print()
traceback.print_exc()
def main():
parsed_args = parse_command_line_args(sys.argv[1:])
try:
clone_all_gists(parsed_args)
except RepoEnumerationException as e:
print('ERROR enumerating the gists (an incorrect GitHub username/password?).')
print('GitHub response:', e)
sys.exit(1)
except Exception:
traceback.print_exc()
sys.exit(1)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment