From e71514c6f9e37563ff051fcb35e56757e0db0647 Mon Sep 17 00:00:00 2001 From: Disassembler Date: Wed, 19 Feb 2020 23:13:46 +0100 Subject: [PATCH] Implement App basics and publish/unpublish --- usr/bin/spoc-app | 52 ++++++++++++++++++++------------- usr/lib/python3.8/spoc/app.py | 55 +++++++++++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/usr/bin/spoc-app b/usr/bin/spoc-app index 7b23d97..d5df60b 100644 --- a/usr/bin/spoc-app +++ b/usr/bin/spoc-app @@ -3,12 +3,26 @@ import argparse import os +from pkg_resources import parse_version -from spoc import publisher +from spoc import repo_local +from spoc import repo_online +from spoc import repo_publish +from spoc.app import App from spoc.cli import readable_size -def listing(): - raise NotImplementedException() +def listing(list_type): + if list_type == 'installed': + apps = repo_local.get_apps() + elif list_type == 'online': + apps = repo_online.get_apps() + elif list_type == 'updates': + online_apps = repo_online.get_apps() + apps = [a for a,d in repo_local.get_apps() if a in online_apps and parse_version(online_apps[a]['version']) > parse_version(d['version'])] + elif list_type == 'published': + apps = repo_publish.get_apps() + for app in apps: + print(app) def install(): raise NotImplementedException() @@ -28,23 +42,20 @@ def stop(): def status(): raise NotImplementedException() -def publish(composefile, do_publish): +def publish(filename, force): + app_name = os.path.basename(os.path.dirname(os.path.abspath(filename))) # Check if publishing is needed and attempt to publish the application - app_name = os.path.basename(os.path.dirname(filepath)) - if not do_publish: - try: - publisher.get_app(app_name) - except KeyError: - do_publish = True - if do_publish: - print(f'Publishing application "{app_name}"') - package = publisher.publish_app(app_name)['package'] - print(f'Application "{app_name}" compressed from {readable_size(package["size"])} to {readable_size(package["dlsize"])}') + if force or app_name not in repo_publish.get_apps(): + app = App(app_name, False) + print(f'Publishing application {app_name} from file {os.path.abspath(filename)}') + app.unpublish() + size, dlsize = app.publish(filename) + print(f'Application {app_name} compressed from {readable_size(size)} to {readable_size(dlsize)} and published successfully') else: - print(f'Application "{app_name}" already published, skipping publishing') + print(f'Application {app_name} already published, skipping publish task') -def unpublish(): - raise NotImplementedException() +def unpublish(app_name): + App(app_name, False).unpublish() parser = argparse.ArgumentParser(description='SPOC application manager') parser.set_defaults(action=None) @@ -52,7 +63,7 @@ subparsers = parser.add_subparsers() parser_list = subparsers.add_parser('list') parser_list.set_defaults(action=listing) -parser_list.add_argument('type', choices=('installed', 'online', 'upgrades', 'published'), default='installed', const='installed', nargs='?') +parser_list.add_argument('type', choices=('installed', 'online', 'updates', 'published'), default='installed', const='installed', nargs='?') parser_install = subparsers.add_parser('install') parser_install.set_defaults(action=install) @@ -81,7 +92,7 @@ parser_status.add_argument('app') parser_publish = subparsers.add_parser('publish') parser_publish.set_defaults(action=publish) parser_publish.add_argument('-f', '--force', action='store_true', help='Force republish already published application') -parser_publish.add_argument('file') +parser_publish.add_argument('filename') parser_unpublish = subparsers.add_parser('unpublish') parser_unpublish.set_defaults(action=unpublish) @@ -104,9 +115,8 @@ elif args.action is stop: elif args.action is status: status(args.app) elif args.action is publish: - publish(args.file, args.force) + publish(args.filename, args.force) elif args.action is unpublish: unpublish(args.app) else: parser.print_usage() - diff --git a/usr/lib/python3.8/spoc/app.py b/usr/lib/python3.8/spoc/app.py index 6bf3394..403463b 100644 --- a/usr/lib/python3.8/spoc/app.py +++ b/usr/lib/python3.8/spoc/app.py @@ -1,6 +1,57 @@ +# -*- coding: utf-8 -*- + +import json +import os +import tarfile + +from . import repo_local +from . import repo_publish +from .config import PUB_APPS_DIR +from .container import Container + class App: - def __init__(self): - self.name - None + def __init__(self, name, load_from_repo=True): + self.name = name self.version = None self.meta = {} self.containers = [] + if load_from_repo: + self.set_definition(repo_local.get_app(name)) + + def set_definition(self, definition): + self.version = definition['version'] + self.meta = definition['meta'] + self.containers = [Container(container) for container in definition['containers']] + + def get_definition(self): + return { + 'version': self.version, + 'meta': self.meta.copy(), + 'containers': [container.name for container in self.containers] + } + + def publish(self, filename): + builddir = os.path.dirname(filename) + os.makedirs(PUB_APPS_DIR, 0o700, True) + files = repo_publish.TarSizeCounter() + archive_path = os.path.join(PUB_APPS_DIR, f'{self.name}.tar.xz') + with tarfile.open(archive_path, 'w:xz') as tar: + for content in ('install', 'install.sh', 'update', 'update.sh', 'uninstall', 'uninstall.sh'): + content_path = os.path.join(builddir, content) + if os.path.exists(content_path): + tar.add(content_path, os.path.join(self.name, content), filter=files.add_file) + with open(filename) as f: + definition = json.load(f) + definition['size'] = files.size + definition['dlsize'] = os.path.getsize(archive_path) + definition['hash'] = repo_publish.sign_file(archive_path).hex() + repo_publish.register_app(self.name, definition) + return (definition['size'], definition['dlsize']) + + def unpublish(self): + repo_publish.unregister_app(self.name) + archive_path = os.path.join(PUB_APPS_DIR, f'{self.name}.tar.xz') + try: + os.unlink(archive_path) + except FileNotFoundError: + pass