Source code for owmeta_core.bundle.common

from os import scandir
from os.path import join as p, exists, relpath
import errno

try:
    from urllib.parse import quote as urlquote
except ImportError:
    from urllib import quote as urlquote

from .exceptions import NotABundlePath, BundleNotFound


BUNDLE_MANIFEST_VERSION = 1
'''
Current version number of the bundle manifest. Written by `Installer` and anticipated by
`Deployer` and `Fetcher`.
'''

BUNDLE_ARCHIVE_MIME_TYPE = 'application/x-gtar'
'''
MIME type for bundle archive files
'''


BUNDLE_INDEXED_DB_NAME = 'owm.db'
'''
Base name of the indexed database that gets built in a bundle directory during
installation
'''

BUNDLE_MANIFEST_FILE_NAME = 'manifest'
'''
Name of the manifest file in a bundle directory or archive
'''


[docs]def fmt_bundle_directory(bundles_directory, ident, version=None): ''' Get the directory for the given bundle identifier and version Parameters ---------- ident : str Bundle identifier version : int Version number. If not provided, returns the directory containing all of the versions ''' base = p(bundles_directory, urlquote(ident, safe='')) if version is not None: return p(base, str(version)) else: return base
[docs]def validate_manifest(bundle_path, manifest_data): ''' Validate manifest data in a `dict` Parameters ---------- bundle_path : str The path to the bundle directory or archive. Used in the exception message if the manifest data is invalid manifest_data : dict The data from a manifest file Raises ------ NotABundlePath Thrown in one of these conditions: - `manifest_data` lacks a `manifest_version` - `manifest_data` has a `manifest_version` > BUNDLE_MANIFEST_VERSION - `manifest_data` has a `manifest_version` <= 0 - `manifest_data` lacks a `version` - `manifest_data` lacks an `id` ''' manifest_version = manifest_data.get('manifest_version') if not manifest_version: raise NotABundlePath(bundle_path, 'the bundle manifest has no manifest version') if manifest_version > BUNDLE_MANIFEST_VERSION or manifest_version <= 0: raise NotABundlePath(bundle_path, 'the bundle manifest has an invalid manifest version') version = manifest_data.get('version') if not version: raise NotABundlePath(bundle_path, 'the bundle manifest has no bundle version') ident = manifest_data.get('id') if not ident: raise NotABundlePath(bundle_path, 'the bundle manifest has no bundle id')
def find_bundle_directory(bundles_directory, ident, version=None): # - look up the bundle in the bundle cache # - generate a config based on the current config load the config # - make a database from the graphs, if necessary (similar to `owm regendb`). If # delete the existing database if it doesn't match the store config if version is None: bundle_root = fmt_bundle_directory(bundles_directory, ident) latest_version = 0 try: ents = scandir(bundle_root) except (OSError, IOError) as e: if e.errno == errno.ENOENT: # FileNotFound raise BundleNotFound(ident, 'Bundle directory does not exist') from e raise for ent in ents: if ent.is_dir(): try: vn = int(ent.name) except ValueError: # We may put things other than versioned bundle directories in # this directory later, in which case this is OK pass else: if vn > latest_version: latest_version = vn version = latest_version if not version: raise BundleNotFound(ident, 'No versioned bundle directories exist') res = fmt_bundle_directory(bundles_directory, ident, version) if not exists(res): if version is None: raise BundleNotFound(ident, f'Bundle directory, "{res}", does not exist') else: raise BundleNotFound(ident, f'Bundle directory, "{res}", does not exist for the specified version', version) return res
[docs]def bundle_tree_filter(path, fullpath): ''' Returns true for file names that are to be included in a bundle for deployment or fetching. Parameters ---------- path : str The relative path of the file to check fillpath : str The full path of the file to check (usable for deeper inspection) ''' if path.startswith(BUNDLE_INDEXED_DB_NAME): # Skip the indexed DB -- the format isn't really designed for sharability and # we can regenerate it anyway. return False return True
class BundleTreeFileIgnorer: def __init__(self, bundle_directory): ''' Parameters ---------- bundle_directory : str Path to the source directory of the bundle. Serves as the base directory for filtering. ''' self.bundle_directory = bundle_directory def __call__(self, directory, contents): ''' Functions as needed for the "ignore" argument to `shutil.copytree` ''' files_to_ignore = [] for fname in contents: fpath = p(directory, fname) rpath = relpath(fpath, start=self.bundle_directory) if not bundle_tree_filter(rpath, fpath): files_to_ignore.append(fname) return files_to_ignore