Skip to content

Commit

Permalink
Merge fa154ee into f7a0da6
Browse files Browse the repository at this point in the history
  • Loading branch information
yohanboniface committed Feb 27, 2016
2 parents f7a0da6 + fa154ee commit d578dfa
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 175 deletions.
1 change: 0 additions & 1 deletion ideascube/conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,4 +304,3 @@
BACKUP_FORMAT = 'zip' # One of 'zip', 'tar', 'bztar', 'gztar'

CATALOG_CACHE_BASE_DIR = '/var/cache/ideascube/catalog'
CATALOG_KIWIX_INSTALL_DIR = os.path.join(STORAGE_ROOT, 'kiwix')
202 changes: 135 additions & 67 deletions ideascube/serveradmin/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,111 @@ def to_file(self, path):
f.write(yaml.safe_dump(d, default_flow_style=False))


class Handler:

def __init__(self):
default = os.path.join(settings.STORAGE_ROOT, self.typename)
settingname = 'CATALOG_{}_INSTALL_DIR'.format(self.typename.upper())
self._install_dir = getattr(settings, settingname, default)

def install(self, package, download_path):
package.install(download_path, self._install_dir)

def remove(self, package):
package.remove(self._install_dir)

def commit(self, removed=None, installed=None):
raise NotImplementedError('Subclasses must implement this method')

def restart_service(self, name):
sys.stdout.write('Restarting service "{}"\n'.format(name))
try:
manager = SystemManager()
service = manager.get_service(name)

except NoSuchUnit:
# Service is not installed, give up.
pass

else:
manager.restart(service.Id)


class Kiwix(Handler):
typename = 'kiwix'

def commit(self, removed=None, installed=None):
sys.stdout.write('Rebuilding the Kiwix library\n')
library = etree.Element('library')
libdir = os.path.join(self._install_dir, 'data', 'library')

for libpath in glob(os.path.join(libdir, '*.xml')):
zimname = os.path.basename(libpath)[:-4]

with open(libpath, 'r') as f:
et = etree.parse(f)
books = et.findall('book')

# Messing with the path gets complicated otherwise
# TODO: Can we assume this is always true for stuff distributed
# by kiwix?
assert len(books) == 1

book = books[0]
book.set('path', 'data/content/%s' % zimname)
book.set('indexPath', 'data/index/%s.idx' % zimname)

library.append(book)

with open(os.path.join(self._install_dir, 'library.xml'), 'wb') as f:
f.write(etree.tostring(
library, xml_declaration=True, encoding='utf-8'))

self.restart_service('kiwix-server')


class Nginx(Handler):
typename = 'nginx'
template = """
server {{
listen 80;
server_name {server_name};
root {root};
index index.html;
}}
"""
root = os.path.join(settings.STORAGE_ROOT, 'nginx')
# root = '/etc/nginx/'

def commit(self, removed=None, installed=None):
if removed:
for pkg in removed:
self.unregister_site(pkg)
if installed:
for pkg in installed:
self.register_site(pkg)
self.restart_service('nginx')

def register_site(self, package):
available = os.path.join(self.root, 'sites-available', package.id)
enabled = os.path.join(self.root, 'sites-enabled', package.id)
server_name = 'http://{subdomain}.{domain}'.format(
subdomain=package.id, domain=settings.DOMAIN)
root = package.get_root_dir(self._install_dir)
with open(available, 'w') as f:
f.write(self.template.format(server_name=server_name, root=root))
try:
os.symlink(available, enabled)
except FileExistsError:
pass

def unregister_site(self, package):
available = os.path.join(self.root, 'sites-available', package.id)
enabled = os.path.join(self.root, 'sites-enabled', package.id)
os.remove(available)
os.remove(enabled)


class MetaRegistry(type):
def __new__(mcs, name, bases, attrs, **kwargs):
cls = super().__new__(mcs, name, bases, attrs)
Expand Down Expand Up @@ -110,6 +215,7 @@ def remove(self, install_dir):

class ZippedZim(Package):
typename = 'zipped-zim'
handler = Kiwix

def install(self, download_path, install_dir):
if not zipfile.is_zipfile(download_path):
Expand Down Expand Up @@ -140,63 +246,26 @@ def remove(self, install_dir):
shutil.rmtree(path)


class Handler(metaclass=MetaRegistry):
registered_types = {}

def __init__(self):
settingname = 'CATALOG_{}_INSTALL_DIR'.format(self.typename.upper())
self._install_dir = getattr(settings, settingname)

def install(self, package, download_path):
package.install(download_path, self._install_dir)

def remove(self, package):
package.remove(self._install_dir)
class StaticFolder(Package):
typename = 'static-folder'
handler = Nginx

