Skip to content

template

napt.build.template

Invoke-AppDeployToolkit.ps1 template generation for NAPT.

This module handles generating the Invoke-AppDeployToolkit.ps1 script by reading PSADT's template, substituting configuration values, and inserting recipe-specific install/uninstall code.

Design Principles
  • PSADT template remains pristine in cache
  • Generate script by substitution, not modification
  • Preserve PSADT's structure and comments
  • Support dynamic values (AppScriptDate, discovered version)
  • Merge org defaults with recipe overrides
Example

Basic usage:

from pathlib import Path
from napt.build.template import generate_invoke_script

script = generate_invoke_script(
    template_path=Path("cache/psadt/4.1.7/Invoke-AppDeployToolkit.ps1"),
    config=recipe_config,
    version="141.0.7390.123",
    psadt_version="4.1.7"
)

Path("builds/app/version/Invoke-AppDeployToolkit.ps1").write_text(script)

generate_invoke_script

generate_invoke_script(
    template_path: Path,
    config: dict[str, Any],
    version: str,
    psadt_version: str,
    architecture: str,
) -> str

Generate Invoke-AppDeployToolkit.ps1 from PSADT template and config.

Reads the PSADT template, replaces the $adtSession hashtable with values from the configuration, and inserts recipe-specific install/ uninstall code.

Parameters:

Name Type Description Default
template_path Path

Path to PSADT's Invoke-AppDeployToolkit.ps1 template.

required
config dict[str, Any]

Merged configuration (org + vendor + recipe).

required
version str

Application version (from filesystem).

required
psadt_version str

PSADT version being used.

required
architecture str

Resolved installer architecture (e.g., "x64", "x86", "arm64", "any"). Sets AppArch in the $adtSession hashtable; "any" leaves AppArch unset.

required

Returns:

Type Description
str

Generated PowerShell script text.

Raises:

Type Description
PackagingError

If template doesn't exist or template parsing fails.

Example

Generate deployment script from template:

from pathlib import Path

script = generate_invoke_script(
    Path("cache/psadt/4.1.7/Invoke-AppDeployToolkit.ps1"),
    config,
    "141.0.7390.123",
    "4.1.7",
    "x64",
)

Source code in napt/build/template.py
def generate_invoke_script(
    template_path: Path,
    config: dict[str, Any],
    version: str,
    psadt_version: str,
    architecture: str,
) -> str:
    """Generate Invoke-AppDeployToolkit.ps1 from PSADT template and config.

    Reads the PSADT template, replaces the $adtSession hashtable with
    values from the configuration, and inserts recipe-specific install/
    uninstall code.

    Args:
        template_path: Path to PSADT's Invoke-AppDeployToolkit.ps1 template.
        config: Merged configuration (org + vendor + recipe).
        version: Application version (from filesystem).
        psadt_version: PSADT version being used.
        architecture: Resolved installer architecture (e.g., "x64", "x86",
            "arm64", "any"). Sets AppArch in the $adtSession hashtable;
            "any" leaves AppArch unset.

    Returns:
        Generated PowerShell script text.

    Raises:
        PackagingError: If template doesn't exist or template parsing fails.

    Example:
        Generate deployment script from template:
            ```python
            from pathlib import Path

            script = generate_invoke_script(
                Path("cache/psadt/4.1.7/Invoke-AppDeployToolkit.ps1"),
                config,
                "141.0.7390.123",
                "4.1.7",
                "x64",
            )
            ```
    """
    from napt.logging import get_global_logger

    logger = get_global_logger()
    if not template_path.exists():
        raise PackagingError(f"PSADT template not found: {template_path}")

    logger.verbose("BUILD", f"Reading PSADT template: {template_path.name}")

    # Read template
    template = template_path.read_text(encoding="utf-8")

    # Build $adtSession variables
    logger.verbose("BUILD", "Building $adtSession variables...")
    session_vars = _build_adtsession_vars(config, version, psadt_version, architecture)

    logger.debug("BUILD", "--- $adtSession Variables ---")
    for key, value in session_vars.items():
        logger.debug("BUILD", f"  {key} = {value}")

    # Replace $adtSession block
    script = _replace_session_block(template, session_vars)
    logger.verbose("BUILD", "[OK] Replaced $adtSession hashtable")

    # Insert recipe code
    psadt_config = config.get("psadt", {})
    install_code = psadt_config.get("install")
    uninstall_code = psadt_config.get("uninstall")

    if install_code:
        logger.verbose("BUILD", "Inserting install code from recipe")
    if uninstall_code:
        logger.verbose("BUILD", "Inserting uninstall code from recipe")

    script = _insert_recipe_code(script, install_code, uninstall_code)

    logger.verbose("BUILD", "[OK] Script generation complete")

    return script