Source code for aiidalab.registry.web

"""Generate the app registry website."""

import logging
import os
import os.path
import shutil
from itertools import chain
from pathlib import Path

import pkg_resources

from ..utils import parse_app_repo
from . import api, yaml
from .apps_index import generate_apps_index
from .core import AppRegistryData, AppRegistrySchemas
from .html import build_html

logger = logging.getLogger(__name__)


[docs]def copy_static_tree_from_path(base_path, static_path): for root, _, files in os.walk(static_path): # Create directory base_path.joinpath(Path(root).relative_to(static_path)).mkdir( parents=True, exist_ok=True ) # Copy all files for filename in files: src = Path(root).joinpath(filename) dst = base_path.joinpath(Path(root).relative_to(static_path), filename) dst.write_bytes(src.read_bytes()) yield dst
[docs]def _walk_pkg_resources(package, root): paths = pkg_resources.resource_listdir(package, root) for path in paths: dir_paths = [ path for path in paths if pkg_resources.resource_isdir(package, os.path.join(root, path)) ] yield root, list(set(paths).difference(dir_paths)) for dir_path in dir_paths: yield from _walk_pkg_resources(package, os.path.join(root, dir_path))
[docs]def copy_static_tree_from_package(html_path, root="static"): for directory, files in _walk_pkg_resources(__package__, root): stem = html_path.joinpath(Path(directory).relative_to(root)) stem.mkdir(parents=True, exist_ok=True) for fn in files: src = pkg_resources.resource_stream( __package__, os.path.join(directory, fn) ) dst = stem.joinpath(fn) dst.write_bytes(src.read()) yield dst
[docs]def build( apps_path: Path, categories_path: Path, base_path: Path, html_path: Path = None, api_path: Path = None, static_path: Path = None, templates_path: Path = None, validate_output: bool = True, validate_input: bool = False, ): """Build the app registry website (including schema files).""" # Parse the schemas shipped with the package. schemas = AppRegistrySchemas.from_package() # Parse the apps and categories data from the given paths. data = AppRegistryData( apps=yaml.load(apps_path), categories=yaml.load(categories_path), ) if validate_input: data.validate(schemas) # Remove previous build (if present) and re-create root directory. shutil.rmtree(base_path, ignore_errors=True) base_path.mkdir(parents=True, exist_ok=True) apps_index, apps_data = generate_apps_index( data=data, scan_app_repository=parse_app_repo ) # Build the website and API endpoints. logger.info(f"Building registry at: {base_path.resolve()}") for outfile in chain( # Build the html pages if the html path is specified ( chain( # Copy static files from package copy_static_tree_from_package(html_path=base_path / html_path), # Copy static files (if specified) ( copy_static_tree_from_path(base_path / html_path, static_path) if static_path else () ), # Build the html pages. build_html( base_path=base_path / html_path, apps_index=apps_index, apps_data=apps_data, templates_path=templates_path, ), ) if html_path is not None else () ), # Build the API endpoints if the api path is specified ( api.build_api_v1( api_path=base_path / api_path, apps_index=apps_index, apps_data=apps_data, scan_app_repository=parse_app_repo, ) if api_path else () ), ): logger.info(f" - {outfile.relative_to(base_path)}") if validate_output: if api_path: api.validate_api_v1(api_path=base_path / api_path, schemas=schemas)