#!/usr/bin/env python3 from __future__ import annotations import re import subprocess import sys import typing import urllib.parse if typing.TYPE_CHECKING: from _typeshed import StrOrBytesPath def oneliner(*args) -> str: return subprocess.run(args, check=True, capture_output=True, text=True).stdout.strip() commit = oneliner('git', 'rev-parse', 'HEAD') local_branch = oneliner('git', 'branch', '--show-current') tag = tracking_branch = None if local_branch.startswith('tags/'): tag = local_branch[5:] if tag.endswith('^0'): tag = tag[:-2] remote_url = oneliner('git', 'config', 'remote.origin.url') else: try: tracking_branch = oneliner('git', 'config', 'branch.%s.merge' % local_branch) if tracking_branch.startswith('refs/heads/'): tracking_branch = tracking_branch[len('refs/heads/'):] else: raise Exception("can't handle " + tracking_branch) tracking_remote = oneliner('git', 'config', 'branch.%s.remote' % local_branch) remote_url = oneliner('git', 'config', 'remote.%s.url' % tracking_remote) except subprocess.CalledProcessError: remote_url = oneliner('git', 'config', 'remote.origin.url') relpath = oneliner('git', 'rev-parse', '--show-prefix')[:-1] remote_url = re.sub(r'^(.+@.+):(.+)$', r'ssh://\1/\2', remote_url) if remote_url.endswith('.git'): remote_url = remote_url[:-len('.git')] parsed = urllib.parse.urlparse(remote_url) hostname = parsed.hostname if hostname.startswith('github.com-'): hostname = 'github.com' obj_type = 'tree' if len(sys.argv) == 2: obj_type = 'blob' repo_url = urllib.parse.urlunparse(('https', hostname, parsed.path, '', '', '')) def url_for(treeish: str) -> str: dir_url = '%s/%s/%s' % (repo_url, obj_type, treeish) if relpath: dir_url = '%s/%s' % (dir_url, relpath) if len(sys.argv) == 2: return '%s/%s' % (dir_url, sys.argv[1]) else: return dir_url if tag is not None: print(url_for(tag)) elif tracking_branch is not None: print(url_for(tracking_branch)) print(url_for(commit)) for remote in oneliner('git', 'remote').splitlines(): try: default_branch = oneliner('git', 'rev-parse', '--abbrev-ref', remote + '/HEAD').removeprefix(remote + '/') except subprocess.CalledProcessError as e: if e.returncode == 128: # not a cloned repo continue else: raise if default_branch != tracking_branch: print(url_for(default_branch))