Skip to content

Instantly share code, notes, and snippets.

@bryanjhv
Last active June 15, 2020 03:10
Show Gist options
  • Save bryanjhv/a357fc6bbc44eeeb788ee029400a9600 to your computer and use it in GitHub Desktop.
Save bryanjhv/a357fc6bbc44eeeb788ee029400a9600 to your computer and use it in GitHub Desktop.
Get PPA .gpg and .list files easily on Ubuntu
#!/usr/bin/python3
# USAGE:
# getppa git-core/ppa bionic
# getppa certbot/certbot bionic
# getppa git-core/ppa bionic git.%s
# getppa certbot/certbot bionic certbot.%s
from shutil import rmtree
from sys import argv, exit
from atexit import register
from tempfile import mkdtemp
from json import dumps, loads
from subprocess import Popen, PIPE
from urllib.error import HTTPError
from urllib.request import Request, urlopen
DEB_URL = 'deb http://ppa.launchpad.net/%s/%s/ubuntu %s main'
PPA_URL = 'https://launchpad.net/api/1.0/~%s/+archive/ubuntu/%s'
KEY_URL = 'https://keyserver.ubuntu.com/pks/lookup?op=get&options=mr&exact=on&search=0x%s'
def req(url, json=False):
res = urlopen(Request(url))
data = res.read().decode('utf-8', 'strict')
return loads(data) if json else data
h = mkdtemp()
register(lambda: rmtree(h))
def gpg(args, stdin):
cmd = 'gpg -q --homedir %s --no-default-keyring --no-options --import --import-options %s' % (h, args)
p = Popen(cmd.split(), stdin=PIPE, stdout=PIPE)
(stdout, _) = p.communicate(stdin)
return (p.returncode, stdout)
def download(ppa, code, base=None):
try:
(owner, name) = ppa.split('/')
info = req(PPA_URL % (owner, name), True)
if not base: base = '%s__%s.%%s' % (owner, name)
ppa_list = DEB_URL % (owner, name, code) + '\n'
ppa_list += ppa_list.replace('deb', '# deb-src', 1)
fingerprint = info['signing_key_fingerprint']
armored_key = req(KEY_URL % fingerprint, False)
(r, minimal_key) = gpg('import-minimal,import-export', armored_key.encode())
if r != 0:
print('ERROR: Cannot minify GPG key.')
exit(2)
fingerprints = []
(r, output) = gpg('show-only --fingerprint --batch --with-colons', minimal_key)
if r == 0:
for line in output.decode('utf-8').splitlines():
if line.startswith('fpr:'):
fingerprints.append(line.split(':')[9])
if len(fingerprints) != 1:
print('ERROR: There are many GPG fingerprints.')
exit(2)
if fingerprint != fingerprints[0]:
print('ERROR: GPG fingerprints not matching.')
exit(2)
ppa_gpg = minimal_key
with open(base % 'list', 'w') as f:
f.write(ppa_list)
with open(base % 'gpg', 'wb') as f:
f.write(ppa_gpg)
print('SUCCESS!')
print()
print('Run the following:')
print()
print(' sudo chmod 644 %s' % (base % '*'))
print(' sudo chown root:root %s' % (base % '*'))
print(' sudo mv %s /etc/apt/trusted.gpg.d' % (base % 'gpg'))
print(' sudo mv %s /etc/apt/sources.list.d' % (base % 'list'))
print(' sudo apt update')
print()
except HTTPError as e:
if e.code == 404:
print('ERROR: PPA does not exist.')
exit(2)
print('ERROR: Unknown network error.')
exit(2)
if __name__ == '__main__':
if len(argv) < 3:
print('USAGE: %s user/repo code [base]' % argv[0])
exit(1)
download(*argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment