110 lines
4.1 KiB
Python
110 lines
4.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
from lxcmgr.paths import LXC_STORAGE_DIR
|
|
|
|
from . import crypto
|
|
from .paths import APP_DIR, IMAGE_DIR, META_FILE, PRIVATE_KEY, ROOT_DIR, SIGNATURE_FILE
|
|
|
|
class PackageExistsError(Exception):
|
|
pass
|
|
|
|
class Packer:
|
|
def __init__(self):
|
|
self.app = None
|
|
self.image = None
|
|
self.tar_path = None
|
|
self.xz_path = None
|
|
|
|
def load_packages_meta(self):
|
|
if os.path.exists(PKG_META):
|
|
with open(PKG_META, 'r') as f:
|
|
return json.load(f)
|
|
else:
|
|
return {'apps': {}, 'images': {}}
|
|
|
|
def save_packages_meta(self, packages):
|
|
with open(PKG_META, 'w') as f:
|
|
json.dump(packages, f, sort_keys=True, indent=4)
|
|
|
|
|
|
def pack_image(self, image, force):
|
|
self.image = image
|
|
# Prepare package file names
|
|
self.tar_path = os.path.join(IMAGE_DIR, '{}.tar'.format(self.image.name))
|
|
self.xz_path = '{}.xz'.format(self.tar_path)
|
|
if os.path.exists(self.xz_path):
|
|
if force:
|
|
self.unregister_image()
|
|
os.unlink(self.xz_path)
|
|
else:
|
|
raise PackageExistsError(self.xz_path)
|
|
self.create_image_archive()
|
|
self.register_image()
|
|
self.sign_packages()
|
|
|
|
def create_image_archive(self):
|
|
# Create archive
|
|
print('Archiving', self.image.path)
|
|
subprocess.run(['tar', '--xattrs', '-cpf', self.tar_path, self.image.name], cwd=LXC_STORAGE_DIR)
|
|
self.compress_archive()
|
|
|
|
def compress_archive(self):
|
|
# Compress the tarball with xz (LZMA2)
|
|
print('Compressing', self.tar_path, '({:.2f} MB)'.format(os.path.getsize(self.tar_path)/1048576))
|
|
subprocess.run(['xz', '-9', self.tar_path])
|
|
print('Compressed ', self.xz_path, '({:.2f} MB)'.format(os.path.getsize(self.xz_path)/1048576))
|
|
|
|
def register_image(self):
|
|
# Register package in global repository metadata file
|
|
print('Registering package {}'.format(self.image.name))
|
|
packages = self.load_packages_meta()
|
|
packages['images'][self.image.name] = self.image.conf.copy()
|
|
packages['images'][self.image.name]['size'] = os.path.getsize(self.xz_path)
|
|
packages['images'][self.image.name]['sha512'] = crypto.hash_file(self.xz_path)
|
|
self.save_packages_meta(packages)
|
|
|
|
def sign_packages(self):
|
|
signature = crypto.sign_file(PRIVATE_KEY, META_FILE)
|
|
with open(SIGNATURE_FILE, 'wb') as f:
|
|
f.write(signature)
|
|
|
|
def unregister_image(self):
|
|
# Removes package from global repository metadata file
|
|
packages = self.load_packages_meta()
|
|
if self.image.name in packages['images']:
|
|
del packages['images'][self.image.name]
|
|
self.save_packages_meta(packages)
|
|
|
|
def pack_app(self, app):
|
|
self.app = app
|
|
# Prepare package file names
|
|
self.tar_path = os.path.join(APP_DIR, '{}.tar'.format(self.image.name))
|
|
self.xz_path = '{}.xz'.format(self.tar_path)
|
|
if os.path.exists(self.xz_path):
|
|
os.unlink(self.xz_path)
|
|
self.create_app_archive()
|
|
self.register_app()
|
|
self.sign_packages()
|
|
|
|
def create_app_archive(self):
|
|
# Create archive with application setup scripts
|
|
print('Archiving setup scripts for', self.app.name)
|
|
scripts = ('install', 'install.sh', 'upgrade', 'upgrade.sh', 'uninstall', 'uninstall.sh')
|
|
scripts = [s for s in scripts if os.path.exists(os.path.join(self.app.build_dir, s))]
|
|
subprocess.run(['tar', '--xattrs', '-cpf', self.tar_path] + scripts, cwd=self.app.build_dir)
|
|
self.compress_archive()
|
|
|
|
def register_app(self):
|
|
# Register package in global repository metadata file
|
|
print('Registering package {}'.format(self.app.name))
|
|
packages = self.load_packages_meta()
|
|
packages['apps'][self.image.name] = self.app.conf.copy()
|
|
packages['apps'][self.image.name]['size'] = os.path.getsize(self.xz_path)
|
|
packages['apps'][self.image.name]['sha512'] = crypto.hash_file(self.xz_path)
|
|
self.save_packages_meta(packages)
|