|
| 1 | +<% |
| 2 | +## Data Initialization |
| 3 | +# Get all functions |
| 4 | + |
| 5 | +funcs = [] |
| 6 | +def get_function_children(func): |
| 7 | + result = [] |
| 8 | + if func.nested_functions: |
| 9 | + for nested in func.nested_functions: |
| 10 | + result.append(nested) |
| 11 | + result.extend(get_function_children(nested)) |
| 12 | + return result |
| 13 | + |
| 14 | +for func in interface_view.functions: |
| 15 | + funcs.append(func) |
| 16 | + funcs.extend(get_function_children(func)) |
| 17 | + |
| 18 | +funcs.sort(key=lambda f: f.name.lower()) |
| 19 | + |
| 20 | +# Get functions deployed to the target partition |
| 21 | +target_partition_name = values["TARGET"] |
| 22 | + |
| 23 | +deployed_funcs = [] |
| 24 | +target_partition = None |
| 25 | +for node in deployment_view.nodes: |
| 26 | + for partition in node.partitions: |
| 27 | + if partition.name == target_partition_name: |
| 28 | + target_partition = partition |
| 29 | + |
| 30 | +deployed_func_names = [f.name for f in target_partition.functions] |
| 31 | +for fun in funcs: |
| 32 | + if fun.name in deployed_func_names: |
| 33 | + deployed_funcs.append(fun) |
| 34 | + |
| 35 | +# Only leaf functions are deployed, so a correction for parents must be applied |
| 36 | +for func in funcs: |
| 37 | + if func.nested_functions: |
| 38 | + for nested in func.nested_functions: |
| 39 | + if nested in deployed_funcs and not func in deployed_funcs: |
| 40 | + deployed_funcs.append(func) |
| 41 | + deployed_func_names.append(func.name) |
| 42 | + |
| 43 | +# Filter SDL functions only |
| 44 | +import os |
| 45 | +import subprocess |
| 46 | +import glob |
| 47 | + |
| 48 | +sdl_funcs = [func for func in deployed_funcs if func.language and func.language.value == "SDL"] |
| 49 | + |
| 50 | +# Generate SDL behavior diagrams using OpenGEODE |
| 51 | +def generate_sdl_images(func): |
| 52 | + """Generate SDL images for a function using OpenGEODE""" |
| 53 | + func_lower = func.name.lower() |
| 54 | + images = [] |
| 55 | + |
| 56 | + # Try different path patterns for SDL/src directory |
| 57 | + # Pattern 1: work/{function}/SDL/src |
| 58 | + sdl_path_1 = f"work/{func_lower}/SDL/src" |
| 59 | + # Pattern 2: work/{function}/implem/{implementation}/SDL/src |
| 60 | + sdl_path_2_pattern = f"work/{func_lower}/implem/*/SDL/src" |
| 61 | + |
| 62 | + sdl_paths = [] |
| 63 | + if os.path.exists(sdl_path_1): |
| 64 | + sdl_paths.append(sdl_path_1) |
| 65 | + else: |
| 66 | + # Check for implementation-specific paths |
| 67 | + matching_paths = glob.glob(sdl_path_2_pattern) |
| 68 | + sdl_paths.extend(matching_paths) |
| 69 | + |
| 70 | + for sdl_path in sdl_paths: |
| 71 | + if not os.path.exists(sdl_path): |
| 72 | + continue |
| 73 | + |
| 74 | + # Find the system_structure.pr and function.pr files |
| 75 | + system_pr = os.path.join(sdl_path, "system_structure.pr") |
| 76 | + func_pr = os.path.join(sdl_path, f"{func_lower}.pr") |
| 77 | + |
| 78 | + if not os.path.exists(system_pr) or not os.path.exists(func_pr): |
| 79 | + continue |
| 80 | + |
| 81 | + # Generate images using OpenGEODE |
| 82 | + try: |
| 83 | + # Change to SDL/src directory to run opengeode |
| 84 | + original_dir = os.getcwd() |
| 85 | + |
| 86 | + # Get absolute path to output directory before changing directories |
| 87 | + abs_output_dir = None |
| 88 | + if output_directory: |
| 89 | + abs_output_dir = os.path.abspath(output_directory) |
| 90 | + print(f"Output directory (absolute): {abs_output_dir}") |
| 91 | + print(f"Output directory exists: {os.path.exists(abs_output_dir)}") |
| 92 | + |
| 93 | + # Get absolute path to SDL directory |
| 94 | + abs_sdl_path = os.path.abspath(sdl_path) |
| 95 | + |
| 96 | + os.chdir(sdl_path) |
| 97 | + |
| 98 | + # Run OpenGEODE to generate PNG images |
| 99 | + subprocess.run( |
| 100 | + ["opengeode", "--png", "system_structure.pr", f"{func_lower}.pr"], |
| 101 | + check=False, |
| 102 | + capture_output=True |
| 103 | + ) |
| 104 | + |
| 105 | + # Find all generated PNG files and move them to output directory |
| 106 | + png_files = glob.glob("*.png") |
| 107 | + print(f"Found {len(png_files)} PNG files in {abs_sdl_path}") |
| 108 | + |
| 109 | + for png_file in sorted(png_files): |
| 110 | + # Extract caption from filename (remove extension) |
| 111 | + caption = os.path.splitext(png_file)[0].replace("-", " ").replace("_", " ") |
| 112 | + |
| 113 | + # If output_directory is specified, copy the image there |
| 114 | + if abs_output_dir and os.path.exists(abs_output_dir): |
| 115 | + import shutil |
| 116 | + # Since we're in the sdl_path directory, png_file is in current dir |
| 117 | + src_path = png_file |
| 118 | + # Create unique filename with function name to avoid collisions |
| 119 | + dest_filename = f"{func_lower}_{png_file}" |
| 120 | + dest_path = os.path.join(abs_output_dir, dest_filename) |
| 121 | + print(f"Copying {src_path} to {dest_path}") |
| 122 | + shutil.copy2(src_path, dest_path) |
| 123 | + # Use only the filename (no path) for markdown reference |
| 124 | + images.append((dest_filename, caption)) |
| 125 | + else: |
| 126 | + # Fallback: use relative path from original working directory |
| 127 | + abs_img_path = os.path.join(abs_sdl_path, png_file) |
| 128 | + rel_path = os.path.relpath(abs_img_path, original_dir) |
| 129 | + images.append((rel_path, caption)) |
| 130 | + |
| 131 | + os.chdir(original_dir) |
| 132 | + except Exception as e: |
| 133 | + # If OpenGEODE fails, just continue |
| 134 | + if 'original_dir' in locals(): |
| 135 | + os.chdir(original_dir) |
| 136 | + pass |
| 137 | + |
| 138 | + return images |
| 139 | + |
| 140 | +# Generate images for all SDL functions |
| 141 | +func_images = {} |
| 142 | +for func in sdl_funcs: |
| 143 | + images = generate_sdl_images(func) |
| 144 | + if images: |
| 145 | + func_images[func.name] = images |
| 146 | + |
| 147 | +%> |
| 148 | + |
| 149 | +This section describes the behaviour of software components implemented in SDL. |
| 150 | + |
| 151 | +The behaviour of each SDL function is documented using state machine diagrams generated from the SDL implementation. |
| 152 | + |
| 153 | +% if not sdl_funcs: |
| 154 | +*No SDL functions found in the ${target_partition_name} partition.* |
| 155 | +% else: |
| 156 | +## SDL Functions |
| 157 | + |
| 158 | +The following functions are implemented in SDL and their behaviour is documented below: |
| 159 | + |
| 160 | +% for func in sdl_funcs: |
| 161 | +${"###"} ${func.name} |
| 162 | + |
| 163 | +**Description:** ${func.comment if func.comment else "No description available."} |
| 164 | + |
| 165 | +% if func.name in func_images and func_images[func.name]: |
| 166 | +**Behavioural Diagrams:** |
| 167 | + |
| 168 | +The following diagrams illustrate the behaviour of the ${func.name} function: |
| 169 | + |
| 170 | +% for (img_path, caption) in func_images[func.name]: |
| 171 | + |
| 172 | + |
| 173 | +% endfor |
| 174 | +% else: |
| 175 | +*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.* |
| 176 | +% endif |
| 177 | + |
| 178 | +% endfor |
| 179 | +% endif |
0 commit comments