#!/usr/bin/env python from __future__ import print_function from os.path import isdir, isfile, join, getmtime from os import mkdir from sys import stderr, exit import time import argparse import requests UPSTREAM='http://mirror.turnkeylinux.org/turnkeylinux/metadata/pve/aplinfo.dat' DATE_FORMAT='%a, %d %b %Y %H:%M:%S %Z' CACHE_PATH='/var/cache/tkl-lxc-index' if not isdir(CACHE_PATH): mkdir(CACHE_PATH) INDEX_TIMESTAMP_PATH = join(CACHE_PATH, 'timestamp') INDEX_PATH = join(CACHE_PATH, 'aplinfo.dat') if isfile(INDEX_TIMESTAMP_PATH): with open(INDEX_TIMESTAMP_PATH, 'r') as fob: TIMESTAMP = fob.read() else: TIMESTMAP = '' SECONDS_PER_DAY = 60*60*24 debian_codenames = { '8' : 'jessie', '9' : 'stretch', '10' : 'buster' } def get_header(key, headers): key = key.lower() for header, value in headers.items(): if header.lower() == key: return value raise KeyError(key) def need_to_update(): # if updated within the last 24 hours, don't bother last_modified = getmtime(INDEX_TIMESTAMP_PATH) if last_modified+SECONDS_PER_DAY > time.time(): return False response = requests.head(UPSTREAM) response.raise_for_status() try: return get_header('date', response.headers) != TIMESTAMP except KeyError: return True def download_upstream_index(): response = requests.get(UPSTREAM) response.raise_for_status() with open(INDEX_PATH, 'w') as fob: fob.write(response.text) try: timestamp = get_header('date', response.headers) except KeyError: timestamp = '' with open(INDEX_TIMESTAMP_PATH, 'w') as fob: fob.write(timestamp) def read_file(fob): attributes = [{}] last_key = '' for line in fob: line = line.rstrip() if not line: attributes.append({}) elif line[0] == ' ': attributes[-1][last_key] += '\n' + line else: key, value = line.split(': ') if key == 'Version': major, rest = value.split('.') minor, patch = rest.split('-') value = (int(major), int(minor)) elif key == 'OS': deb_version = value.split('-')[-1] if deb_version in debian_codenames: value = debian_codenames[deb_version] else: print('Unrecognised debian version {}'.format(deb_version), file=stderr) exit(1) attributes[-1][key] = value last_key = key return attributes[:-1] if __name__ == '__main__': parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='command') version = subparsers.add_parser('version', description='Get newest valid version of appliance') version.add_argument('appliance') update = subparsers.add_parser('update', description='Updates index if necessary') update.add_argument('-f', '--force', action='store_true', help='Force update') args = parser.parse_args() if args.command == 'version': appliance = args.appliance.lower() if not isfile(INDEX_PATH): print('Index not found: Updating', file=stderr) try: download_upstream_index() except requests.exceptions.RequestException: print('Failed to update index!', file=stderr) exit(1) with open(INDEX_PATH, 'r') as fob: data = read_file(fob) for record in data: if (appliance == record['Package'] or appliance == record['Package'].split('-', 1)[1]): print('{0}.{1}-{2}'.format( record['Version'][0], record['Version'][1], record['OS'])) exit(0) elif args.command == 'update': if args.force or need_to_update(): try: download_upstream_index() except requests.exceptions.RequestException: print('Failed to update index!', file=stderr) exit(1)