# iterate source tree # create directors in target tree # for each item: # run processor(s) on item, each processor could be in a chain or a branch # Processors also provide filename munging # output target based on processor output import argparse import logging import os import shutil import sys import time from typing import Dict, List, cast from .metadata import MetaTree from .processchain import ProcessorChains from .processors.processors import PassthroughException from .pygments import pygments_get_css, pygments_markup_contents_html from .template_tools import (date_iso8601, file_content, file_list, file_list_hier, file_metadata, file_name, file_raw, time_iso8601) logger = logging.getLogger() def setup_logging(verbose: bool = False) -> None: pass def get_args(args: List[str]) -> argparse.Namespace: parser = argparse.ArgumentParser("Compile a Pixywerk directory into an output directory.") parser.add_argument("root", help="The root of the pixywerk directory to process.") parser.add_argument("output", help="The output directory to export post-compiled files to.") parser.add_argument( "-c", "--clean", help="Remove the target tree before proceeding (by renaming to .bak).", action="store_true" ) parser.add_argument("-s", "--safe", help="Abort if the target directory already exists.", action="store_true") parser.add_argument("-t", "--template", help="The template directory (default: root/templates)", default=None) parser.add_argument("-d", "--dry-run", help="Perform a dry-run.", action="store_true") parser.add_argument("-v", "--verbose", help="Output verbosely.", action="store_true") parser.add_argument("--processors", help="Specify a path to a processor configuration file.", default=None) # parser.add_argument("--prescript", help="Specify one or more prescripts to run (in order specified) with context of the compile.", default=[], action="append") # parser.add_argument("--postscript", help="Specify one or more postsscripts to run (in order specified) with context of the compile.", default=[], action="append") result = parser.parse_args(args) # validate arguments if not os.path.isdir(result.root): raise FileNotFoundError("can't find root folder {}".format(result.root)) if not result.template: result.template = os.path.join(result.root, "templates") result.excludes = [result.template] return result def main() -> int: try: args = get_args(sys.argv[1:]) except FileNotFoundError as ex: print("error finding arguments: {}".format(ex)) return 1 setup_logging(args.verbose) if os.path.exists(args.output) and args.clean: bak = "{}.bak-{}".format(args.output, int(time.time())) print("cleaning target {} -> {}".format(args.output, bak)) os.rename(args.output, bak) process_chains = ProcessorChains(args.processors) default_metadata = { "templates": args.template, "template": "default.jinja2", "dir-template": "default-dir.jinja2", "filters": {}, "build-time": time.time(), "uuid-oid-root": "pixywerk", "summary": "", "description": "", "author": "", "author_email": "", } meta_tree = MetaTree(args.root, default_metadata) file_list_cache = cast(Dict, {}) file_cont_cache = cast(Dict, {}) file_name_cache = cast(Dict, {}) file_raw_cache = cast(Dict, {}) flist = file_list(args.root, file_list_cache) default_metadata["globals"] = { "get_file_list": flist, "get_hier": file_list_hier(args.root, flist), "get_file_name": file_name(args.root, meta_tree, process_chains, file_name_cache), "get_file_content": file_content(args.root, meta_tree, process_chains, file_cont_cache), "get_raw": file_raw(args.root, file_raw_cache), "get_file_metadata": file_metadata(meta_tree), "get_time_iso8601": time_iso8601("UTC"), "get_date_iso8601": date_iso8601("UTC"), "pygments_get_css": pygments_get_css, "pygments_markup_contents_html": pygments_markup_contents_html, } for root, _, files in os.walk(args.root): workroot = os.path.relpath(root, args.root) if workroot == ".": workroot = "" target_dir = os.path.join(args.output, workroot) print("mkdir -> {}".format(target_dir)) if not args.dry_run: try: os.mkdir(target_dir) except FileExistsError: if args.safe: print("error, target directory exists, aborting") return 1 for f in files: # fixme global generic filters if f.endswith(".meta") or f.endswith("~"): continue metadata = meta_tree.get_metadata(os.path.join(workroot, f)) chain = process_chains.get_chain_for_filename(os.path.join(root, f), ctx=metadata) print("process {} -> {}".format(os.path.join(root, f), os.path.join(target_dir, chain.output_filename))) if not args.dry_run: try: with open(os.path.join(target_dir, chain.output_filename), "w") as outfile: for line in chain.output: outfile.write(line) except PassthroughException: shutil.copyfile(os.path.join(root, f), os.path.join(target_dir, chain.output_filename)) return 0 if __name__ == "__main__": sys.exit(main())