#!/usr/bin/python3 # -*- coding: utf-8 -*- import argparse import time import sys from concurrent.futures import ThreadPoolExecutor from lxcmgr import lxcmgr from lxcmgr.pkgmgr import App, Stage, PkgMgr def print_apps(packages): for app, meta in packages.items(): print(app, meta['version']) for key, value in meta['meta'].items(): print(' {}: {}'.format(key, value)) def list_online(): pm = PkgMgr() apps = pm.online_packages['apps'] if apps: print_apps(apps) else: print('Repository lists no applications packages.') def list_installed(): pm = PkgMgr() apps = pm.installed_packages['apps'] if apps: print_apps(apps) else: print('No applications packages installed.') def list_updates(): pm = PkgMgr() apps = pm.installed_packages['apps'] if apps: updateable_apps = [app for app in apps if pm.has_update(app)] if updateable_apps: updates = {name: meta for (name, meta) in pm.online_packages['apps'].items() if name in updateable_apps} print_apps(updates) else: print('All installed application packages are up-to-date.') else: print('No applications packages installed.') def run_install_action(action, app): with ThreadPoolExecutor() as executor: future = executor.submit(action, app) while not future.done(): time.sleep(0.25) print_install_status(app) # Get the result of the future and let it raise exception, if there was any data = future.result() print_install_status(app) def print_install_status(app): # Prints current status of the installation. Uses ANSI "erase line" and "carriage return" to rewrite the status on single line. if app.stage == Stage.QUEUED: print('\x1b[KQueued...', end='\r') elif app.stage == Stage.DOWNLOAD: print('\x1b[KDownloading... {} % ({} / {} bytes)'.format(app.percent_processed, app.bytes_processed, app.bytes_total), end='\r') elif app.stage == Stage.UNPACK: print('\x1b[KUnpacking...', end='\r') elif app.stage == Stage.INSTALL: print('\x1b[KInstalling...', end='\r') elif app.stage == Stage.UNINSTALL: print('\x1b[KUninstalling...', end='\r') elif app.stage == Stage.UPDATE: print('\x1b[KUpdating...', end='\r') elif app.stage == Stage.DONE: print('\x1b[KDone.') def install_app(app): pm = PkgMgr() app = App(app) run_install_action(pm.install_app, app) def update_app(app): pm = PkgMgr() app = App(app) run_install_action(pm.update_app, app) def uninstall_app(app): pm = PkgMgr() app = App(app) run_install_action(pm.uninstall_app, app) def main(args): if args.action == 'list-installed': list_installed() elif args.action == 'list-online': list_online() elif args.action == 'list-updates': list_updates() elif args.action == 'install': install_app(args.app) elif args.action == 'update': update_app(args.app) elif args.action == 'uninstall': uninstall_app(args.app) parser = argparse.ArgumentParser(description='LXC container and package manager') subparsers = parser.add_subparsers() parser_list = subparsers.add_parser('list') subparsers_list = parser_list.add_subparsers() parser_list_installed = subparsers_list.add_parser('installed') parser_list_installed.set_defaults(action='list-installed') parser_list_online = subparsers_list.add_parser('online') parser_list_online.set_defaults(action='list-online') parser_list_updates = subparsers_list.add_parser('updates') parser_list_updates.set_defaults(action='list-updates') parser_install = subparsers.add_parser('install') parser_install.set_defaults(action='install') parser_install.add_argument('app', help='Application to install') parser_update = subparsers.add_parser('update') parser_update.set_defaults(action='update') parser_update.add_argument('app', help='Application to update') parser_uninstall = subparsers.add_parser('uninstall') parser_uninstall.set_defaults(action='uninstall') parser_uninstall.add_argument('app', help='Application to uninstall') main(parser.parse_args())