From 95c60d22c28238c716c91558e883f43754e96191 Mon Sep 17 00:00:00 2001 From: wolandscat Date: Wed, 4 Sep 2024 16:00:19 -0600 Subject: [PATCH] Add OPT copy script generator to adlc --- apps/adlc/src/main/application.e | 20 +- apps/adlc/src/main/options_processor.e | 34 ++- apps/adlc/src/main/templates_closure_copy.e | 204 ++++++++++++++++++ apps/adlc/src/main/templates_missing_coding.e | 1 - .../messages/compiled/adl_messages_db.e | 6 +- .../messages/compiled/adl_messages_ids.e | 4 + .../messages/source/app_adlc_ui_messages.txt | 7 + .../src/library/arch_lib_archetype.e | 26 +++ .../src/library/arch_lib_template.e | 12 +- 9 files changed, 303 insertions(+), 11 deletions(-) create mode 100644 apps/adlc/src/main/templates_closure_copy.e diff --git a/apps/adlc/src/main/application.e b/apps/adlc/src/main/application.e index b62abe39d..5ac77d8a1 100755 --- a/apps/adlc/src/main/application.e +++ b/apps/adlc/src/main/application.e @@ -15,6 +15,7 @@ note adlc [-q] -b [-f ] --report [-o ] adlc [-q] -b --inject_term_bindings -i adlc [-q] -b --export_term_bindings + adlc [-q] -b --gen_opts_copy_script --target_repo --output OPTIONS: Options should be prefixed with: '-' or '/' @@ -226,7 +227,10 @@ feature -- Commands elseif opts.report then generate_library_reports extract_templates_missing_coding - + + elseif opts.gen_opts_copy_script then + generate_opts_copy_script + elseif opts.inject_term_bindings then inject_term_bindings @@ -342,6 +346,20 @@ feature -- Commands end end + generate_opts_copy_script + -- generate a script to copy valid OPTs and the archetype reachable by direct reference from + -- their use_reference statements + local + action: TEMPLATES_CLOSURE_COPY + do + if opts.write_to_file_system and then attached opts.copy_opts_target_repo as repo and then attached opts.output_dir as att_op_dir then + create action.make (att_op_dir, current_library_name, repo, agent report_std_out, agent report_std_err, agent :BOOLEAN do Result := error_reported end) + action.execute + else + report_std_err (get_msg ({ADL_MESSAGES_IDS}.ec_output_directory_required_err, <<>>)) + end + end + clean_term_bindings -- export all term bindings into one files per terminology namespace -- Each file is a CSV file of the form diff --git a/apps/adlc/src/main/options_processor.e b/apps/adlc/src/main/options_processor.e index 46f37849a..56fa305cc 100755 --- a/apps/adlc/src/main/options_processor.e +++ b/apps/adlc/src/main/options_processor.e @@ -65,6 +65,7 @@ feature -- Definitions Result.extend (create {ARGUMENT_SWITCH}.make (export_switch, get_text (ec_export_switch_desc), False, False)) Result.extend (create {ARGUMENT_SWITCH}.make (export_term_bindings_switch, get_text (ec_export_term_bindings_desc), False, False)) Result.extend (create {ARGUMENT_SWITCH}.make (clean_term_bindings_switch, get_text (ec_clean_term_bindings_desc), False, False)) + Result.extend (create {ARGUMENT_SWITCH}.make (gen_opts_copy_script_switch, get_text (ec_gen_opts_copy_script_desc), True, False)) -- switches with arguments Result.extend (create {ARGUMENT_VALUE_SWITCH}.make (cfg_switch, get_text (ec_cfg_switch_desc), True, False, cfg_switch_arg_name, get_text (ec_cfg_switch_arg_desc), False)) @@ -77,6 +78,8 @@ feature -- Definitions Result.extend (create {ARGUMENT_VALUE_SWITCH}.make (input_file_switch, get_text (ec_input_file_switch_desc), False, False, input_file_switch_arg_name, get_text (ec_input_file_switch_arg_desc), False)) Result.extend (create {ARGUMENT_VALUE_SWITCH}.make (inject_term_bindings_switch, get_text (ec_term_bindings_switch_desc), False, False, inject_term_bindings_switch_arg, get_text (ec_term_bindings_switch_arg_desc), False)) + Result.extend (create {ARGUMENT_VALUE_SWITCH}.make (opts_copy_target_repo_switch, get_text (ec_opts_copy_target_repo_switch_desc), True, False, opts_copy_target_repo_switch_arg, get_text (ec_opts_copy_target_repo_switch_arg_desc), False)) + -- valid command line configurations end @@ -157,7 +160,8 @@ feature -- Definitions switch_of_name (cfg_switch), switch_of_name (library_switch), switch_of_name (format_switch), - switch_of_name (report_switch), switch_of_name (output_dir_switch)>>, False)) + switch_of_name (report_switch), + switch_of_name (output_dir_switch)>>, False)) -- INJECT Terminology bindings -- adlc [--quiet] [--cfg ] --library --inject_term_bindings --input_file @@ -165,6 +169,16 @@ feature -- Definitions switch_of_name (cfg_switch), switch_of_name (library_switch), switch_of_name (inject_term_bindings_switch), switch_of_name (input_file_switch)>>, False)) + + -- GENERATE OPTS COPY SCRIPT + -- adlc [--quiet] [--cfg ] --library --gen_opts_copy_script --target_repo [--output ] + Result.extend (create {ARGUMENT_GROUP}.make (<< switch_of_name (quiet_switch), + switch_of_name (cfg_switch), + switch_of_name (library_switch), + switch_of_name (gen_opts_copy_script_switch), + switch_of_name (opts_copy_target_repo_switch), + switch_of_name (output_dir_switch)>>, False)) + end quiet_switch: STRING = "q|quiet" @@ -187,6 +201,10 @@ feature -- Definitions report_switch: STRING = "r|report" export_switch: STRING = "x|export" + gen_opts_copy_script_switch: STRING = "gen_opts_copy_script" + opts_copy_target_repo_switch: STRING = "target_repo" + opts_copy_target_repo_switch_arg: STRING = "repo name" + export_term_bindings_switch: STRING = "export_term_bindings" clean_term_bindings_switch: STRING = "clean_term_bindings" @@ -258,6 +276,8 @@ feature {NONE} -- Initialization export_term_bindings := has_option (export_term_bindings_switch) clean_term_bindings := has_option (clean_term_bindings_switch) inject_term_bindings := has_option (inject_term_bindings_switch) + + gen_opts_copy_script := has_option (gen_opts_copy_script_switch) end end @@ -352,6 +372,16 @@ feature -- Access end end + copy_opts_target_repo: detachable STRING + -- target repo for gen copy OPTs script operation + require + is_successful: is_successful + once + if has_option (gen_opts_copy_script_switch) and then attached option_of_name (opts_copy_target_repo_switch) as opt and then opt.has_value then + Result := opt.value + end + end + feature -- Status Report is_verbose: BOOLEAN @@ -386,6 +416,8 @@ feature -- Status Report clean_term_bindings: BOOLEAN + gen_opts_copy_script: BOOLEAN + feature {NONE} -- Usage copyright: STRING = "Copyright (c) 2012- openEHR International" diff --git a/apps/adlc/src/main/templates_closure_copy.e b/apps/adlc/src/main/templates_closure_copy.e new file mode 100644 index 000000000..3987daf18 --- /dev/null +++ b/apps/adlc/src/main/templates_closure_copy.e @@ -0,0 +1,204 @@ +note + component: "openEHR ADL Tools" + description :"Extract missing LOINC codes and missing value-sets for all templates" + keywords: "ADL, archetype, compiler, command line" + author: "Thomas Beale " + support: "http://www.openehr.org/issues/browse/AWB" + copyright: "Copyright (c) 2024- Graphite Health " + license: "Apache 2.0 License " + +class + TEMPLATES_CLOSURE_COPY + +inherit + CLI_COMMAND + rename + make as make_cli + end + +create + make + +feature -- Initialization + + make (an_output_dir, a_source_repo, a_target_repo: STRING; report_std_out_agt, report_std_err_agt: PROCEDURE [ANY, TUPLE[STRING]]; an_error_reported_agt: FUNCTION[ANY, TUPLE[], BOOLEAN]) + do + make_cli (report_std_out_agt, report_std_err_agt, an_error_reported_agt) + + source_repo := a_source_repo + + target_repo := a_target_repo + + output_dir := an_output_dir + if not file_system.is_absolute_pathname (output_dir) then + output_dir := file_system.pathname (file_system.current_working_directory, output_dir) + end + file_system.recursive_create_directory (output_dir) + if not file_system.directory_exists (output_dir) then + report_std_err (get_msg ({ADL_MESSAGES_IDS}.ec_invalid_output_directory, <>)) + end + end + +feature -- Commands + + execute + -- export all term bindings into one files per terminology namespace + -- Each file is a CSV file of the form + -- archetype_id, archetype_node_id, binding_value + local + out_file: KI_TEXT_OUTPUT_FILE + output_filename, tgt_path, tgt_dirname, str: STRING + do + report_std_out ("--------- Generating templates closure copy script " + output_dir + "---------") + + current_library.do_for_all_templates (agent tpl_get_archetype_closure) + + output_filename := file_system.pathname (output_dir, "template_copy_script.sh") + out_file := file_system.new_output_file (output_filename) + + out_file.open_write + + -- build script + create str.make_empty + str.append ("#!/bin/bash%N") + str.append ("if [ ! -d " + target_repo + " ]; then%N") + str.append (" echo %"target repo " + target_repo + " not found; exiting%"%N") + str.append (" exit 1%N") + str.append ("fi%N") + + across path_map as paths_csr loop + tgt_path := paths_csr.item + tgt_dirname := file_system.dirname (tgt_path) + + -- don't overwrite existing + str.append ("if [ ! -f " + tgt_path + " ]; then%N") + + --output a mkdir -p command to make sure target directory exists + str.append (" mkdir -p " + tgt_dirname + " && ") + + -- output a copy command of form 'cp source target' + str.append (" cp " + paths_csr.key.to_string_8 + " " + tgt_path + "%N") + str.append ("fi%N") + end + + -- replace local OS dir sep character with Unix dir separator + if {OPERATING_ENVIRONMENT}.directory_separator /= {PATH}.unix_separator then + str.replace_substring_all ({OPERATING_ENVIRONMENT}.directory_separator.out, {PATH}.unix_separator.out) + end + + out_file.put_string (str) + + out_file.close + end + +feature {NONE} -- Implementation + + output_dir: STRING + + source_repo: STRING + -- name of source repository + + target_repo: STRING + -- name of target repository + + path_map: STRING_TABLE[STRING] + -- table of target path keyed by source path + attribute + create Result.make(0) + end + + arch_list: ARRAYED_LIST[STRING] + -- list of archetypes processed so far + attribute + create Result.make(0) + Result.compare_objects + end + + tpl_get_archetype_closure (aci: ARCH_LIB_TEMPLATE) + do + if aci.is_valid then +debug ("adlc-tpl") + report_std_out ("--------- template " + aci.id.as_string + "---------") +end + add_lineage (aci) + end + end + + add_supplier_closure (ala: ARCH_LIB_AUTHORED_ARCHETYPE) + do +debug ("adlc-tpl") + report_std_out (indent + "add_supplier_closure - target " + ala.id.as_string) + inc_indent +end + across ala.suppliers_index as car_csr loop + if attached {ARCH_LIB_AUTHORED_ARCHETYPE} car_csr.item as supp_ala then + add_lineage (supp_ala) + elseif attached {ARCH_LIB_TEMPLATE_OVERLAY} car_csr.item as ovl and then attached {ARCH_LIB_AUTHORED_ARCHETYPE} ovl.specialisation_parent as supp_ala then + add_lineage (supp_ala) + end + end +debug ("adlc-tpl") + dec_indent +end + end + + add_lineage (ala: ARCH_LIB_AUTHORED_ARCHETYPE) + do + if not arch_list.has (ala.id.as_string) then +debug ("adlc-tpl") + inc_indent + report_std_out (indent + "add_lineage - target " + ala.id.as_string) +end + add_path_map_entry (ala.file_mgr.source_file_path) + arch_list.extend (ala.id.as_string) + add_supplier_closure (ala) + + if ala.is_specialised then + across ala.ancestors as ancs_csr loop + if attached {ARCH_LIB_AUTHORED_ARCHETYPE} ancs_csr.item as spec_parent then +debug ("adlc-tpl") + report_std_out (indent + "add_lineage - ancestor " + spec_parent.id.as_string) +end + add_path_map_entry (spec_parent.file_mgr.source_file_path) + arch_list.extend (spec_parent.id.as_string) + add_supplier_closure (spec_parent) + end + end + end +debug ("adlc-tpl") + dec_indent +end + end + end + + add_path_map_entry (a_src_path: STRING) + local + pos: INTEGER + tail_path: STRING + do + pos := a_src_path.substring_index (source_repo, 1) + if pos > 0 then + -- generate a relative path below the repo level + tail_path := a_src_path.substring (pos + source_repo.count, a_src_path.count) + path_map.put (target_repo + tail_path, source_repo + tail_path) + else + report_std_err (get_msg ({ADL_MESSAGES_IDS}.ec_source_path_not_in_source_repo, <>)) + end + end + + indent: STRING + attribute + create Result.make(0) + end + + inc_indent + do + indent.append (" ") + end + + dec_indent + do + indent.remove_tail (4) + end + +end diff --git a/apps/adlc/src/main/templates_missing_coding.e b/apps/adlc/src/main/templates_missing_coding.e index 3a2770178..e4d974e47 100644 --- a/apps/adlc/src/main/templates_missing_coding.e +++ b/apps/adlc/src/main/templates_missing_coding.e @@ -55,7 +55,6 @@ feature -- Commands out_file := file_system.new_output_file (output_filename) out_file.open_write - -- out_file.put_string (row_str) conv := fac.smart_serialization conv.set_pretty_printing diff --git a/apps/resources/messages/compiled/adl_messages_db.e b/apps/resources/messages/compiled/adl_messages_db.e index d3772c224..3f5432a63 100755 --- a/apps/resources/messages/compiled/adl_messages_db.e +++ b/apps/resources/messages/compiled/adl_messages_db.e @@ -24,7 +24,7 @@ feature -- Initialisation make do - create message_table.make (978) + create message_table.make (982) message_table.put ("Terminology initialisation failed; reason: $1", ec_terminology_init_failed) message_table.put ("Using ADL version $1 for output serialisation", ec_adl_version_warning) message_table.put ("Validation level STRICT", ec_validation_strict) @@ -303,6 +303,7 @@ feature -- Initialisation message_table.put ("generate reports", ec_report_switch_desc) message_table.put ("export archetype term bindings", ec_export_term_bindings_desc) message_table.put ("remove mis-matched archetype term bindings", ec_clean_term_bindings_desc) + message_table.put ("generate OPTs copy script", ec_gen_opts_copy_script_desc) message_table.put ("display reference model in user-friendly format", ec_display_rm_switch_desc) message_table.put ("reference model name", ec_display_rm_switch_arg_desc) message_table.put ("export reference models in all available formats", ec_export_rms_switch_desc) @@ -319,6 +320,8 @@ feature -- Initialisation message_table.put (".cfg file path", ec_cfg_switch_arg_desc) message_table.put ("library to use", ec_library_switch_desc) message_table.put ("library name", ec_library_switch_arg_desc) + message_table.put ("target repo to write to", ec_opts_copy_target_repo_switch_desc) + message_table.put ("repo name", ec_opts_copy_target_repo_switch_arg_desc) message_table.put ("id_pattern", ec_id_pattern_arg_name) message_table.put ("archetype id regex", ec_id_pattern_arg_description) message_table.put ("regex string", ec_id_pattern_arg_type) @@ -347,6 +350,7 @@ feature -- Initialisation message_table.put ("-----------------------------------------------------%N", ec_archs_list_text_end) message_table.put ("External tool $1 not found on local system; repository operations limited to local access.%N(Recommendation on Windows: install Git for any platform from https://git-scm.com/)", ec_repository_tool_unavailable) message_table.put ("For missing external tools, see Help menu > External tools", ec_external_tools_help_text) + message_table.put ("Source path $1 is not in source repo $2", ec_source_path_not_in_source_repo) message_table.put ("Not implemented in this release", ec_to_be_implemented) message_table.put ("Copying file $1 to $2, backing up original to $3", ec_copy_file_with_backup) message_table.put ("Display", ec_display_in_active_tab) diff --git a/apps/resources/messages/compiled/adl_messages_ids.e b/apps/resources/messages/compiled/adl_messages_ids.e index 4469d8c0b..fea601f47 100755 --- a/apps/resources/messages/compiled/adl_messages_ids.e +++ b/apps/resources/messages/compiled/adl_messages_ids.e @@ -288,6 +288,7 @@ feature -- Definitions ec_report_switch_desc: STRING = "report_switch_desc" ec_export_term_bindings_desc: STRING = "export_term_bindings_desc" ec_clean_term_bindings_desc: STRING = "clean_term_bindings_desc" + ec_gen_opts_copy_script_desc: STRING = "gen_opts_copy_script_desc" ec_display_rm_switch_desc: STRING = "display_rm_switch_desc" ec_display_rm_switch_arg_desc: STRING = "display_rm_switch_arg_desc" ec_export_rms_switch_desc: STRING = "export_rms_switch_desc" @@ -304,6 +305,8 @@ feature -- Definitions ec_cfg_switch_arg_desc: STRING = "cfg_switch_arg_desc" ec_library_switch_desc: STRING = "library_switch_desc" ec_library_switch_arg_desc: STRING = "library_switch_arg_desc" + ec_opts_copy_target_repo_switch_desc: STRING = "opts_copy_target_repo_switch_desc" + ec_opts_copy_target_repo_switch_arg_desc: STRING = "opts_copy_target_repo_switch_arg_desc" ec_id_pattern_arg_name: STRING = "id_pattern_arg_name" ec_id_pattern_arg_description: STRING = "id_pattern_arg_description" ec_id_pattern_arg_type: STRING = "id_pattern_arg_type" @@ -332,6 +335,7 @@ feature -- Definitions ec_archs_list_text_end: STRING = "archs_list_text_end" ec_repository_tool_unavailable: STRING = "repository_tool_unavailable" ec_external_tools_help_text: STRING = "external_tools_help_text" + ec_source_path_not_in_source_repo: STRING = "source_path_not_in_source_repo" ec_to_be_implemented: STRING = "to_be_implemented" ec_copy_file_with_backup: STRING = "copy_file_with_backup" ec_display_in_active_tab: STRING = "display_in_active_tab" diff --git a/apps/resources/messages/source/app_adlc_ui_messages.txt b/apps/resources/messages/source/app_adlc_ui_messages.txt index f5724e430..56aba1070 100755 --- a/apps/resources/messages/source/app_adlc_ui_messages.txt +++ b/apps/resources/messages/source/app_adlc_ui_messages.txt @@ -35,6 +35,7 @@ templates = < ["report_switch_desc"] = <"generate reports"> ["export_term_bindings_desc"] = <"export archetype term bindings"> ["clean_term_bindings_desc"] = <"remove mis-matched archetype term bindings"> + ["gen_opts_copy_script_desc"] = <"generate OPTs copy script"> -- command line options with arguments ["display_rm_switch_desc"] = <"display reference model in user-friendly format"> @@ -61,6 +62,9 @@ templates = < ["library_switch_desc"] = <"library to use"> ["library_switch_arg_desc"] = <"library name"> + ["opts_copy_target_repo_switch_desc"] = <"target repo to write to"> + ["opts_copy_target_repo_switch_arg_desc"] = <"repo name"> + -- non-switched command-line options ["id_pattern_arg_name"] = <"id_pattern"> ["id_pattern_arg_description"] = <"archetype id regex"> @@ -97,6 +101,9 @@ templates = < ["repository_tool_unavailable"] = <"External tool $1 not found on local system; repository operations limited to local access.%N(Recommendation on Windows: install Git for any platform from https://git-scm.com/)"> ["external_tools_help_text"] = <"For missing external tools, see Help menu > External tools"> + + + ["source_path_not_in_source_repo"] = <"Source path $1 is not in source repo $2"> > > diff --git a/components/archetype_repository/src/library/arch_lib_archetype.e b/components/archetype_repository/src/library/arch_lib_archetype.e index 9e199ae00..9e155e9fc 100755 --- a/components/archetype_repository/src/library/arch_lib_archetype.e +++ b/components/archetype_repository/src/library/arch_lib_archetype.e @@ -357,6 +357,32 @@ feature -- Relationships att_ala.has_ancestor (an_arch_id)) end + ancestor_ids: LIST[STRING] + -- List of specialisation parents; empty if none + local + csr: ARCH_LIB_ARCHETYPE + do + create {ARRAYED_LIST[STRING]} Result.make(0) + + from csr := specialisation_parent until csr = Void loop + Result.extend (csr.id.as_string) + csr := csr.specialisation_parent + end + end + + ancestors: LIST[ARCH_LIB_ARCHETYPE] + -- List of specialisation parents; empty if none + local + csr: ARCH_LIB_ARCHETYPE + do + create {ARRAYED_LIST[ARCH_LIB_ARCHETYPE]} Result.make(0) + + from csr := specialisation_parent until csr = Void loop + Result.extend (csr) + csr := csr.specialisation_parent + end + end + is_specialised: BOOLEAN -- True if this archetype is a specialisation of another archetype do diff --git a/components/archetype_repository/src/library/arch_lib_template.e b/components/archetype_repository/src/library/arch_lib_template.e index 418a7a3a4..156030215 100755 --- a/components/archetype_repository/src/library/arch_lib_template.e +++ b/components/archetype_repository/src/library/arch_lib_template.e @@ -95,6 +95,11 @@ feature -- Artefacts Result := template_compiled (True) end + overlays: ARRAYED_LIST [ARCH_LIB_TEMPLATE_OVERLAY] + attribute + create Result.make (0) + end + feature -- Visualisation select_archetype (differential_view, editing_enabled: BOOLEAN): ARCHETYPE @@ -267,12 +272,5 @@ feature {NONE} -- Output create Result.make_dt (Void) end -feature {NONE} -- Implementation - - overlays: ARRAYED_LIST [ARCH_LIB_TEMPLATE_OVERLAY] - attribute - create Result.make (0) - end - end