create builder infrastructure
This commit is contained in:
		
							
								
								
									
										35
									
								
								builders.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								builders.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| import functools | ||||
|  | ||||
| def _lazy_evaluable(func): | ||||
|     """ | ||||
|     Decorator which makes a function lazy-evaluable: that is, when it's | ||||
|     initially called, it returns a zero-argument lambda with the arguments | ||||
|     initially passed wrapped up in it. Calling that lambda has the effect | ||||
|     of executing the function. | ||||
|  | ||||
|     We use this in TZK to allow the user to use function calls in her config | ||||
|     to define the build steps, while not requiring her to write a bunch of | ||||
|     ugly and confusing lambda:'s in the config. The functions that will be called | ||||
|     are prepared during the config and executed later. | ||||
|     """ | ||||
|  | ||||
|     @functools.wraps(func) | ||||
|     def new_func(*args, **kwargs): | ||||
|         my_args = args | ||||
|         my_kwargs = kwargs | ||||
|         @functools.wraps(new_func) | ||||
|         def inner(): | ||||
|             func(*my_args, **my_kwargs) | ||||
|         return inner | ||||
|     return new_func | ||||
|  | ||||
| # Now a more descriptive name that doesn't expose inner workings | ||||
| # if the user wants to write her own builder. | ||||
| tzk_builder = _lazy_evaluable | ||||
|  | ||||
| @tzk_builder | ||||
| def printer(username: str): | ||||
|     if username == 'Maud': | ||||
|         raise Exception("No Mauds allowed!") | ||||
|     print(f"Hallelujah, {username} built a wiki!") | ||||
| printer.name = "Display the user's name" | ||||
| @@ -16,9 +16,10 @@ class ConfigurationManager: | ||||
|             if child.is_file() and child.name.endswith('.py'): | ||||
|                 mod_name = child.name.rsplit('.', 1)[0] | ||||
|                 if mod_name == 'tzk_config': | ||||
|                     sys.path.insert(0, Path("__file__").parent) | ||||
|                     sys.path.insert(0, str(self.config_path)) | ||||
|                     self.conf_mod = importlib.import_module(mod_name) | ||||
|                     del sys.path[0] | ||||
|                     del sys.path[0:1] | ||||
|                     break | ||||
|         else: | ||||
|             fail( | ||||
|   | ||||
							
								
								
									
										47
									
								
								tzk.py
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								tzk.py
									
									
									
									
									
								
							| @@ -3,6 +3,7 @@ import argparse | ||||
| import os | ||||
| import shutil | ||||
| import sys | ||||
| import traceback | ||||
| from typing import Optional | ||||
|  | ||||
| from config import cm | ||||
| @@ -146,6 +147,52 @@ class InitCommand(CliCommand): | ||||
|         tw.install(args.wiki_name, args.tiddlywiki_version_spec, args.author) | ||||
|  | ||||
|  | ||||
| class BuildCommand(CliCommand): | ||||
|     cmd = "build" | ||||
|     help = ("Build another wiki or derivative product, " | ||||
|             "such as a public version of the wiki, " | ||||
|             "from this TZK repository.") | ||||
|  | ||||
|     @classmethod | ||||
|     def setup_arguments(cls, parser: argparse.ArgumentParser) -> None: | ||||
|         parser.add_argument( | ||||
|             "product", | ||||
|             metavar="PRODUCT", | ||||
|             help="Name of the product you want to build (defined in your config file).", | ||||
|         ) | ||||
|  | ||||
|     def _precheck(self, product: str) -> None: | ||||
|         if cm.products is None: | ||||
|             fail("No 'products' dictionary is defined in your config file.") | ||||
|         if product not in cm.products: | ||||
|             fail(f"No '{product}' product found in the products dictionary " | ||||
|                  f"in your config file. (Available: {', '.join(cm.products.keys())})") | ||||
|         if not cm.products[product]: | ||||
|             fail(f"No build steps are defined in the '{product}' product " | ||||
|                  f"in your config file.") | ||||
|  | ||||
|     def execute(self, args: argparse.Namespace) -> None: | ||||
|         self._precheck(args.product) | ||||
|  | ||||
|         steps = cm.products[args.product] | ||||
|         print(f"tzk: Starting build of product '{args.product}'.") | ||||
|         print(f"tzk: Found {len(steps)} build steps.") | ||||
|  | ||||
|         for idx, step in enumerate(steps, 1): | ||||
|             if hasattr(step, 'name'): | ||||
|                 print(f"\ntzk: Step {idx}/{len(steps)}: {step.name}") | ||||
|             else: | ||||
|                 print(f"\ntzk: Step {idx}/{len(steps)}") | ||||
|             try: | ||||
|                 step() | ||||
|             except Exception as e: | ||||
|                 print(f"\ntzk: Build of product '{args.product}' failed on step {failed}. " | ||||
|                       f"The original error follows:") | ||||
|                 traceback.print_exc() | ||||
|                 sys.exit(1) | ||||
|  | ||||
|         print(f"\ntzk: Build of product '{args.product}' completed successfully.") | ||||
|  | ||||
|  | ||||
| parser = argparse.ArgumentParser() | ||||
| subparsers = parser.add_subparsers() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Soren I. Bjornstad
					Soren I. Bjornstad