Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,52 @@ TP is a template processing engine developed for TASTE Document Generator. Its m

## Installation

TODO
This project uses Python. The recommended way to install dependencies is via the provided Makefile which exposes a convenient `make install` target.

Prerequisites:
- Python 3.10+ (or a compatible system Python)

## Configuration

None

## Running

The assumed use case is for the Template Processor to be invoked by TASTE Document Generator. However, if TP is to be used manually, the following command line interface, as documented in the built-in help, is available:
The Template Processor can be run from the command line. The application name is `template-processor` which exposes the following arguments. Run the built-in help to see the same list:

```bash
template-processor --help
```

Key command-line arguments:

- `-i, --iv` : Input Interface View file (XML)
- `-d, --dv` : Input Deployment View file (XML)
- `-s, --system-objects` : One or more CSV files describing System Object Types (can be supplied multiple times)
- `-v, --value` : One or more name=value pairs to provide template values (e.g., `-v TARGET=ASW`)
- `-t, --template` : One or more template files to process (Mako templates). This argument can be provided multiple times.
- `-m, --module-directory` : Module directory for Mako to use for compiled template modules (optional)
- `-o, --output` : Output directory for processed templates (required)
- `--verbosity` : Logging verbosity (choices `info`, `debug`, `warning`, `error`, default `warning`)
- `-p, --postprocess` : Postprocessing option (choices `none`, `md2docx`, `md2html`; default `none`)

Example usage:

```bash
# instantiate a template and postprocess to DOCX
template-processor \\
-i examples/demo-project/interfaceview.xml \\
-d examples/demo-project/deploymentview.dv.xml \\
-s data/parameters.csv \\
-v TARGET=ASW \\
-t data/ecss-template/ecss-e-st-40c_4_1_software_static_architecture.tmplt \\
-o output \\
-p md2docx
```

TODO
Notes:
- The `-o/--output` directory will be used for writing generated files; templates may also copy or move generated assets (images) into that directory if supported by the template.
- When using `md2docx` postprocessing, image paths inside the generated Markdown should be resolvable from the working directory or the output directory so images are embedded correctly in the produced DOCX.

## Frequently Asked Questions (FAQ)

Expand Down
179 changes: 179 additions & 0 deletions data/ecss-template/ecss-e-st-40c_4_3_software_behaviour.tmplt
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<%
## Data Initialization
# Get all functions

funcs = []
def get_function_children(func):
result = []
if func.nested_functions:
for nested in func.nested_functions:
result.append(nested)
result.extend(get_function_children(nested))
return result

for func in interface_view.functions:
funcs.append(func)
funcs.extend(get_function_children(func))

funcs.sort(key=lambda f: f.name.lower())

# Get functions deployed to the target partition
target_partition_name = values["TARGET"]

deployed_funcs = []
target_partition = None
for node in deployment_view.nodes:
for partition in node.partitions:
if partition.name == target_partition_name:
target_partition = partition

deployed_func_names = [f.name for f in target_partition.functions]
for fun in funcs:
if fun.name in deployed_func_names:
deployed_funcs.append(fun)

# Only leaf functions are deployed, so a correction for parents must be applied
for func in funcs:
if func.nested_functions:
for nested in func.nested_functions:
if nested in deployed_funcs and not func in deployed_funcs:
deployed_funcs.append(func)
deployed_func_names.append(func.name)

# Filter SDL functions only
import os
import subprocess
import glob

sdl_funcs = [func for func in deployed_funcs if func.language and func.language.value == "SDL"]

# Generate SDL behavior diagrams using OpenGEODE
def generate_sdl_images(func):
"""Generate SDL images for a function using OpenGEODE"""
func_lower = func.name.lower()
images = []

# Try different path patterns for SDL/src directory
# Pattern 1: work/{function}/SDL/src
sdl_path_1 = f"work/{func_lower}/SDL/src"
# Pattern 2: work/{function}/implem/{implementation}/SDL/src
sdl_path_2_pattern = f"work/{func_lower}/implem/*/SDL/src"

sdl_paths = []
if os.path.exists(sdl_path_1):
sdl_paths.append(sdl_path_1)
else:
# Check for implementation-specific paths
matching_paths = glob.glob(sdl_path_2_pattern)
sdl_paths.extend(matching_paths)

for sdl_path in sdl_paths:
if not os.path.exists(sdl_path):
continue

# Find the system_structure.pr and function.pr files
system_pr = os.path.join(sdl_path, "system_structure.pr")
func_pr = os.path.join(sdl_path, f"{func_lower}.pr")

if not os.path.exists(system_pr) or not os.path.exists(func_pr):
continue

# Generate images using OpenGEODE
try:
# Change to SDL/src directory to run opengeode
original_dir = os.getcwd()

# Get absolute path to output directory before changing directories
abs_output_dir = None
if output_directory:
abs_output_dir = os.path.abspath(output_directory)
print(f"Output directory (absolute): {abs_output_dir}")
print(f"Output directory exists: {os.path.exists(abs_output_dir)}")

# Get absolute path to SDL directory
abs_sdl_path = os.path.abspath(sdl_path)

os.chdir(sdl_path)

# Run OpenGEODE to generate PNG images
subprocess.run(
["opengeode", "--png", "system_structure.pr", f"{func_lower}.pr"],
check=False,
capture_output=True
)

# Find all generated PNG files and move them to output directory
png_files = glob.glob("*.png")
print(f"Found {len(png_files)} PNG files in {abs_sdl_path}")

for png_file in sorted(png_files):
# Extract caption from filename (remove extension)
caption = os.path.splitext(png_file)[0].replace("-", " ").replace("_", " ")

# If output_directory is specified, copy the image there
if abs_output_dir and os.path.exists(abs_output_dir):
import shutil
# Since we're in the sdl_path directory, png_file is in current dir
src_path = png_file
# Create unique filename with function name to avoid collisions
dest_filename = f"{func_lower}_{png_file}"
dest_path = os.path.join(abs_output_dir, dest_filename)
print(f"Copying {src_path} to {dest_path}")
shutil.copy2(src_path, dest_path)
# Use only the filename (no path) for markdown reference
images.append((dest_filename, caption))
else:
# Fallback: use relative path from original working directory
abs_img_path = os.path.join(abs_sdl_path, png_file)
rel_path = os.path.relpath(abs_img_path, original_dir)
images.append((rel_path, caption))

os.chdir(original_dir)
except Exception as e:
# If OpenGEODE fails, just continue
if 'original_dir' in locals():
os.chdir(original_dir)
pass

return images

# Generate images for all SDL functions
func_images = {}
for func in sdl_funcs:
images = generate_sdl_images(func)
if images:
func_images[func.name] = images

%>

This section describes the behaviour of software components implemented in SDL.

The behaviour of each SDL function is documented using state machine diagrams generated from the SDL implementation.

% if not sdl_funcs:
*No SDL functions found in the ${target_partition_name} partition.*
% else:
## SDL Functions

The following functions are implemented in SDL and their behaviour is documented below:

% for func in sdl_funcs:
${"###"} ${func.name}

**Description:** ${func.comment if func.comment else "No description available."}

% if func.name in func_images and func_images[func.name]:
**Behavioural Diagrams:**

The following diagrams illustrate the behaviour of the ${func.name} function:

% for (img_path, caption) in func_images[func.name]:
![${func.name}](${img_path} "${caption}")

% endfor
% else:
*No SDL diagrams available for this function. The function may not have SDL source files in the expected location, or OpenGEODE image generation was not successful.*
% endif

% endfor
% endif
Loading