From 25ab623328e63edabe6af54d7416e6d317988c1a Mon Sep 17 00:00:00 2001 From: "D. Berge" Date: Wed, 30 Aug 2023 14:17:47 +0200 Subject: [PATCH] Add functions for translating paths. The Dougal database will no longer store physical file paths but rather logical ones, relative to (config.yaml).imports.paths. These functions translate between physical and logical paths. --- bin/configuration.py | 71 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/bin/configuration.py b/bin/configuration.py index 17cf0f7..d59d0ee 100644 --- a/bin/configuration.py +++ b/bin/configuration.py @@ -1,4 +1,5 @@ import os +import pathlib from glob import glob from yaml import full_load as _load @@ -87,3 +88,73 @@ def rxflags (flagstr): for flag in flagstr: flags |= cases.get(flag, 0) return flags + +def translate_path (file): + """ + Translate a path from a Dougal import directory to an actual + physical path on disk. + + Any user files accessible by Dougal must be under a path prefixed + by `(config.yaml).imports.paths`. The value of `imports.paths` may + be either a string, in which case this represents the prefix under + which all Dougal data resides, or a dictionary where the keys are + logical paths and their values the corresponding physical path. + """ + cfg = read() + root = pathlib.Path(DOUGAL_ROOT) + filepath = pathlib.Path(file).resolve() + import_paths = cfg["imports"]["paths"] + + if filepath.is_absolute(): + if type(import_paths) == str: + # Substitute the root for the real physical path + # NOTE: `root` deals with import_paths not being absolute + prefix = root.joinpath(pathlib.Path(import_paths)).resolve() + return str(pathlib.Path(prefix).joinpath(*filepath.parts[2:])) + else: + # Look for a match on the second path element + if filepath.parts[1] in import_paths: + # NOTE: `root` deals with import_paths[…] not being absolute + prefix = root.joinpath(import_paths[filepath.parts[1]]) + return str(pathlib.Path(prefix).joinpath(*filepath.parts[2:])) + else: + # This path is invalid + raise TypeError("invalid path or file: {0!r}".format(filepath)) + else: + # A relative filepath is always resolved relative to the logical root + root = pathlib.Path("/") + return translate_path(root.joinpath(filepath)) + +def untranslate_path (file): + """ + Attempt to convert a physical path into a logical one. + See `translate_path()` above for details. + """ + cfg = read() + dougal_root = pathlib.Path(DOUGAL_ROOT) + filepath = pathlib.Path(file).resolve() + import_paths = cfg["imports"]["paths"] + physical_root = pathlib.Path("/") + + if filepath.is_absolute(): + if type(import_paths) == str: + if filepath.is_relative_to(import_paths): + physical_root = pathlib.Path("/") + physical_prefix = pathlib.Path(import_paths) + return str(root.joinpath(filepath.relative_to(physical_prefix))) + else: + raise TypeError("invalid path or file: {0!r}".format(filepath)) + else: + for key, value in import_paths.items(): + value = dougal_root.joinpath(value) + physical_prefix = pathlib.Path(value) + if filepath.is_relative_to(physical_prefix): + logical_prefix = physical_root.joinpath(pathlib.Path(key)).resolve() + return str(logical_prefix.joinpath(filepath.relative_to(physical_prefix))) + + # If we got here with no matches, this is not a valid + # Dougal data path + raise TypeError("invalid path or file: {0!r}".format(filepath)) + else: + # A relative filepath is always resolved relative to DOUGAL_ROOT + return untranslate_path(root.joinpath(filepath))