def commit(self):
raise NotImplementedError('Subclasses must implement this method')


class Kiwix(Handler):
typename = 'kiwix'

def commit(self):
sys.stdout.write('Rebuilding the Kiwix library\n')
library = etree.Element('library')
libdir = os.path.join(self._install_dir, 'data', 'library')

for libpath in glob(os.path.join(libdir, '*.xml')):
zimname = os.path.basename(libpath)[:-4]

with open(libpath, 'r') as f:
et = etree.parse(f)
books = et.findall('book')

# Messing with the path gets complicated otherwise
# TODO: Can we assume this is always true for stuff distributed
# by kiwix?
assert len(books) == 1

book = books[0]
book.set('path', 'data/content/%s' % zimname)
book.set('indexPath', 'data/index/%s.idx' % zimname)

library.append(book)
def extract(self, download_path, install_dir):
if not zipfile.is_zipfile(download_path):
os.unlink(download_path)
raise InvalidFile('{} is not a zip file'.format(download_path))

with open(os.path.join(self._install_dir, 'library.xml'), 'wb') as f:
f.write(etree.tostring(
library, xml_declaration=True, encoding='utf-8'))
with zipfile.ZipFile(download_path, "r") as z:
z.extractall(install_dir)

try:
manager = SystemManager()
kiwix = manager.get_service('kiwix-server')
def get_root_dir(self, install_dir):
return os.path.join(install_dir, self.id)

except NoSuchUnit:
# Kiwix is not installed, give up
pass
def install(self, download_path, install_dir):
self.extract(download_path, self.get_root_dir(install_dir))

else:
manager.restart(kiwix.Id)
def remove(self, install_dir):
shutil.rmtree(self.get_root_dir(install_dir))


class Catalog:
Expand Down Expand Up @@ -273,17 +342,7 @@ def _get_packages(self, id_patterns, source, fail_if_no_match=True):
return pkgs

def _get_handler(self, package):
try:
handlertype = package.handler

except AttributeError:
raise InvalidPackageMetadata('Packages must have a handler')

try:
return Handler.registered_types[handlertype]()

except KeyError:
raise InvalidHandlerType(handlertype)
return package.handler()

def _verify_sha256(self, path, sha256sum):
sha = sha256()
Expand Down Expand Up @@ -362,6 +421,7 @@ def list_upgradable(self, ids):

def install_packages(self, ids):
used_handlers = {}
installed = []

for pkg in self._get_packages(ids, self._catalog['available']):
if pkg.id in self._catalog['installed']:
Expand All @@ -376,29 +436,34 @@ def install_packages(self, ids):
used_handlers[handler.__class__.__name__] = handler
self._catalog['installed'][pkg.id] = (
self._catalog['available'][pkg.id])
installed.append(pkg)

for handler in used_handlers.values():
handler.commit()
handler.commit(installed=installed)

self._persist_cache()

def remove_packages(self, ids):
used_handlers = {}
removed = []

for pkg in self._get_packages(ids, self._catalog['installed']):
handler = self._get_handler(pkg)
sys.stdout.write('Removing {0.id}\n'.format(pkg))
handler.remove(pkg)
used_handlers[handler.__class__.__name__] = handler
del(self._catalog['installed'][pkg.id])
removed.append(pkg)

for handler in used_handlers.values():
handler.commit()
handler.commit(removed=removed)

self._persist_cache()

def upgrade_packages(self, ids):
used_handlers = {}
installed = []
removed = []

for ipkg in self._get_packages(ids, self._catalog['installed']):
upkg = self._get_package(ipkg.id, self._catalog['available'])
Expand All @@ -416,15 +481,17 @@ def upgrade_packages(self, ids):

ihandler.remove(ipkg)
used_handlers[ihandler.__class__.__name__] = ihandler
removed.append(ipkg)

uhandler.install(upkg, download_path)
used_handlers[uhandler.__class__.__name__] = uhandler
installed.append(upkg)

self._catalog['installed'][ipkg.id] = (
self._catalog['available'][upkg.id])

for handler in used_handlers.values():
handler.commit()
handler.commit(removed=removed, installed=installed)

self._persist_cache()

Expand All @@ -434,7 +501,8 @@ def _load_cache(self):
with open(self._cache_catalog, 'r') as f:
self._catalog = yaml.safe_load(f.read())

else:
# yaml.safe_load returns None for an empty file.
if not getattr(self, '_catalog', None):
self._catalog = {'installed': {}, 'available': {}}
self._persist_cache()

Expand Down
Binary file not shown.

0 comments on commit d578dfa

Please sign in to comment.