Last active
March 9, 2020 17:47
-
-
Save MohamedKari/d2ed975a0c9abc152e5e6262892aa1ed to your computer and use it in GitHub Desktop.
This file contains 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
''' | |
**Author**: | |
Mohamed Kari <contact@mkari.de> | |
**Describtion** | |
Clone private github repos effortlessly into your Notebook Cloud VM with a two-liner. | |
**Usage** | |
Alternative 1 (recommended): | |
------ | |
Copy the following two lines into your notebook: | |
!curl https://gist.githubusercontent.com/MohamedKari/d2ed975a0c9abc152e5e6262892aa1ed/raw/?$(date +%s) -o "nb-git.py" -s | |
%run nb-git.py basicauth MohamedKari/waymo_od_perception MohamedKari | |
- or - | |
%run nb-git.py oauth2 MohamedKari/waymo_od_perception | |
Then adapt the command line args to your specfic repo and - in case of basicauth - user name and run the cell. | |
To push changes back to the repo run | |
%run nb-git.py basicauth MohamedKari/waymo_od_perception MohamedKari --push | |
- or - | |
%run nb-git.py oauth2 MohamedKari/waymo_od_perception --push | |
------ | |
Alternative 2 | |
------ | |
Copy & paste & run the following code in your notebook. You'll be interactively asked for the relevant settings. | |
!curl https://gist.githubusercontent.com/MohamedKari/d2ed975a0c9abc152e5e6262892aa1ed/raw/?$(date +%s) -o "nb-git.py" -s | |
%run nb-git.py | |
------ | |
Alternative 3: | |
------ | |
Copy & paste the second code block from below into your Colab Notebook and execute it. You'll be interactively asked for the relevant settings. | |
To avoid re-entering the settings every time you load the notebook, you can hard-code them at the top of the copied notebook. | |
------ | |
''' | |
######################################################### | |
###### CALLABLE SCRIPT FOR MINIMAL INTERACTIVENESS ###### | |
######################################################### | |
import argparse | |
import sys | |
def get_interactive(args): | |
return None, None, None, None, None | |
def get_oauth2_settings(args): | |
return "oauth2", args.gitcommand, args.repo, None, args.keep_secret | |
def get_basicauth_settings(args): | |
return "basicauth", args.gitcommand, args.repo, args.user, args.keep_secret | |
# shared parser that is inherited to other parsers | |
shared_parser = argparse.ArgumentParser(add_help=False) | |
shared_parser.add_argument("-k", "--keep-secret", action="store_true") | |
# mutually exclusive group that stores their value in a field called 'gitcommand' which assumes the default 'clone' | |
group = shared_parser.add_mutually_exclusive_group() | |
group.add_argument("-c", "--clone", action="store_const", dest="gitcommand", const="clone") | |
group.add_argument("-p", "--push", action="store_const", dest="gitcommand", const="push") | |
group.set_defaults(gitcommand="clone") | |
# Main and sub parsers | |
mainparser = argparse.ArgumentParser() | |
mainparser.set_defaults(func=get_interactive) | |
subparsers = mainparser.add_subparsers() | |
subparser_oauth2 = subparsers.add_parser("oauth2", parents=[shared_parser]) | |
subparser_oauth2.add_argument("repo") | |
subparser_oauth2.set_defaults(func=get_oauth2_settings) | |
subparser_basicauth = subparsers.add_parser("basicauth", parents=[shared_parser]) | |
subparser_basicauth.add_argument("repo") | |
subparser_basicauth.add_argument("user") | |
subparser_basicauth.set_defaults(func=get_basicauth_settings) | |
args = mainparser.parse_args(sys.argv[1:]) | |
mode, gitcommand, repo, user, keep_secret = args.func(args) | |
######################################################### | |
########## PASTABLE CODE FOR INTERACTIVE CLONE ########## | |
######################################################### | |
# hardcode setting here if you like by uncommenting and editing the lines | |
# if not, you'll be asked interactively for the settings | |
# gitcommand = "clone" | |
# repo = "MohamedKari/waymo_od_perception" | |
# mode = "basicauth" | |
# user = "MohamedKari" | |
# or | |
# gitcommand = "clone" | |
# repo = "MohamedKari/waymo_od_perception" | |
# mode = "oauth2" | |
import os | |
from getpass import getpass | |
import urllib.parse | |
import re | |
gitcommand = gitcommand if "gitcommand" in vars() and gitcommand is not None else input("gitcommand (clone, push)") | |
repo = repo if "repo" in vars() and repo is not None else input("Repo (<user>/<name>): ") | |
git_dir = repo.split("/")[1] | |
mode = mode if "mode" in vars() and mode is not None else { | |
"": "basicauth", | |
"b": "basicauth", | |
"basicauth": "basicauth", | |
"o": "oauth2", | |
"oauth2": "oauth2" | |
}.get(input("[b]asicauth or [o]auth2 (default: basicauth):\n")) | |
remove_secret = mode if "mode" in vars() and mode is not None else True | |
if mode == "basicauth": | |
user = user if "user" in vars() and user is not None else input("User name: ") | |
secret = getpass('Password: ') | |
secret = urllib.parse.quote(secret) | |
cmd_string = f"git --git-dir {git_dir}/.git {gitcommand} https://{user}:{secret}@github.com/{repo}.git" | |
if mode == "oauth2": | |
secret = getpass('Token: ') | |
secret = urllib.parse.quote(secret) | |
cmd_string = f"git --git-dir {git_dir}/.git {gitcommand} https://oauth2:{secret}@github.com/{repo}.git" | |
os.system(cmd_string) | |
del cmd_string | |
del secret | |
if remove_secret: | |
with open(os.path.join(repo.split("/")[1], ".git", "config"), "rt+") as f: | |
gitconfig = f.read() | |
f.seek(0) | |
f.write( | |
re.sub(r"https://[A-Za-z0-9]*:.*@", f"https://", gitconfig)) # ASSUMPTION: [A-Za-z0-9]* covers GitHub usernames | |
f.truncate() | |
else: | |
print("WARNING: you chose not to remove your secret. Everybody with access to files in this directory will be able to read your password or token in plaintext from the cloned repos .git/config file!") | |
################################################# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment