#!/usr/bin/env bash set -u SCRIPT_DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")" && pwd )" PACKAGE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" DEFAULT_SOURCE="$PACKAGE_ROOT/baseline/smoke_s2_binary_recording_from_s01.marte" DEFAULT_OUTPUT_ROOT="$PACKAGE_ROOT/configurations/generated/S03H1/from_patcher" EXPECTED_SOURCE_SHA256="8ecc8ba55e46e9f6fb8f304404d4070ff4c2ea5b9c783a69113bc08b457859d1" EXPECTED_TEST_SHA256="d037561b32760fbd0e2aec9f1eefc5efda27b1918eca4742c89092a8a2f7e92e" EXPECTED_DIAGNOSTIC_SHA256="cd999ff249452298d650a22c8fe5b0b03bf48c0735f4630befdec8209cbb13a3" fail() { code="$1" shift printf "S03_H1_BUILD_STATUS=FAIL\n" >&2 printf "S03_H1_BUILD_ERROR=%s\n" "$*" >&2 exit "$code" } usage() { printf "Uso:\n" >&2 printf " %s TEST|DIAGNOSTIC\n" "$0" >&2 printf " %s TEST|DIAGNOSTIC\n" "$0" >&2 } case "$#" in 1) SOURCE_CONFIG="$DEFAULT_SOURCE" MODE="$1" case "$MODE" in TEST) OUTPUT_CONFIG="$DEFAULT_OUTPUT_ROOT/smoke_s03h1_execution_profiles_test_from_s02.marte" ;; DIAGNOSTIC) OUTPUT_CONFIG="$DEFAULT_OUTPUT_ROOT/smoke_s03h1_execution_profiles_diagnostic_from_s02.marte" ;; *) usage fail 20 "UNKNOWN_MODE:$MODE" ;; esac ;; 3) SOURCE_CONFIG="$1" OUTPUT_CONFIG="$2" MODE="$3" ;; *) usage fail 20 "INVALID_ARGUMENT_COUNT:$#" ;; esac case "$MODE" in TEST) EXPECTED_OUTPUT_SHA256="$EXPECTED_TEST_SHA256" DISPLAY_CLASS="GAMDataSource" ;; DIAGNOSTIC) EXPECTED_OUTPUT_SHA256="$EXPECTED_DIAGNOSTIC_SHA256" DISPLAY_CLASS="LoggerDataSource" ;; *) usage fail 20 "UNKNOWN_MODE:$MODE" ;; esac if [ ! -f "$SOURCE_CONFIG" ]; then fail 21 "SOURCE_NOT_FOUND:$SOURCE_CONFIG" fi SOURCE_SHA256="$(sha256sum -- "$SOURCE_CONFIG" | awk '{print $1}')" printf "MODE=%s\n" "$MODE" printf "SOURCE_CONFIG=%s\n" "$SOURCE_CONFIG" printf "EXPECTED_SOURCE_SHA256=%s\n" "$EXPECTED_SOURCE_SHA256" printf "ACTUAL_SOURCE_SHA256=%s\n" "$SOURCE_SHA256" if [ "$SOURCE_SHA256" != "$EXPECTED_SOURCE_SHA256" ]; then fail 22 "SOURCE_HASH_MISMATCH:$SOURCE_SHA256" fi OUTPUT_DIR="$(dirname "$OUTPUT_CONFIG")" if ! mkdir -p -- "$OUTPUT_DIR"; then fail 23 "OUTPUT_DIRECTORY_CREATE_FAILED:$OUTPUT_DIR" fi if [ -e "$OUTPUT_CONFIG" ] && [ ! -f "$OUTPUT_CONFIG" ]; then fail 24 "OUTPUT_EXISTS_NOT_REGULAR_FILE:$OUTPUT_CONFIG" fi TEMP_CONFIG="$(mktemp "$OUTPUT_DIR/.s03h1_candidate_XXXXXX.marte")" || fail 25 "TEMPORARY_FILE_CREATE_FAILED:$OUTPUT_DIR" cleanup() { rm -f -- "$TEMP_CONFIG" } trap cleanup EXIT HUP INT TERM PYTHONHASHSEED=0 python3 - \ "$SOURCE_CONFIG" \ "$TEMP_CONFIG" \ "$MODE" \ "$DISPLAY_CLASS" <<'PY_S03H1_PATCHER' import sys from pathlib import Path source = Path(sys.argv[1]) destination = Path(sys.argv[2]) mode = sys.argv[3] display_class = sys.argv[4] text = source.read_text(encoding="utf-8") def require_count(haystack, needle, expected, label): observed = haystack.count(needle) print(f"{label}_COUNT={observed}") if observed != expected: raise RuntimeError( f"{label}_COUNT_EXPECTED_{expected}_OBSERVED_{observed}" ) def replace_once(haystack, old, new, label): require_count(haystack, old, 1, label) return haystack.replace(old, new, 1) for forbidden in ( "+SentinelProducer =", "SentinelScalarA", "SentinelScalarB", "SentinelVector", "s03_output.bin", ): if forbidden in text: raise RuntimeError("SOURCE_ALREADY_CONTAINS_S03_CONTENT:" + forbidden) if mode not in {"TEST", "DIAGNOSTIC"}: raise RuntimeError("UNKNOWN_MODE:" + mode) if display_class not in {"GAMDataSource", "LoggerDataSource"}: raise RuntimeError("UNKNOWN_DISPLAY_CLASS:" + display_class) constant_gam = """ +SentinelProducer = { Class = ConstantGAM OutputSignals = { SentinelScalarA = { DataSource = DDB1 Type = uint32 NumberOfElements = 1 Default = 324508639 } SentinelScalarB = { DataSource = DDB1 Type = uint32 NumberOfElements = 1 Default = 610839776 } SentinelVector = { DataSource = DDB1 Type = uint32 NumberOfDimensions = 1 NumberOfElements = 3 Default = {16909060 286397204 555885348} } } } """ gam_display = f""" +GAMDisplay = {{ Class = IOGAM InputSignals = {{ Counter = {{ DataSource = DDB1 Type = uint32 }} Time = {{ DataSource = DDB1 Type = uint32 }} State1_Thread1_CycleTime = {{ Alias = State1.Thread1_CycleTime DataSource = Timings Type = uint32 }} SentinelScalarA = {{ DataSource = DDB1 Type = uint32 NumberOfElements = 1 }} SentinelScalarB = {{ DataSource = DDB1 Type = uint32 NumberOfElements = 1 }} SentinelVector = {{ DataSource = DDB1 Type = uint32 NumberOfDimensions = 1 NumberOfElements = 3 }} }} OutputSignals = {{ Counter = {{ DataSource = Display Type = uint32 }} Time = {{ DataSource = Display Type = uint32 }} State1_Thread1_CycleTime = {{ DataSource = Display Type = uint32 }} SentinelScalarA = {{ DataSource = Display Type = uint32 NumberOfElements = 1 }} SentinelScalarB = {{ DataSource = Display Type = uint32 NumberOfElements = 1 }} SentinelVector = {{ DataSource = Display Type = uint32 NumberOfDimensions = 1 NumberOfElements = 3 }} }} }} """ sentinel_signals = """ SentinelScalarA = { DataSource = DDB1 Type = uint32 NumberOfElements = 1 } SentinelScalarB = { DataSource = DDB1 Type = uint32 NumberOfElements = 1 } SentinelVector = { DataSource = DDB1 Type = uint32 NumberOfDimensions = 1 NumberOfElements = 3 } """ filewriter_signals = """ SentinelScalarA = { Type = uint32 NumberOfElements = 1 } SentinelScalarB = { Type = uint32 NumberOfElements = 1 } SentinelVector = { Type = uint32 NumberOfDimensions = 1 NumberOfElements = 3 } """ require_count(text, " +GAMDisplay = {\n", 1, "GAMDISPLAY_START_ANCHOR") require_count(text, " +IOGAM_Writer = {\n", 1, "IOGAM_WRITER_START_ANCHOR") display_start = text.index(" +GAMDisplay = {\n") writer_start = text.index(" +IOGAM_Writer = {\n", display_start) text = text[:display_start] + constant_gam + gam_display + text[writer_start:] writer_start = text.index(" +IOGAM_Writer = {\n") writer_end = text.index(" }\n +Data = {\n", writer_start) writer = text[writer_start:writer_end] writer = replace_once( writer, """ State1_Thread1_CycleTime = { Alias = State1.Thread1_CycleTime DataSource = Timings Type = uint32 } } OutputSignals = { """, """ State1_Thread1_CycleTime = { Alias = State1.Thread1_CycleTime DataSource = Timings Type = uint32 } """ + sentinel_signals + """ } OutputSignals = { """, "WRITER_INPUT_ANCHOR", ) writer_output_signals = sentinel_signals.replace( "DataSource = DDB1", "DataSource = FileWriter" ) writer = replace_once( writer, """ State1_Thread1_CycleTime = { DataSource = FileWriter Type = uint32 } } } """, """ State1_Thread1_CycleTime = { DataSource = FileWriter Type = uint32 } """ + writer_output_signals + """ } } """, "WRITER_OUTPUT_ANCHOR", ) text = text[:writer_start] + writer + text[writer_end:] text = replace_once( text, """ +Display = { Class = LoggerDataSource } """, f""" +Display = {{ Class = {display_class} }} """, "DISPLAY_DATASOURCE_ANCHOR", ) filewriter_start = text.index(" +FileWriter = {\n") filewriter_end = text.index(" }\n +States = {\n", filewriter_start) filewriter = text[filewriter_start:filewriter_end] filewriter = replace_once( filewriter, ' Filename = "__MARTE_RUN_DIR__/s02_output.bin"\n', ' Filename = "__MARTE_RUN_DIR__/s03_output.bin"\n', "OUTPUT_FILENAME_ANCHOR", ) filewriter = replace_once( filewriter, """ State1_Thread1_CycleTime = { Type = uint32 } } } """, """ State1_Thread1_CycleTime = { Type = uint32 } """ + filewriter_signals + """ } } """, "FILEWRITER_SIGNAL_ANCHOR", ) text = text[:filewriter_start] + filewriter + text[filewriter_end:] text = replace_once( text, "Functions = {GAMTimer GAMDisplay IOGAM_Writer}", "Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}", "THREAD_FUNCTION_LIST_ANCHOR", ) text = text.rstrip("\n") + "\n" checks = { "SENTINEL_PRODUCER": text.count("+SentinelProducer ="), "CONSTANT_GAM_CLASS": text.count("Class = ConstantGAM"), "GAMDISPLAY_OBJECT": text.count("+GAMDisplay ="), "SENTINEL_SCALAR_A_DECLARATIONS": text.count("SentinelScalarA ="), "SENTINEL_SCALAR_B_DECLARATIONS": text.count("SentinelScalarB ="), "SENTINEL_VECTOR_DECLARATIONS": text.count("SentinelVector ="), "VECTOR_DIMENSION_DECLARATIONS": text.count("NumberOfDimensions = 1"), "VECTOR_CARDINALITY_DECLARATIONS": text.count("NumberOfElements = 3"), "S03_OUTPUT_FILENAME": text.count("__MARTE_RUN_DIR__/s03_output.bin"), "S02_OUTPUT_FILENAME": text.count("s02_output.bin"), "RUN_DIR_PLACEHOLDER": text.count("__MARTE_RUN_DIR__"), "FILEWRITER_CLASS": text.count("Class = FileDataSource::FileWriter"), "THREAD_FUNCTION_LIST": text.count( "Functions = {GAMTimer SentinelProducer GAMDisplay IOGAM_Writer}" ), "DISPLAY_DATASOURCE_BLOCK": text.count( f" +Display = {{\n Class = {display_class}\n }}\n" ), } expected = { "SENTINEL_PRODUCER": 1, "CONSTANT_GAM_CLASS": 1, "GAMDISPLAY_OBJECT": 1, "SENTINEL_SCALAR_A_DECLARATIONS": 6, "SENTINEL_SCALAR_B_DECLARATIONS": 6, "SENTINEL_VECTOR_DECLARATIONS": 6, "VECTOR_DIMENSION_DECLARATIONS": 6, "VECTOR_CARDINALITY_DECLARATIONS": 6, "S03_OUTPUT_FILENAME": 1, "S02_OUTPUT_FILENAME": 0, "RUN_DIR_PLACEHOLDER": 1, "FILEWRITER_CLASS": 1, "THREAD_FUNCTION_LIST": 1, "DISPLAY_DATASOURCE_BLOCK": 1, } for name in sorted(checks): print(f"{name}_COUNT={checks[name]}") if checks != expected: raise RuntimeError(f"STRUCTURAL_CHECK_MISMATCH:{checks!r}") destination.write_text(text, encoding="utf-8") print("TRANSFORM_STATUS=PASS") print("STRUCTURAL_CHECK_STATUS=PASS") PY_S03H1_PATCHER PYTHON_RC=$? if [ "$PYTHON_RC" -ne 0 ]; then fail 26 "TRANSFORM_FAILED_RC_$PYTHON_RC" fi GENERATED_SHA256="$(sha256sum -- "$TEMP_CONFIG" | awk '{print $1}')" printf "GENERATED_SHA256=%s\n" "$GENERATED_SHA256" printf "EXPECTED_OUTPUT_SHA256=%s\n" "$EXPECTED_OUTPUT_SHA256" if [ "$GENERATED_SHA256" != "$EXPECTED_OUTPUT_SHA256" ]; then fail 27 "OUTPUT_HASH_MISMATCH:$GENERATED_SHA256" fi if [ -f "$OUTPUT_CONFIG" ]; then if cmp -s -- "$TEMP_CONFIG" "$OUTPUT_CONFIG"; then printf "S03_H1_BUILD_STATUS=ALREADY_VALID\n" printf "MODE=%s\n" "$MODE" printf "OUTPUT_CONFIG=%s\n" "$OUTPUT_CONFIG" printf "OUTPUT_SHA256=%s\n" "$GENERATED_SHA256" exit 0 fi fail 28 "OUTPUT_EXISTS_BUT_DIFFERS:$OUTPUT_CONFIG" fi chmod 0644 "$TEMP_CONFIG" || fail 29 "OUTPUT_CHMOD_FAILED:$TEMP_CONFIG" if ! mv -- "$TEMP_CONFIG" "$OUTPUT_CONFIG"; then fail 30 "ATOMIC_PUBLISH_FAILED:$OUTPUT_CONFIG" fi trap - EXIT HUP INT TERM printf "S03_H1_BUILD_STATUS=CREATED\n" printf "MODE=%s\n" "$MODE" printf "OUTPUT_CONFIG=%s\n" "$OUTPUT_CONFIG" printf "OUTPUT_SHA256=%s\n" "$GENERATED_SHA256"