diff --git a/git-open b/git-open index 30f36280390e077815dad40b19b4a18d8acb8381..b175a7a06d2d8f9716da61e11adf30be059b345b 100755 --- a/git-open +++ b/git-open @@ -1,15 +1,34 @@ #!/usr/bin/env python3 +"""Figure out the HTTP source of a remote, and open it in a browser.""" + import sys import subprocess import argparse import re import os.path + + +def err(s): + """Print error message.""" + print("\x1b[0;31mError\x1b[m " + s, file=sys.stderr) + + +def warn(s): + """Print warning message.""" + print("\x1b[0;33mWarn\x1b[m " + s, file=sys.stderr) + + +def info(s): + """Print info message.""" + print("\x1b[0;32mInfo\x1b[m " + s, file=sys.stderr) + + try: # package python-pyxdg on Arch from xdg.BaseDirectory import xdg_config_dirs except ModuleNotFoundError: - print("xdg module not found, defaulting to $HOME/.config", file=sys.stderr) + warn("xdg module not found, defaulting to $HOME/.config") import os home = os.getenv("HOME") xdg_config_dirs = [os.path.join(home, ".config")] @@ -20,8 +39,7 @@ try: import yaml can_load_configuration = True except ModuleNotFoundError: - print("yaml module not found, configuration will NOT be loaded", - file=sys.stderr) + warn("yaml module not found, configuration will NOT be loaded") configuration = { @@ -31,6 +49,7 @@ configuration = { def popen(str): + """Exec str, and return its stdout.""" p = subprocess.Popen(str.split(" "), universal_newlines=True, stdout=subprocess.PIPE) @@ -42,15 +61,24 @@ def popen(str): def gitconf(field): + """Get git config field, or die.""" return popen("git config " + field) def remote_url(remote_name): + """Get url for git remote by name.""" # return gitconf("remote.{}.url".format(remote_name)) return popen(f'git remote get-url {remote_name}').strip() def to_http(url): + """ + Convert url into matching HTTP url. + + Uses configuration['patterns'] to check for special cases, + otherwise anything starting with http is returned verbatim, and + git@ is replaced with https://. + """ for pattern in configuration['patterns']: if match := re.match(pattern['i'], url): rx = re.compile('[$]([0-9]+)') @@ -74,28 +102,33 @@ def to_http(url): def xdg_open(item): + """Run xdg-open on argument.""" subprocess.run(["xdg-open", item]) -def err(s): - print("\x1b[0;31mError\x1b[m " + s) - - -def warn(s): - print("\x1b[0;33mWarn\x1b[m " + s) - - -def info(s): - print("\x1b[0;32mInfo\x1b[m " + s) - - def open_remote(remote): + """Open url for the named remote.""" url = to_http(remote_url(remote)) xdg_open(url) info(f'opening {url}') +def load_configuration(): + """Load configuration file, updates `configuration`.""" + global configuration + # TODO possibly add ~/.config/git/open.yaml to list + for dir in xdg_config_dirs: + try: + with open(os.path.join(dir, 'git-open.yaml')) as f: + conf = yaml.unsafe_load(f) + configuration |= conf + break + except FileNotFoundError: + pass + + def main(args): + """Entry point, args should come from ArgumentParser.parse_args.""" out = popen("git remote") remotes = out.strip().split("\n") @@ -127,19 +160,6 @@ def main(args): err("All remotes failed") -def load_configuration(): - global configuration - # TODO possibly add ~/.config/git/open.yaml to list - for dir in xdg_config_dirs: - try: - with open(os.path.join(dir, 'git-open.yaml')) as f: - conf = yaml.unsafe_load(f) - configuration |= conf - break - except FileNotFoundError: - pass - - if __name__ == "__main__": # Note that argparse gives `--help' and `-h', but git "eats" # `--help'. `-h' does however work.