From 840509a6e4f5e514bd6f87c1607d3d373e8c5838 Mon Sep 17 00:00:00 2001 From: "(Holloway) Chew, Kean Ho" Date: Wed, 19 Jun 2024 14:47:19 +0800 Subject: [PATCH] root: refactored msi packager to match the latest implementation The MSI packager was intentionally left out due to its complications and issue listed in: https://github.com/wixtoolset/issues/issues/7896 Now that the overall package job and release job are stabilized, we can proceed to refactor MSI packager now. Hence, let's do this. This patch refactors MSI packager to match the latest implementation in root repository. Co-authored-by: Shuralyov, Jean Co-authored-by: Galyna, Cory Co-authored-by: (Holloway) Chew, Kean Ho Signed-off-by: (Holloway) Chew, Kean Ho --- CONFIG.toml | 294 ++++++- automataCI/_package-msi_unix-any.sh | 727 ++++++++++++--- automataCI/_package-msi_windows-any.ps1 | 824 +++++++++++++++--- automataCI/ci.ps1 | 1 + automataCI/ci.sh | 1 + automataCI/package_unix-any.sh | 51 +- automataCI/package_windows-any.ps1 | 52 +- automataCI/services/compilers/msi.ps1 | 31 +- automataCI/services/compilers/msi.sh | 27 +- .../hestiaI18N/Get_Languages_List.sh.ps1 | 64 ++ ...ranslate-All-Components-Description.sh.ps1 | 92 ++ .../Translate-All-Components-Title.sh.ps1 | 92 ++ .../Translate-Already-Latest-Version.sh.ps1 | 91 ++ ...ranslate-Bin-Components-Description.sh.ps1 | 92 ++ .../Translate-Bin-Components-Title.sh.ps1 | 92 ++ ...slate-Config-Components-Description.sh.ps1 | 92 ++ .../Translate-Config-Components-Title.sh.ps1 | 92 ++ ...anslate-Docs-Components-Description.sh.ps1 | 92 ++ .../Translate-Docs-Components-Title.sh.ps1 | 92 ++ ...ranslate-Lib-Components-Description.sh.ps1 | 92 ++ .../Translate-Lib-Components-Title.sh.ps1 | 92 ++ ...anslate-Main-Components-Description.sh.ps1 | 92 ++ .../Translate-Main-Components-Title.sh.ps1 | 92 ++ .../Translate-Only-Install-On-Windows.sh.ps1 | 209 +++++ automataCI/services/hestiaI18N/Vanilla.sh.ps1 | 82 ++ .../services/hestiaLOCALE/Get-LCID.sh.ps1 | 113 +++ .../services/hestiaLOCALE/Vanilla.sh.ps1 | 54 ++ .../i18n/_check-available-skipped.ps1 | 28 + .../services/i18n/_check-available-skipped.sh | 29 + .../services/i18n/_copy-exists-skipped.ps1 | 28 + .../services/i18n/_copy-exists-skipped.sh | 29 + automataCI/services/i18n/translations.ps1 | 2 + automataCI/services/i18n/translations.sh | 2 + src/.ci/_package-chocolatey_unix-any.sh | 1 + src/.ci/_package-chocolatey_windows-any.ps1 | 1 + src/.ci/_package-deb_unix-any.sh | 1 + src/.ci/_package-deb_windows-any.ps1 | 1 + src/.ci/_package-homebrew_unix-any.sh | 1 + src/.ci/_package-homebrew_windows-any.ps1 | 1 + src/.ci/_package-msi_unix-any.sh | 706 ++++----------- src/.ci/_package-msi_windows-any.ps1 | 793 ++++------------- src/.ci/_x-package-msi_windows-any.ps1 | 12 + .../{msi-banner_en.jpg => msi-banner.jpg} | Bin src/icons/msi-banner_zh-hans.jpg | Bin 7233 -> 0 bytes .../{msi-dialog_en.jpg => msi-dialog.jpg} | Bin src/icons/msi-dialog_zh-hans.jpg | Bin 34547 -> 0 bytes 46 files changed, 3951 insertions(+), 1409 deletions(-) create mode 100755 automataCI/services/hestiaI18N/Get_Languages_List.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-All-Components-Description.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-All-Components-Title.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Already-Latest-Version.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Bin-Components-Description.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Bin-Components-Title.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Config-Components-Description.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Config-Components-Title.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Docs-Components-Description.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Docs-Components-Title.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Lib-Components-Description.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Lib-Components-Title.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Main-Components-Description.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Main-Components-Title.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Translate-Only-Install-On-Windows.sh.ps1 create mode 100755 automataCI/services/hestiaI18N/Vanilla.sh.ps1 create mode 100755 automataCI/services/hestiaLOCALE/Get-LCID.sh.ps1 create mode 100755 automataCI/services/hestiaLOCALE/Vanilla.sh.ps1 create mode 100644 automataCI/services/i18n/_check-available-skipped.ps1 create mode 100644 automataCI/services/i18n/_check-available-skipped.sh create mode 100644 automataCI/services/i18n/_copy-exists-skipped.ps1 create mode 100644 automataCI/services/i18n/_copy-exists-skipped.sh create mode 100644 src/.ci/_x-package-msi_windows-any.ps1 rename src/icons/{msi-banner_en.jpg => msi-banner.jpg} (100%) delete mode 100644 src/icons/msi-banner_zh-hans.jpg rename src/icons/{msi-dialog_en.jpg => msi-dialog.jpg} (100%) delete mode 100644 src/icons/msi-dialog_zh-hans.jpg diff --git a/CONFIG.toml b/CONFIG.toml index d481829..99b2e6a 100644 --- a/CONFIG.toml +++ b/CONFIG.toml @@ -859,14 +859,6 @@ PROJECT_RELEASE_ARCHIVE = 'enabled' PROJECT_RELEASE_IPK = 'enabled' -# PROJECT_RELEASE_MSI -# The flag to package msi pipeline. -# -# To enable : fill in some string (e.g. 'enabled') -# To disable: leave it empty ('') -PROJECT_RELEASE_IPK = 'enabled' - - ############################# @@ -1381,6 +1373,292 @@ PROJECT_HOMEBREW_REPO_BRANCH = 'main' +########################### +# DISTRIBUTION - MSI # +########################### +# PROJECT_MSI_INSTALL_DIRECTORY +# Defines the primary directory installation value for installer execute +# sequences ('InstallExecuteSequence'). +# +# This field also acts as the flag for enabling or disabling the homebrew +# pipeline. +# +# To enable it: set the value as 'INSTALLDIR' +# To disable it: set it empty. +# +# Default is: 'INSTALLDIR' (enabled) +PROJECT_MSI_INSTALL_DIRECTORY = 'INSTALLDIR' + + +# PROJECT_MSI_ARP_INSTALL_LOCATION +# Defines the CustomAction's ID for installer execute sequences +# ('InstallExecuteSequence'). Unless absolute required, this value is best +# leave it as 'ARPINSTALLLOCATION' unchanged. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'ARPINSTALLLOCATION' +PROJECT_MSI_ARP_INSTALL_LOCATION = 'ARPINSTALLLOCATION' + + +# PROJECT_MSI_COMPRESSED_MODE +# Defines the compress mode for the installer. It STRICTLY accepts lowercase +# 'yes' or 'no' only. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'yes' +PROJECT_MSI_COMPRESSED_MODE = 'yes' + + +# PROJECT_MSI_INSTALLER_VERSION_UNIX +# Defines the MSI installer version for unix workspace (where WiX is not used). +# +# This field CANNOT BE LEFT EMPTY and is only for unix packagers. +# +# Default is: '400' (Windows Installer 4.0 - included in Vista) +PROJECT_MSI_INSTALLER_VERSION_UNIX = '400' + + +# PROJECT_MSI_INSTALLER_VERSION_WINDOWS +# Defines the MSI installer version for windows workspace (where WiX is used). +# +# This field CANNOT BE LEFT EMPTY and is only for windows packagers. +# +# Default is: '500' (WiX4) +PROJECT_MSI_INSTALLER_VERSION_WINDOWS = '500' + + +# PROJECT_MSI_CODEPAGE +# Defines the charset of the installer. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: '65001' (UTF-8) +PROJECT_MSI_CODEPAGE = '65001' + + +# PROJECT_MSI_INSTALLER_SCOPE +# Defines the installer scope. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'perMachine' +PROJECT_MSI_INSTALLER_SCOPE = 'perMachine' + + +# PROJECT_MSI_REGISTRY_NAME +# Defines the name of the registry. Unless aboslute needed, it's best to leave +# this as it is. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'InstallLocation' +PROJECT_MSI_REGISTRY_NAME = 'InstallLocation' + + +# PROJECT_MSI_REGISTRY_KEY +# Defines the location of the registry. +# +# This field is shared for both unix and windows packagers. +# +# If this field is left empty, AutomataCI shall generate a default version +# using the following pattern: +# 'Software\${PROJECT_SCOPE}\InstalledProducts\${PROJECT_SKU_TITLECASE}' +# +# Default is: '' (leave it automated) +PROJECT_MSI_REGISTRY_KEY = '' + + +# PROJECT_MSI_FEATURES_ID +# The ID for the entire installer's feature list. This the the root of the list +# consisting of main feature list, optional features list, and etc. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'FeaturesAll' +PROJECT_MSI_FEATURES_ID = 'FeaturesAll' + + +# PROJECT_MSI_MAIN_FEATURE_ID +# The ID for the compulsory features list. This consists of all the MUST HAVE +# components to be installed at the client side. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'FeaturesMain' +PROJECT_MSI_MAIN_FEATURE_ID = 'FeaturesMain' + + +# PROJECT_MSI_REGISTRIES_ID +# The ID for the compulsory main registries component. This handles the main +# registeries internal implementations. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'RegValInstallLocation_comp' +PROJECT_MSI_REGISTRIES_ID = 'RegValInstallLocation_comp' + + +# PROJECT_MSI_REGISTRIES_GUID +# The unique GUID for the compulsory main registries component. Its value is +# similar to a UUID type. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# When in doubt, use asterisk instead ('*'). +# +# Default is: '*' +PROJECT_MSI_REGISTRIES_GUID = '*' + + +# PROJECT_MSI_BIN_FEATURE_ID +# The ID for the executables features list. When available, the executables will +# be in this component. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'FeaturesBin' +PROJECT_MSI_BIN_FEATURE_ID = 'FeaturesBin' + + +# PROJECT_MSI_BIN_COMPONENT_ID +# The ID for the executables component. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'ComponentBin' +PROJECT_MSI_BIN_COMPONENT_ID = 'ComponentBin' + + +# PROJECT_MSI_BIN_COMPONENT_GUID +# The unique GUID for the executables component. Its value is similar to an UUID +# type. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# When in doubt, use asterisk instead ('*'). +# +# Default is: '*' +PROJECT_MSI_BIN_COMPONENT_GUID = '*' + + +# PROJECT_MSI_CONFIG_FEATURE_ID +# The ID for the config files features list. When available, the config files +# will be in this component. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'FeaturesBin' +PROJECT_MSI_CONFIG_FEATURE_ID = 'FeaturesConfig' + + +# PROJECT_MSI_CONFIG_COMPONENT_ID +# The ID for the config files component. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'ComponentConfig' +PROJECT_MSI_CONFIG_COMPONENT_ID = 'ComponentConfig' + + +# PROJECT_MSI_CONFIG_COMPONENT_GUID +# The unique GUID for the config files component. Its value is similar to +# an UUID type. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# When in doubt, use asterisk instead ('*'). +# +# Default is: '*' +PROJECT_MSI_CONFIG_COMPONENT_GUID = '*' + + +# PROJECT_MSI_LIB_FEATURE_ID +# The ID for the libraries features list. When available, the libraries will +# be in this component. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'FeaturesLib' +PROJECT_MSI_LIB_FEATURE_ID = 'FeaturesLib' + + +# PROJECT_MSI_LIB_COMPONENT_ID +# The ID for the libraries component. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'ComponentLib' +PROJECT_MSI_LIB_COMPONENT_ID = 'ComponentLib' + + +# PROJECT_MSI_LIB_COMPONENT_GUID +# The unique GUID for the libraries component. Its value is similar to an UUID +# type. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# When in doubt, use asterisk instead ('*') +# +# Default is: '*' +PROJECT_MSI_LIB_COMPONENT_GUID = '*' + + +# PROJECT_MSI_DOCS_FEATURE_ID +# The ID for the documenations features list. When available, the documents will +# be in this component. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'FeaturesDocs' +PROJECT_MSI_DOCS_FEATURE_ID = 'FeaturesDocs' + + +# PROJECT_MSI_DOCS_COMPONENT_ID +# The ID for the documentations component. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# Default is: 'ComponentDocs' +PROJECT_MSI_DOCS_COMPONENT_ID = 'ComponentDocs' + + +# PROJECT_MSI_DOCS_COMPONENT_GUID +# The unique GUID for the documentations component. Its value is similar to an +# UUID type. +# +# This field CANNOT BE LEFT EMPTY and is shared for both unix and windows +# packagers. +# +# When in doubt, use asterisk instead ('*'). +# +# Default is: '*' +PROJECT_MSI_LIB_COMPONENT_GUID = '*' + + + + ########################## # DISTRIBUTION - RPM # ########################## diff --git a/automataCI/_package-msi_unix-any.sh b/automataCI/_package-msi_unix-any.sh index f6b4363..cab9f60 100644 --- a/automataCI/_package-msi_unix-any.sh +++ b/automataCI/_package-msi_unix-any.sh @@ -12,9 +12,11 @@ # the License. . "${LIBS_AUTOMATACI}/services/io/os.sh" . "${LIBS_AUTOMATACI}/services/io/fs.sh" -. "${LIBS_AUTOMATACI}/services/io/sync.sh" +. "${LIBS_AUTOMATACI}/services/io/strings.sh" . "${LIBS_AUTOMATACI}/services/i18n/translations.sh" . "${LIBS_AUTOMATACI}/services/compilers/msi.sh" +. "${LIBS_AUTOMATACI}/services/hestiaLOCALE/Vanilla.sh.ps1" +. "${LIBS_AUTOMATACI}/services/hestiaI18N/Vanilla.sh.ps1" @@ -28,44 +30,633 @@ fi -SUBROUTINE_Package_MSI() { - # parse input - __line="$1" - - __target="${__line%%|*}" - __line="${__line#*|}" +PACKAGE_Seal_MSI() { + __workspace="$1" + __output_directory="$2" - __dest="${__line%%|*}" - __line="${__line#*|}" - __log="${__line%%|*}" + # obtain buildable target architecture + _target_arch="$(FS_Get_File "$__workspace")" + I18N_Check "MSI: '$_target_arch'" + case "$_target_arch" in + amd64) + ;; + *) + I18N_Check_Incompatible_Skipped + return 0 # wixl does not support other arch aside amd64 + ;; + esac - __subject="${__log##*/}" - __subject="${__subject%.*}" - __subject="${__subject#*msi-wxs_}" - __arch="${__subject##*windows-}" - __arch="${__arch%%_*}" + # validate icon.ico available + __icon_filepath="${__workspace}/icon.ico" + I18N_Check "$__icon_filepath" + FS_Is_File "$__icon_filepath" + if [ $? -ne 0 ]; then + I18N_Check_Failed + return 1 + fi - # execute - I18N_Package "$__subject" - MSI_Compile "$__target" "$__arch" &> "$__log" + # validate msi-banner.jpg is available + __banner_filepath="${__workspace}/msi-banner.jpg" + I18N_Check "$__banner_filepath" + FS_Is_File "$__banner_filepath" if [ $? -ne 0 ]; then - I18N_Package_Failed + I18N_Check_Failed return 1 fi - __target="$(FS_Extension_Replace "$__target" ".wxs" ".msi")" - I18N_Export "$__subject" - if [ ! -f "$__target" ]; then - I18N_Export_Missing "$__subject" + + # validate msi-dialog.jpg is available + __dialog_filepath="${__workspace}/msi-dialog.jpg" + I18N_Check "$__dialog_filepath" + FS_Is_File "$__dialog_filepath" + if [ $? -ne 0 ]; then + I18N_Check_Failed return 1 fi - FS_Copy_File "$__target" "${__dest}/${__target##*/}" &> "$__log" + + # create wxs scripts by languages + __old_IFS="$IFS" + while IFS="" read -r __language || [ -n "$__language" ]; do + # formulate destination path + __dest="${__workspace}/${PROJECT_SKU}_${__language}_windows-${_target_arch}.wxs" + I18N_Check_Availability "$__dest" + FS_Is_File "$__dest" + if [ $? -eq 0 ]; then + I18N_Check_Available_Skipped + continue ## user supplied - skipping + fi + + + # creating wxs headers + I18N_Create "$__dest" + FS_Write_File "$__dest" "\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CMDLINE_${PROJECT_MSI_INSTALL_DIRECTORY} + + + + CMDLINE_${PROJECT_MSI_INSTALL_DIRECTORY} + + + + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + __source="${__workspace}/bin" + FS_Is_Directory_Empty "$__source" + if [ $? -ne 0 ]; then + ## write the opener + FS_Append_File "$__dest" "\ + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + ## loop through each file and create the following + for __file in "${__source}/"*; do + FS_Is_File "$__file" + if [ $? -ne 0 ]; then + continue + fi + + FS_Append_File "$__dest" "\ + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + done + + ## write the closure + FS_Append_File "$__dest" "\ + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + fi + + __source="${__workspace}/config" + FS_Is_Directory_Empty "$__source" + if [ $? -ne 0 ]; then + ## write the opener + FS_Append_File "$__dest" "\ + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + ## loop through each file and create the following + for __file in "${__source}/"*; do + FS_Is_File "$__file" + if [ $? -ne 0 ]; then + continue + fi + + FS_Append_File "$__dest" "\ + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + done + + ## write the closure + FS_Append_File "$__dest" "\ + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + fi + + __source="${__workspace}/lib" + FS_Is_Directory_Empty "$__source" + if [ $? -ne 0 ]; then + ## write the opener + FS_Append_File "$__dest" "\ + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + ## loop through each file and create the following + for __file in "${__source}/"*; do + FS_Is_File "$__file" + if [ $? -ne 0 ]; then + continue + fi + + FS_Append_File "$__dest" "\ + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + done + + ## write the closure + FS_Append_File "$__dest" "\ + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + fi + + __source="${__workspace}/docs" + FS_Is_Directory_Empty "$__source" + if [ $? -ne 0 ]; then + ## write the opener + FS_Append_File "$__dest" "\ + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + ## loop through each file and create the following + for __file in "${__source}/"*; do + FS_Is_File "$__file" + if [ $? -ne 0 ]; then + continue + fi + + FS_Append_File "$__dest" "\ + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + done + + ## write the closure + FS_Append_File "$__dest" "\ + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + fi + + + # close directory section + FS_Append_File "$__dest" "\ + + + + + + + + + + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + + # define all feature components + FS_Append_File "$__dest" "\ + + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + + # write bin feature list + FS_Is_Directory_Empty "${__workspace}/bin" + if [ $? -ne 0 ]; then + FS_Append_File "$__dest" "\ + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + fi + + + # write config feature list + FS_Is_Directory_Empty "${__workspace}/config" + if [ $? -ne 0 ]; then + FS_Append_File "$__dest" "\ + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + fi + + + # write lib feature list + FS_Is_Directory_Empty "${__workspace}/lib" + if [ $? -ne 0 ]; then + FS_Append_File "$__dest" "\ + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + fi + + + # write docs feature list + FS_Is_Directory_Empty "${__workspace}/docs" + if [ $? -ne 0 ]; then + FS_Append_File "$__dest" "\ + + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + fi + + + # close feature list + FS_Append_File "$__dest" "\ + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + + + # conclude the wxs write-up + FS_Append_File "$__dest" "\ + + +" + if [ $? -ne 0 ]; then + I18N_Create_Failed + return 1 + fi + done < + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + $__source = "${__workspace}\bin" + $___process = FS-Is-Directory-Empty "${__source}" + if ($___process -ne 0) { + $___process = FS-Append-File "${__dest}" @" + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + $__source = "${__workspace}\config" + $___process = FS-Is-Directory-Empty "${__source}" + if ($___process -ne 0) { + $___process = FS-Append-File "${__dest}" @" + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + $__source = "${__workspace}\lib" + $___process = FS-Is-Directory-Empty "${__source}" + if ($___process -ne 0) { + $___process = FS-Append-File "${__dest}" @" + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + # Close directory tree definitions + $___process = FS-Append-File "${__dest}" @" + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + + ## begin assemble bin/* files + $__source = "${__workspace}\bin" + $___process = FS-Is-Directory-Empty "${__source}" + if ($___process -ne 0) { + ## write the opener + $___process = FS-Append-File "${__dest}" @" + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + ## loop through each file and create the following + foreach ($__file in (Get-ChildItem "${__source}" -File)) { + $___process = FS-Append-File "${__dest}" @" + + +"@ + } + + ## write the closure + $___process = FS-Append-File "${__dest}" @" + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + ## begin assemble config/* files + $__source = "${__workspace}\config" + $___process = FS-Is-Directory-Empty "${__source}" + if ($___process -ne 0) { + ## write the opener + $___process = FS-Append-File "${__dest}" @" + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + ## loop through each file and create the following + foreach ($__file in (Get-ChildItem "${__source}" -File)) { + $___process = FS-Append-File "${__dest}" @" + + +"@ + } + + ## write the closure + $___process = FS-Append-File "${__dest}" @" + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + ## begin assemble lib/* files + $__source = "${__workspace}\lib" + $___process = FS-Is-Directory-Empty "${__source}" + if ($___process -ne 0) { + ## write the opener + $___process = FS-Append-File "${__dest}" @" + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + ## loop through each file and create the following + foreach ($__file in (Get-ChildItem "${__source}" -File)) { + $___process = FS-Append-File "${__dest}" @" + + +"@ + } + + ## write the closure + $___process = FS-Append-File "${__dest}" @" + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + ## begin assemble docs/* files + $__source = "${__workspace}\docs" + $___process = FS-Is-Directory-Empty "${__source}" + if ($___process -ne 0) { + ## write the opener + $___process = FS-Append-File "${__dest}" @" + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + ## loop through each file and create the following + foreach ($__file in (Get-ChildItem "${__source}" -File)) { + $___process = FS-Append-File "${__dest}" @" + + +"@ + } + + ## write the closure + $___process = FS-Append-File "${__dest}" @" + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + # create registry key + $___process = FS-Append-File "${__dest}" @" + + + + + + + + + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + + # Define all feature components + $___process = FS-Append-File "${__dest}" @" + + + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + + # write bin feature list + $___process = FS-Is-Directory-Empty "${__workspace}\bin" + if ($___process -ne 0) { + $___process = FS-Append-File "${__dest}" @" + + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + # write config feature list + $___process = FS-Is-Directory-Empty "${__workspace}\config" + if ($___process -ne 0) { + $___process = FS-Append-File "${__dest}" @" + + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + # write lib feature list + $___process = FS-Is-Directory-Empty "${__workspace}\lib" + if ($___process -ne 0) { + $___process = FS-Append-File "${__dest}" @" + + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + # write docs feature list + $___process = FS-Is-Directory-Empty "${__workspace}\docs" + if ($___process -ne 0) { + $___process = FS-Append-File "${__dest}" @" + + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + # close feature list + $___process = FS-Append-File "${__dest}" @" + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + + # Add standard UI support + $___process = FS-Append-File "${__dest}" @" + + + + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + + + # conclude the wxs write-up + $___process = FS-Append-File "${__dest}" @" + + + +"@ + if ($___process -ne 0) { + $null = I18N-Create-Failed + return 1 + } + } + + + # begin packages compilation + Get-ChildItem -Path "${__workspace}" -File ` + | Where-Object { ($_.Name -like "*.wxs") } ` + | ForEach-Object { $__line = $_.FullName + $null = I18N-Package "${__line}" + $___process = MSI-Compile "${__line}" "${_target_arch}" + if ($___process -ne 0) { + $null = I18N-Package-Failed + return 1 + } + } + + + # begin export packages + Get-ChildItem -Path "${__workspace}" -File ` + | Where-Object { ($_.Name -like "*.msi") } ` + | ForEach-Object { $__line = $_.FullName + $__dest = "${__output_directory}\$(FS-Get-File "${__line}")" + + $null = I18N-Export "${__dest}" + $___process = MSI-Compile "${__line}" "${__dest}" + if ($___process -ne 0) { + $null = I18N-Export-Failed + return 1 + } + } - $__subject = Split-Path -Leaf -Path "${__log}" - $__subject = FS-Extension-Remove "${__subject}" "*" - $__subject = $__subject -replace "^msi-wxs_", "" - $__arch = $__subject -replace '.*windows-','' - $__arch = $__arch -replace '_.*','' + # report status + return 0 +} - $__lang = $__subject -split "_" - $__lang = $__lang[2] + + + +function PACKAGE-Sort-MSI { + param( + [string]$__workspace + ) # execute - $null = I18N-Package "${__subject}" - $($___process = MSI-Compile "${__target}" "${__arch}" "${__lang}") *> "${__log}" + $__source = "${__workspace}\any" + $null = I18N-Check "${__source}" + $___process = FS-Is-Directory "${__source}" if ($___process -ne 0) { - $null = I18N-Package-Failed - return 1 + return 0 # nothing to sort - report status } - $__target = FS-Extension-Replace "${__target}" ".wxs" ".msi" - $null = I18N-Export "${__target}" - if (-not (Test-Path "${__target}")) { - $null = I18N-Export-Missing "${__subject}" - return 1 + :arch_loop foreach ($_arch in (Get-ChildItem -Path "${__workspace}" -Directory)) { + $_arch = $_arch.FullName + $___process = FS-Is-Directory "${_arch}" + if ($___process -ne 0) { + continue arch_loop + } + + if ("$(FS-Get-File "${_arch}")" -eq "any") { + continue arch_loop + } + + # begin merging from any + Get-ChildItem -Path "${__workspace}\any" ` + | ForEach-Object { $__target = $_.FullName + $___process = FS-Is-File "${__target}" + if ($___process -eq 0) { + $__dest = FS-Get-File "${__target}" + $__dest = "${_arch}\${__dest}" + $null = I18N-Copy "${__target}" "${__dest}" + $___process = FS-Is-File "${__dest}" + if ($___process -eq 0) { + $null = I18N-Copy-Exists-Skipped + continue # do not overwrite + } + + $___process = FS-Copy-File "${__target}" "${__dest}" + if ($___process -ne 0) { + $null = I18N-Copy-Failed + return 1 + } + + continue + } + + + # it's a directory, loop it + Get-ChildItem -Path "${__target}" ` + | ForEach-Object { $__file = $_.FullName + $___process = FS-Is-File "${__file}" + if ($___process -ne 0) { + continue + } + + $__dest = "$(FS-Get-File "${__file}")" + $__dest = "${_arch}\$(FS-Get-File "${__target}")\${__dest}" + $null = I18N-Copy "${__file}" "${__dest}" + $___process = FS-Is-File "${__dest}" + if ($___process -eq 0) { + $null = I18N-Copy-Exists-Skipped + continue # do not overwrite + } + + $___process = FS-Copy-File "${__target}" "${__dest}" + if ($___process -ne 0) { + $null = I18N-Copy-Failed + return 1 + } + } + } } - $___process = FS-Copy-File ` - "${__target}" ` - "${__dest}\$(Split-Path -Leaf -Path "${__target}")" + + # remove 'any' to prevent bad compilation + $___process = FS-Remove "${__workspace}/any" if ($___process -ne 0) { - $null = I18N-Export-Failed "${__subject}" + $null = I18N-Check-Failed return 1 } @@ -100,6 +786,7 @@ function PACKAGE-Run-MSI { $_target_filename = $__list[2] $_target_os = $__list[3] $_target_arch = $__list[4] + $_src = $__list[5] # validate input @@ -113,25 +800,12 @@ function PACKAGE-Run-MSI { # prepare workspace and required values $null = I18N-Create-Package "MSI" - $_src = "${_target_filename}_${env:PROJECT_VERSION}_${_target_os}-${_target_arch}" - $_src = "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_TEMP}\packagers-msi-${_src}" - $null = I18N-Remake "${_src}" - $___process = FS-Remake-Directory "${_src}" - if ($___process -ne 0) { - $null = I18N-Remake-Failed - return 1 - } - - $__control_directory = "${_src}\.automataCI" - $null = I18N-Remake "${__control_directory}" - $___process = FS-Remake-Directory "${__control_directory}" - if ($___process -ne 0) { - $null = I18N-Remake-Failed - return 1 - } - - $__parallel_control = "${__control_directory}\control-parallel.txt" - $null = FS-Remove-Silently "${__parallel_control}" + $_src = "${_src}\${_target_arch}" + $null = FS-Make-Directory "${_src}\bin" + $null = FS-Make-Directory "${_src}\config" + $null = FS-Make-Directory "${_src}\docs" + $null = FS-Make-Directory "${_src}\ext" + $null = FS-Make-Directory "${_src}\lib" # copy all complimentary files to the workspace @@ -162,54 +836,6 @@ function PACKAGE-Run-MSI { }} - # archive the assembled payload - foreach ($__recipe in (Get-ChildItem -Path "${_src}" -Filter *.wxs)) { - $___process = FS-Is-File "${__recipe}" - if ($___process -ne 0) { - continue - } - - - # register for packaging in parallel - $null = I18N-Sync-Register "${__recipe}" - $__log = Split-Path -Leaf -Path "${__recipe}" - $__log = FS-Extension-Remove "${__log}" "*" - $__log = "${__control_directory}\msi-wxs_${__log}.log" - $___process = FS-Append-File "${__parallel_control}" @" -${__recipe}|${_dest}|${__log} -"@ - if ($___process -ne 0) { - return 1 - } - } - - $null = I18N-Sync-Run - $___process = FS-Is-File "${__parallel_control}" - if ($___process -eq 0) { - $___process = SYNC-Exec-Parallel ` - ${function:SUBROUTINE-Package-MSI}.ToString() ` - "${__parallel_control}" ` - "${__control_directory}" ` - "$([System.Environment]::ProcessorCount)" - } else { - $null = I18N-Sync-Run-Skipped - $___process = 0 - } - - foreach ($__log in (Get-ChildItem -Path "${__control_directory}" -Filter *.log)) { - $null = I18N-Sync-Report-Log "${__log}" - foreach ($__line in (Get-Content "${__log}")) { - $null = I18N-Status-Print plain "${__line}" - } - $null = I18N-Newline - } - - # report status - if ($___process -ne 0) { - $null = I18N-Sync-Failed - return 1 - } - return 0 } diff --git a/automataCI/ci.ps1 b/automataCI/ci.ps1 index 5f06254..ec6f0e4 100644 --- a/automataCI/ci.ps1 +++ b/automataCI/ci.ps1 @@ -70,6 +70,7 @@ if (Test-Path ".\ci.ps1") { } ${env:LIBS_AUTOMATACI} = "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_AUTOMATA}" +${env:LIBS_HESTIA} = "${env:LIBS_AUTOMATACI}\services" diff --git a/automataCI/ci.sh b/automataCI/ci.sh index 7e68f21..0f2bfec 100644 --- a/automataCI/ci.sh +++ b/automataCI/ci.sh @@ -63,6 +63,7 @@ else fi export LIBS_AUTOMATACI="${PROJECT_PATH_ROOT}/${PROJECT_PATH_AUTOMATA}" +export LIBS_HESTIA="${LIBS_AUTOMATACI}/services" diff --git a/automataCI/package_unix-any.sh b/automataCI/package_unix-any.sh index 7e7a7c6..25b7382 100644 --- a/automataCI/package_unix-any.sh +++ b/automataCI/package_unix-any.sh @@ -67,7 +67,7 @@ if [ "$(STRINGS_Is_Empty "$PROJECT_HOMEBREW_URL")" -ne 0 ]; then HOMEBREW_WORKSPACE="packagers-homebrew-${PROJECT_SKU}" I18N_Setup "$HOMEBREW_WORKSPACE" HOMEBREW_WORKSPACE="${PROJECT_PATH_ROOT}/${PROJECT_PATH_TEMP}/${HOMEBREW_WORKSPACE}" - FS_Remake_Directory "${HOMEBREW_WORKSPACE}" + FS_Remake_Directory "$HOMEBREW_WORKSPACE" if [ $? -ne 0 ]; then I18N_Setup_Failed return 1 @@ -75,6 +75,23 @@ if [ "$(STRINGS_Is_Empty "$PROJECT_HOMEBREW_URL")" -ne 0 ]; then fi +if [ "$(STRINGS_Is_Empty "$PROJECT_MSI_INSTALL_DIRECTORY")" -ne 0 ]; then + MSI_WORKSPACE="packagers-msi-${PROJECT_SKU}" + I18N_Setup "$MSI_WORKSPACE" + MSI_WORKSPACE="${PROJECT_PATH_ROOT}/${PROJECT_PATH_TEMP}/${MSI_WORKSPACE}" + FS_Remake_Directory "$MSI_WORKSPACE" + if [ $? -ne 0 ]; then + I18N_Setup_Failed + return 1 + fi + + if [ $(STRINGS_Is_Empty "$PROJECT_MSI_REGISTRY_KEY") -eq 0 ]; then + PROJECT_MSI_REGISTRY_KEY="\ +Software\\\\${PROJECT_SCOPE}\\\\InstalledProducts\\\\${PROJECT_SKU_TITLECASE}" + fi +fi + + if [ "$(STRINGS_Is_Empty "$PROJECT_FLATPAK_URL")" -ne 0 ]; then FLATPAK_REPO="flatpak-repo" I18N_Setup "$FLATPAK_REPO" @@ -373,13 +390,13 @@ ${__common}|${__log}|PACKAGE_Run_LIB fi # NOTE: MSI only works in windows - if [ $(STRINGS_Is_Empty "$PROJECT_RELEASE_MSI") -ne 0 ]; then + if [ $(STRINGS_Is_Empty "$PROJECT_MSI_INSTALL_DIRECTORY") -ne 0 ]; then case "$TARGET_OS" in any|windows) __log="msi_${TARGET_FILENAME}_${TARGET_OS}-${TARGET_ARCH}.log" __log="${__log_directory}/${__log}" - FS_Append_File "$__serial_control" "\ -${__common}|${__log}|PACKAGE_Run_MSI + FS_Append_File "$__parallel_control" "\ +${__common}|${MSI_WORKSPACE}|${__log}|PACKAGE_Run_MSI " if [ $? -ne 0 ]; then return 1 @@ -467,6 +484,32 @@ if [ $(STRINGS_Is_Empty "$PROJECT_HOMEBREW_URL") -ne 0 ]; then fi +if [ "$(STRINGS_Is_Empty "$PROJECT_MSI_INSTALL_DIRECTORY")" -ne 0 ]; then + I18N_Newline + I18N_Newline + + # sort any arch into others + PACKAGE_Sort_MSI "$MSI_WORKSPACE" + if [ $? -ne 0 ];then + return 1 + fi + + # seal all MSI packages + for _candidate in "${MSI_WORKSPACE}/"*; do + FS_Is_Directory "$_candidate" + if [ $? -ne 0 ]; then + continue + fi + + I18N_Newline + PACKAGE_Seal_MSI "$_candidate" "${PROJECT_PATH_ROOT}/${PROJECT_PATH_PKG}" + if [ $? -ne 0 ];then + return 1 + fi + done +fi + + I18N_Sync_Run_Series FS_Is_File "$__serial_control" if [ $? -eq 0 ]; then diff --git a/automataCI/package_windows-any.ps1 b/automataCI/package_windows-any.ps1 index 05abb63..c22a48e 100644 --- a/automataCI/package_windows-any.ps1 +++ b/automataCI/package_windows-any.ps1 @@ -29,6 +29,7 @@ if (-not (Test-Path -Path $env:PROJECT_PATH_ROOT)) { . "${env:LIBS_AUTOMATACI}\_package-changelog_windows-any.ps1" . "${env:LIBS_AUTOMATACI}\_package-citation_windows-any.ps1" +. "${env:LIBS_AUTOMATACI}\_package-msi_windows-any.ps1" @@ -55,6 +56,25 @@ if ($(STRINGS-Is-Empty "${env:PROJECT_HOMEBREW_URL}") -ne 0) { } +if ($(STRINGS-Is-Empty "${env:PROJECT_MSI_INSTALL_DIRECTORY}") -ne 0) { + $MSI_WORKSPACE = "packagers-msi-${env:PROJECT_SKU}" + $null = I18N-Setup "${MSI_WORKSPACE}" + $MSI_WORKSPACE = "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_TEMP}\${MSI_WORKSPACE}" + $___process = FS-Remake-Directory "${MSI_WORKSPACE}" + if ($___process -ne 0) { + $null = I18N-Setup-Failed + return 1 + } + + + if ($(STRINGS-Is-Empty "${env:PROJECT_MSI_REGISTRY_KEY}") -eq 0) { + ${env:PROJECT_MSI_REGISTRY_KEY} = @" +Software\${env:PROJECT_SCOPE}\InstalledProducts\${env:PROJECT_SKU_TITLECASE} +"@ + } +} + + if ($(STRINGS-Is-Empty "${env:PROJECT_FLATPAK_URL}") -ne 0) { $FLATPAK_REPO = "flatpak-repo" $null = I18N-Setup "${FLATPAK_REPO}" @@ -165,7 +185,7 @@ function SUBROUTINE-Package { $null = . "${env:LIBS_AUTOMATACI}\_package-ipk_windows-any.ps1" $null = . "${env:LIBS_AUTOMATACI}\_package-lib_windows-any.ps1" $null = . "${env:LIBS_AUTOMATACI}\_package-msi_windows-any.ps1" - $null = . "${env:LIBS_AUTOMATACI}\_package-pdf_windows-any.ps1" + $null = . "${env:LIBS_AUTOMATACI}\_package-pypi_windows-any.ps1" $null = . "${env:LIBS_AUTOMATACI}\_package-rpm_windows-any.ps1" $null = . "${env:LIBS_AUTOMATACI}\_package-sourcing_windows-any.ps1" @@ -388,13 +408,13 @@ ${__common}|${__log}|PACKAGE-Run-LIB } # NOTE: MSI only works in windows - if ($(STRINGS-Is-Empty "${env:PROJECT_RELEASE_MSI}") -ne 0) { + if ($(STRINGS-Is-Empty "${env:PROJECT_MSI_INSTALL_DIRECTORY}") -ne 0) { switch ("${TARGET_OS}") { { $_ -in "any", "windows" } { $__log = "msi_${TARGET_FILENAME}_${TARGET_OS}-${TARGET_ARCH}.log" $__log = "${__log_directory}\${__log}" - $___process = FS-Append-File "${__serial_control}" @" -${__common}|${__log}|PACKAGE-Run-MSI + $___process = FS-Append-File "${__parallel_control}" @" +${__common}|${MSI_WORKSPACE}|${__log}|PACKAGE-Run-MSI "@ if ($___process -ne 0) { @@ -484,6 +504,30 @@ if ($(STRINGS-Is-Empty "${env:PROJECT_HOMEBREW_URL}") -ne 0) { } +if ($(STRINGS-Is-Empty "${env:PROJECT_MSI_INSTALL_DIRECTORY}") -ne 0) { + $null = I18N-Newline + $null = I18N-Newline + + + # sort 'any' arch into others + $___process = PACKAGE-Sort-MSI "${MSI_WORKSPACE}" + if ($___process -ne 0) { + return 1 + } + + # seal all MSI packages + Get-ChildItem -Path "${MSI_WORKSPACE}" -Directory ` + | ForEach-Object { $_candidate = $_.FullName + $null = I18N-Newline + $___process = PACKAGE-Seal-MSI "${_candidate}" ` + "${env:PROJEC_PATH_ROOT}\${env:PROJECT_PATH_PKG}" + if ($___process -ne 0) { + return 1 + } + } +} + + $null = I18N-Sync-Run-Series $___process = FS-Is-File "${__serial_control}" if ($___process -eq 0) { diff --git a/automataCI/services/compilers/msi.ps1 b/automataCI/services/compilers/msi.ps1 index 4b032a3..78abfee 100644 --- a/automataCI/services/compilers/msi.ps1 +++ b/automataCI/services/compilers/msi.ps1 @@ -1,4 +1,4 @@ -# Copyright 2023 (Holloway) Chew, Kean Ho +# Copyright 2023 (Holloway) Chew, Kean Ho # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of @@ -21,8 +21,7 @@ function MSI-Compile { param ( [string]$___target, - [string]$___arch, - [string]$___lang + [string]$___arch ) @@ -46,15 +45,10 @@ function MSI-Compile { return 1 } - if ($(STRINGS-Is-Empty "${___lang}") -eq 0) { - return 1 - } - # execute $___arguments = "build " ` + "-arch ${___arch} " ` - + "-culture ${___lang} " ` + "-out `"" + $(FS-Extension-Replace "${___target}" ".wxs" ".msi") + "`" " $___extensions = $(Split-Path -Parent -Path "${___target}") + "\ext" @@ -67,6 +61,7 @@ function MSI-Compile { $___arguments += "`"${___target}`" " $___process = OS-Exec "wix" "${___arguments}" + $null = Write-Host "DEBUG: cmd |wix ${___argments}" if ($___process -ne 0) { return 1 } @@ -79,6 +74,26 @@ function MSI-Compile { +function MSI-Get-Directory-Program-Files { + param( + [string]$___arch + ) + + + # execute + switch ("${___arch}") { + { $_ -in "amd64", "arm64" } { + return "ProgramFiles64Folder" + } { $_ -in "i386", "arm" } { + return "ProgramFilesFolder" + } default { + return "ProgramFiles6432Folder" + }} +} + + + + function MSI-Install-Silent() { param( [string]$___installer diff --git a/automataCI/services/compilers/msi.sh b/automataCI/services/compilers/msi.sh index b361a8d..bee865d 100644 --- a/automataCI/services/compilers/msi.sh +++ b/automataCI/services/compilers/msi.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright 2023 (Holloway) Chew, Kean Ho +# Copyright 2023 (Holloway) Chew, Kean Ho # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of @@ -58,6 +58,31 @@ MSI_Compile() { +MSI_Get_Directory_Program_Files() { + #___arch="$1" + + + # execute + case "$1" in + amd64|arm64) + printf -- "ProgramFiles64Folder" + ;; + i386|arm) + printf -- "ProgramFilesFolder" + ;; + *) + printf -- "" + ;; + esac + + + # report status + return 0 +} + + + + MSI_Install_Silent() { #___installer="$1" diff --git a/automataCI/services/hestiaI18N/Get_Languages_List.sh.ps1 b/automataCI/services/hestiaI18N/Get_Languages_List.sh.ps1 new file mode 100755 index 0000000..054add3 --- /dev/null +++ b/automataCI/services/hestiaI18N/Get_Languages_List.sh.ps1 @@ -0,0 +1,64 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Get-Languages-List { + return @( + "en", + "zh-hans" + ) +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Get_Languages_List() { + printf -- "%s" "\ +en +zh-hans +" +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-All-Components-Description.sh.ps1 b/automataCI/services/hestiaI18N/Translate-All-Components-Description.sh.ps1 new file mode 100755 index 0000000..47f41d2 --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-All-Components-Description.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-All-Components-Description() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "包装里的所有元件。" + } default { + # fallback to default english + return "All components in this package." + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_All_Components_Description() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "包装里的所有元件。" + ;; + *) + # fallback to default english + printf -- "%b" "All components in this package." + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-All-Components-Title.sh.ps1 b/automataCI/services/hestiaI18N/Translate-All-Components-Title.sh.ps1 new file mode 100755 index 0000000..6f5a520 --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-All-Components-Title.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-All-Components-Title() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "所有元件" + } default { + # fallback to default english + return "All Components" + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_All_Components_Title() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "所有元件" + ;; + *) + # fallback to default english + printf -- "%b" "All Components" + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Already-Latest-Version.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Already-Latest-Version.sh.ps1 new file mode 100755 index 0000000..a69b790 --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Already-Latest-Version.sh.ps1 @@ -0,0 +1,91 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Already-Latest-Version() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "您已经有同样或是最新的版本了。那就不需要任何另外加工吧。" + } default { + # fallback to default english + return "You have the same/latest version. No further action is required." + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Already_Latest_Version() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "您已经有同样或是最新的版本了。那就不需要任何另外加工吧。" + ;; + *) + # fallback to default english + printf -- "%b" "You have the same/latest version. No further action is required." + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Bin-Components-Description.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Bin-Components-Description.sh.ps1 new file mode 100755 index 0000000..d170f5f --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Bin-Components-Description.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Bin-Components-Description() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "所有可启动的软件产品。" + } default { + # fallback to default english + return "All executable software products." + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Bin_Components_Description() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "所有可启动的软件产品。" + ;; + *) + # fallback to default english + printf -- "%b" "All executable software products." + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Bin-Components-Title.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Bin-Components-Title.sh.ps1 new file mode 100755 index 0000000..cc9bac9 --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Bin-Components-Title.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Bin-Components-Title() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "软件元件" + } default { + # fallback to default english + return "Executables Components" + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Bin_Components_Title() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "软件元件" + ;; + *) + # fallback to default english + printf -- "%b" "Executables Components" + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Config-Components-Description.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Config-Components-Description.sh.ps1 new file mode 100755 index 0000000..2820d6a --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Config-Components-Description.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Config-Components-Description() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "所有设定的文件。" + } default { + # fallback to default english + return "All configuration files." + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Config_Components_Description() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "所有设定的文件。" + ;; + *) + # fallback to default english + printf -- "%b" "All configuration files." + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Config-Components-Title.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Config-Components-Title.sh.ps1 new file mode 100755 index 0000000..ce0214c --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Config-Components-Title.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Config-Components-Title() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "设定元件" + } default { + # fallback to default english + return "Configurations Components" + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Config_Components_Title() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "设定元件" + ;; + *) + # fallback to default english + printf -- "%b" "Configurations Components" + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Docs-Components-Description.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Docs-Components-Description.sh.ps1 new file mode 100755 index 0000000..cfdd493 --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Docs-Components-Description.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Docs-Components-Description() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "所有笔记书写文稿。" + } default { + # fallback to default english + return "All articles and documentations." + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Docs_Components_Description() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "所有笔记书写文稿。" + ;; + *) + # fallback to default english + printf -- "%b" "All articles and documentations." + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Docs-Components-Title.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Docs-Components-Title.sh.ps1 new file mode 100755 index 0000000..f6133dd --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Docs-Components-Title.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Docs-Components-Title() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "书写笔记元件" + } default { + # fallback to default english + return "Documentations Components" + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Docs_Components_Title() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "书写笔记元件" + ;; + *) + # fallback to default english + printf -- "%b" "Documentations Components" + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Lib-Components-Description.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Lib-Components-Description.sh.ps1 new file mode 100755 index 0000000..8f480f3 --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Lib-Components-Description.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Lib-Components-Description() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "所有可开发的码库类产品。" + } default { + # fallback to default english + return "All importable libraries products." + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Lib_Components_Description() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "所有可开发的码库类产品。" + ;; + *) + # fallback to default english + printf -- "%b" "All importable libraries products." + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Lib-Components-Title.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Lib-Components-Title.sh.ps1 new file mode 100755 index 0000000..b438df2 --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Lib-Components-Title.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Lib-Components-Title() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "代码库类型元件" + } default { + # fallback to default english + return "Libraries Components" + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Lib_Components_Title() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "代码库类型元件" + ;; + *) + # fallback to default english + printf -- "%b" "Libraries Components" + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Main-Components-Description.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Main-Components-Description.sh.ps1 new file mode 100755 index 0000000..644af0c --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Main-Components-Description.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Main-Components-Description() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "所有第一重要无法缺乏的产品。" + } default { + # fallback to default english + return "All critical and core products." + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Main_Components_Description() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "所有第一重要无法缺乏的产品。" + ;; + *) + # fallback to default english + printf -- "%b" "All critical and core products." + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Main-Components-Title.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Main-Components-Title.sh.ps1 new file mode 100755 index 0000000..5eabc9d --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Main-Components-Title.sh.ps1 @@ -0,0 +1,92 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Main-Components-Title() { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "zh-hans" { + # 简体中文 + return "主要元件" + } default { + # fallback to default english + return "Main Components" + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Main_Components_Title() { + #___locale="$1" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + printf -- "%b" "主要元件" + ;; + *) + # fallback to default english + printf -- "%b" "Main Components" + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Translate-Only-Install-On-Windows.sh.ps1 b/automataCI/services/hestiaI18N/Translate-Only-Install-On-Windows.sh.ps1 new file mode 100755 index 0000000..6a90b68 --- /dev/null +++ b/automataCI/services/hestiaI18N/Translate-Only-Install-On-Windows.sh.ps1 @@ -0,0 +1,209 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +function hestiaI18N-Translate-Only-Install-On-Windows() { + param( + [string]$___locale, + [string]$___arch + ) + + + # execute + switch (${___locale}) { + "zh-hans" { + # 简体中文 + switch ("${___arch}") { + "32" { + $null = I18N-Status-Print info @" +真遗憾。您只能在32位微软Windows操作系统里安装。 +"@ + } "64" { + $null = I18N-Status-Print info @" +真遗憾。您只能在64位微软Windows操作系统里安装。 +"@ + } "amd64" { + $null = I18N-Status-Print info @" +真遗憾。您只能在amd64型芯片的微软Windows操作系统里安装。 +"@ + } "arm64" { + $null = I18N-Status-Print info @" +真遗憾。您只能在arm64型芯片的微软Windows操作系统里安装。 +"@ + } "i386" { + $null = I18N-Status-Print info @" +真遗憾。您只能在i386型芯片的微软Windows操作系统里安装。 +"@ + } "arm" { + $null = I18N-Status-Print info @" +真遗憾。您只能在arm型芯片的微软Windows操作系统里安装。 +"@ + } default { + $null = I18N-Status-Print info @" +真遗憾。您只能在微软Windows操作系统里安装。 +"@ + }} + } default { + # fallback to default english + switch ("${___arch}") { + "32" { + $null = I18N-Status-Print info @" +Unfortunately, you can only install this in a 32-bits Microsoft Windows operating system. +"@ + } "64" { + $null = I18N-Status-Print info @" +Unfortunately, you can only install this in a 64-bits Microsoft Windows operating system. +"@ + } "amd64" { + $null = I18N-Status-Print info @" +Unfortunately, you can only install this in an amd64 Microsoft Windows operating system. +"@ + } "arm64" { + $null = I18N-Status-Print info @" +Unfortunately, you can only install this in an arm64 Microsoft Windows operating system. +"@ + } "i386" { + $null = I18N-Status-Print info @" +Unfortunately, you can only install this in an i386 Microsoft Windows operating system. +"@ + } "arm" { + $null = I18N-Status-Print info @" +Unfortunately, you can only install this in an arm Microsoft Windows operating system. +"@ + } default { + $null = I18N-Status-Print info @" +Unfortunately, you can only install this in a Microsoft Windows operating system. +"@ + }} + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +hestiaI18N_Translate_Only_Install_On_Windows() { + #___locale="$1" + #___arch="$2" + + + # execute + case "$1" in + zh-hans) + # 简体中文 + case "$2" in + 32) + printf -- "%b" "\ +真遗憾。您只能在32位微软Windows操作系统里安装。" + ;; + 64) + printf -- "%b" "\ +真遗憾。您只能在64位微软Windows操作系统里安装。" + ;; + amd64) + printf -- "%b" "\ +真遗憾。您只能在amd64型芯片的微软Windows操作系统里安装。" + ;; + arm64) + printf -- "%b" "\ +真遗憾。您只能在arm64型芯片的微软Windows操作系统里安装。" + ;; + i386) + printf -- "%b" "\ +真遗憾。您只能在i386型芯片的微软Windows操作系统里安装。" + ;; + arm) + printf -- "%b" "\ +真遗憾。您只能在arm型芯片的微软Windows操作系统里安装。" + ;; + *) + printf -- "%b" "\ +真遗憾。您只能在微软Windows操作系统里安装。" + ;; + esac + ;; + *) + # fallback to default english + case "$2" in + 32) + printf -- "%b" "\ +Unfortunately, you can only install this in a 32-bits Microsoft Windows operating system." + ;; + 64) + printf -- "%b" "\ +Unfortunately, you can only install this in a 64-bits Microsoft Windows operating system." + ;; + amd64) + printf -- "%b" "\ +Unfortunately, you can only install this in an amd64 Microsoft Windows operating system." + ;; + arm64) + printf -- "%b" "\ +Unfortunately, you can only install this in an arm64 Microsoft Windows operating system." + ;; + i386) + printf -- "%b" "\ +Unfortunately, you can only install this in an i386 Microsoft Windows operating system." + ;; + arm) + printf -- "%b" "\ +Unfortunately, you can only install this in an arm Microsoft Windows operating system." + ;; + *) + printf -- "%b" "\ +Unfortunately, you can only install this in a Microsoft Windows operating system." + ;; + esac + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaI18N/Vanilla.sh.ps1 b/automataCI/services/hestiaI18N/Vanilla.sh.ps1 new file mode 100755 index 0000000..2dc2478 --- /dev/null +++ b/automataCI/services/hestiaI18N/Vanilla.sh.ps1 @@ -0,0 +1,82 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +. "${env:LIBS_HESTIA}\hestiaI18N\Get_Languages_List.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Already-Latest-Version.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-All-Components-Description.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-All-Components-Title.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Bin-Components-Description.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Bin-Components-Title.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Docs-Components-Description.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Docs-Components-Title.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Config-Components-Description.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Config-Components-Title.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Lib-Components-Description.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Lib-Components-Title.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Main-Components-Description.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Main-Components-Title.sh.ps1" +. "${env:LIBS_HESTIA}\hestiaI18N\Translate-Only-Install-On-Windows.sh.ps1" +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +. "${LIBS_HESTIA}/hestiaI18N/Get_Languages_List.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Already-Latest-Version.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-All-Components-Description.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-All-Components-Title.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Bin-Components-Description.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Bin-Components-Title.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Docs-Components-Description.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Docs-Components-Title.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Config-Components-Description.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Config-Components-Title.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Lib-Components-Description.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Lib-Components-Title.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Main-Components-Description.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Main-Components-Title.sh.ps1" +. "${LIBS_HESTIA}/hestiaI18N/Translate-Only-Install-On-Windows.sh.ps1" +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaLOCALE/Get-LCID.sh.ps1 b/automataCI/services/hestiaLOCALE/Get-LCID.sh.ps1 new file mode 100755 index 0000000..72d2291 --- /dev/null +++ b/automataCI/services/hestiaLOCALE/Get-LCID.sh.ps1 @@ -0,0 +1,113 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +## More Info: +## https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f +function hestiaLOCALE-Get-LCID { + param( + [string]$___locale + ) + + + # execute + switch ("${___locale}") { + "en" { + return 9 + } { $_ -in "en-US", "en-us" } { + return 1033 + } "zh" { + return 30724 + } { $_ -in "zh-CN", "zh-cn" } { + return 2052 + } { $_ -in "zh-Hans", "zh-hans" } { + return 4 + } default { + return + }} + + + # report status + return 0 +} +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +## More Info: +## https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f +hestiaLOCALE_Get_LCID() { + #___locale="$1" + + + # execute + case "$1" in + en) + printf -- "9" + ;; + en-US|en-us) + printf -- "1033" + ;; + zh) + printf -- "30724" + ;; + zh-CN|zh-cn) + printf -- "2052" + ;; + zh-Hans|zh-hans) + printf -- "4" + ;; + *) + printf -- "" + return 1 + ;; + esac + + + # report status + return 0 +} +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/hestiaLOCALE/Vanilla.sh.ps1 b/automataCI/services/hestiaLOCALE/Vanilla.sh.ps1 new file mode 100755 index 0000000..eda087c --- /dev/null +++ b/automataCI/services/hestiaLOCALE/Vanilla.sh.ps1 @@ -0,0 +1,54 @@ +echo \" <<'RUN_AS_BATCH' >/dev/null ">NUL "\" \`" <#" +@ECHO OFF +REM LICENSE CLAUSES HERE +REM ---------------------------------------------------------------------------- + + + + +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +where /q powershell +if errorlevel 1 ( + echo "ERROR: missing powershell facility." + exit /b 1 +) + +copy /Y "%~nx0" "%~n0.ps1" >nul +timeout /t 1 /nobreak >nul +powershell -executionpolicy remotesigned -Command "& '.\%~n0.ps1' %*" +start /b "" cmd /c del "%~f0" & exit /b %errorcode% +REM ############################################################################ +REM # Windows BATCH Codes # +REM ############################################################################ +RUN_AS_BATCH +#> | Out-Null + + + + +echo \" <<'RUN_AS_POWERSHELL' >/dev/null # " | Out-Null +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +. "${env:LIBS_HESTIA}\hestiaLOCALE\Get-LCID.sh.ps1" +################################################################################ +# Windows POWERSHELL Codes # +################################################################################ +return +<# +RUN_AS_POWERSHELL + + + + +################################################################################ +# Unix Main Codes # +################################################################################ +. "${LIBS_HESTIA}/hestiaLOCALE/Get-LCID.sh.ps1" +################################################################################ +# Unix Main Codes # +################################################################################ +return 0 +#> diff --git a/automataCI/services/i18n/_check-available-skipped.ps1 b/automataCI/services/i18n/_check-available-skipped.ps1 new file mode 100644 index 0000000..84eb740 --- /dev/null +++ b/automataCI/services/i18n/_check-available-skipped.ps1 @@ -0,0 +1,28 @@ +# Copyright 2024 (Holloway) Chew, Kean Ho +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at: +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +. "${env:LIBS_AUTOMATACI}\services\i18n\__printer.ps1" + + + + +function I18N-Check-Available-Skipped { + # execute + switch (${env:AUTOMATACI_LANG}) { + default { + # fallback to default english + $null = I18N-Status-Print warning "It's available. Skipping...`n`n" + }} + + + # report status + return 0 +} diff --git a/automataCI/services/i18n/_check-available-skipped.sh b/automataCI/services/i18n/_check-available-skipped.sh new file mode 100644 index 0000000..0f5d528 --- /dev/null +++ b/automataCI/services/i18n/_check-available-skipped.sh @@ -0,0 +1,29 @@ +# Copyright 2024 (Holloway) Chew, Kean Ho +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at: +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +. "${LIBS_AUTOMATACI}/services/i18n/__printer.sh" + + + + +I18N_Check_Available_Skipped() { + # execute + case "$AUTOMATACI_LANG" in + *) + # fallback to default english + I18N_Status_Print warning "It's available. Skipping...\n\n" + ;; + esac + + + # report status + return 0 +} diff --git a/automataCI/services/i18n/_copy-exists-skipped.ps1 b/automataCI/services/i18n/_copy-exists-skipped.ps1 new file mode 100644 index 0000000..6192a0d --- /dev/null +++ b/automataCI/services/i18n/_copy-exists-skipped.ps1 @@ -0,0 +1,28 @@ +# Copyright 2023 (Holloway) Chew, Kean Ho +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at: +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +. "${env:LIBS_AUTOMATACI}\services\i18n\__printer.ps1" + + + + +function I18N-Copy-Exists-Skipped { + # execute + switch (${env:AUTOMATACI_LANG}) { + default { + # fallback to default english + $null = I18N-Status-Print warning "target exists. Skip copying...`n" + }} + + + # report status + return 0 +} diff --git a/automataCI/services/i18n/_copy-exists-skipped.sh b/automataCI/services/i18n/_copy-exists-skipped.sh new file mode 100644 index 0000000..37e66fe --- /dev/null +++ b/automataCI/services/i18n/_copy-exists-skipped.sh @@ -0,0 +1,29 @@ +# Copyright 2023 (Holloway) Chew, Kean Ho +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at: +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +. "${LIBS_AUTOMATACI}/services/i18n/__printer.sh" + + + + +I18N_Copy_Exists_Skipped() { + # execute + case "$AUTOMATACI_LANG" in + *) + # fallback to default english + I18N_Status_Print warning "target exists. Skip copying...\n" + ;; + esac + + + # report status + return 0 +} diff --git a/automataCI/services/i18n/translations.ps1 b/automataCI/services/i18n/translations.ps1 index 69584ce..65ebf27 100644 --- a/automataCI/services/i18n/translations.ps1 +++ b/automataCI/services/i18n/translations.ps1 @@ -25,6 +25,7 @@ . "${env:LIBS_AUTOMATACI}\services\i18n\_build-failed-parallel.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_check.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_check-availability.ps1" +. "${env:LIBS_AUTOMATACI}\services\i18n\_check-available-skipped.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_check-disabled-skipped.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_check-failed.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_check-failed-skipped.ps1" @@ -40,6 +41,7 @@ . "${env:LIBS_AUTOMATACI}\services\i18n\_configure-build-settings.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_configure-failed.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_copy.ps1" +. "${env:LIBS_AUTOMATACI}\services\i18n\_copy-exists-skipped.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_copy-failed.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_create.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\_create-failed.ps1" diff --git a/automataCI/services/i18n/translations.sh b/automataCI/services/i18n/translations.sh index 075a698..5761889 100644 --- a/automataCI/services/i18n/translations.sh +++ b/automataCI/services/i18n/translations.sh @@ -25,6 +25,7 @@ . "${LIBS_AUTOMATACI}/services/i18n/_build-failed-parallel.sh" . "${LIBS_AUTOMATACI}/services/i18n/_check.sh" . "${LIBS_AUTOMATACI}/services/i18n/_check-availability.sh" +. "${LIBS_AUTOMATACI}/services/i18n/_check-available-skipped.sh" . "${LIBS_AUTOMATACI}/services/i18n/_check-disabled-skipped.sh" . "${LIBS_AUTOMATACI}/services/i18n/_check-failed.sh" . "${LIBS_AUTOMATACI}/services/i18n/_check-failed-skipped.sh" @@ -41,6 +42,7 @@ . "${LIBS_AUTOMATACI}/services/i18n/_configure-build-settings.sh" . "${LIBS_AUTOMATACI}/services/i18n/_configure-failed.sh" . "${LIBS_AUTOMATACI}/services/i18n/_copy.sh" +. "${LIBS_AUTOMATACI}/services/i18n/_copy-exists-skipped.sh" . "${LIBS_AUTOMATACI}/services/i18n/_copy-failed.sh" . "${LIBS_AUTOMATACI}/services/i18n/_create.sh" . "${LIBS_AUTOMATACI}/services/i18n/_create-failed.sh" diff --git a/src/.ci/_package-chocolatey_unix-any.sh b/src/.ci/_package-chocolatey_unix-any.sh index 5bafcd8..c8523df 100644 --- a/src/.ci/_package-chocolatey_unix-any.sh +++ b/src/.ci/_package-chocolatey_unix-any.sh @@ -81,6 +81,7 @@ PACKAGE_Assemble_CHOCOLATEY_Content() { fi else # copy library file + __dest="${__dest}/$(FS_Get_File "$_target")" I18N_Assemble "$_target" "$__dest" FS_Make_Directory "$__dest" FS_Copy_File "$_target" "$__dest" diff --git a/src/.ci/_package-chocolatey_windows-any.ps1 b/src/.ci/_package-chocolatey_windows-any.ps1 index 2bb2a8b..0bd8bd8 100644 --- a/src/.ci/_package-chocolatey_windows-any.ps1 +++ b/src/.ci/_package-chocolatey_windows-any.ps1 @@ -81,6 +81,7 @@ function PACKAGE-Assemble-CHOCOLATEY-Content { } } else { # copy library file + $__dest = "${__dest}\$(FS-Get-File "${_target}")" $null = I18N-Assemble "${_target}" "${__dest}" $null = FS-Make-Directory "${__dest}" $___process = FS-Copy-File "${_target}" "${__dest}" diff --git a/src/.ci/_package-deb_unix-any.sh b/src/.ci/_package-deb_unix-any.sh index da5a640..8cb012c 100644 --- a/src/.ci/_package-deb_unix-any.sh +++ b/src/.ci/_package-deb_unix-any.sh @@ -112,6 +112,7 @@ PACKAGE_Assemble_DEB_Content() { fi else # copy library file + __dest="${__dest}/$(FS_Get_File "$_target")" I18N_Assemble "$_target" "$__dest" FS_Make_Directory "$__dest" FS_Copy_File "$_target" "$__dest" diff --git a/src/.ci/_package-deb_windows-any.ps1 b/src/.ci/_package-deb_windows-any.ps1 index c21b825..9ff15d6 100644 --- a/src/.ci/_package-deb_windows-any.ps1 +++ b/src/.ci/_package-deb_windows-any.ps1 @@ -110,6 +110,7 @@ function PACKAGE-Assemble-DEB-Content { } } else { # copy library file + $__dest = "${__dest}\$(FS-Get-File "${_target}")" $null = I18N-Assemble "${_target}" "${__dest}" $null = FS-Make-Directory "${__dest}" $___process = FS-Copy-File "${_target}" "${__dest}" diff --git a/src/.ci/_package-homebrew_unix-any.sh b/src/.ci/_package-homebrew_unix-any.sh index d38a0f3..8e39131 100644 --- a/src/.ci/_package-homebrew_unix-any.sh +++ b/src/.ci/_package-homebrew_unix-any.sh @@ -88,6 +88,7 @@ PACKAGE_Assemble_HOMEBREW_Content() { fi else # copy library file + __dest="${__dest}/$(FS_Get_File "$_target")" I18N_Assemble "$_target" "$__dest" FS_Make_Directory "$__dest" FS_Copy_File "$_target" "$__dest" diff --git a/src/.ci/_package-homebrew_windows-any.ps1 b/src/.ci/_package-homebrew_windows-any.ps1 index 02957af..de198b0 100644 --- a/src/.ci/_package-homebrew_windows-any.ps1 +++ b/src/.ci/_package-homebrew_windows-any.ps1 @@ -86,6 +86,7 @@ function PACKAGE-Assemble-HOMEBREW-Content { } } else { # copy library file + $__dest = "${__dest}\$(FS-Get-File "${_target}")" $null = I18N-Assemble "${_target}" "${__dest}" $null = FS-Make-Directory "${__dest}" $___process = FS-Copy-File "${_target}" "${__dest}" diff --git a/src/.ci/_package-msi_unix-any.sh b/src/.ci/_package-msi_unix-any.sh index 610ab17..3096bff 100644 --- a/src/.ci/_package-msi_unix-any.sh +++ b/src/.ci/_package-msi_unix-any.sh @@ -15,15 +15,13 @@ # initialize -if [ "$PROJECT_PATH_ROOT" = "" ]; then +if [ "$PROJECT_PATH_ROOT" == "" ]; then >&2 printf "[ ERROR ] - Please run from automataCI/ci.sh.ps1 instead!\n" return 1 fi . "${LIBS_AUTOMATACI}/services/io/fs.sh" -. "${LIBS_AUTOMATACI}/services/io/strings.sh" . "${LIBS_AUTOMATACI}/services/i18n/translations.sh" -. "${LIBS_AUTOMATACI}/services/crypto/random.sh" @@ -36,593 +34,203 @@ PACKAGE_Assemble_MSI_Content() { _target_arch="$5" - # package based on target's nature - if [ $(FS_Is_Target_A_MSI "$_target") -ne 0 ]; then - return 10 # not applicable - fi - + # validate input + case "$_target_os" in + any|windows) + ;; + *) + return 10 # not supported + ;; + esac - # validate critical inputs - if [ -z "$PRODUCT_APP_UUID" ]; then - return 1 - fi + case "$_target_arch" in + any|amd64) + ;; + arm64|i386|arm) + return 10 # wixl can only support amd64 + ;; + *) + return 10 # not supported + ;; + esac - # Assemble all files across all languages. Checking is not required - # since it will be checked during the scripting phase. - __build_path="${PROJECT_PATH_ROOT}/${PROJECT_PATH_BUILD}" - __source_path="${PROJECT_PATH_ROOT}/${PROJECT_PATH_SOURCE}" - __files="\ -${__build_path}/${PROJECT_SKU}_windows-amd64.exe|none -${__build_path}/${PROJECT_SKU}_windows-arm64.exe|none -${__build_path}/${PROJECT_SKU}_windows-i386.exe|none -${__build_path}/${PROJECT_SKU}_windows-arm.exe|none -${__source_path}/licenses/LICENSE_en.rtf|LICENSE_en.rtf -${__source_path}/licenses/LICENSE_en.rtf|LICENSE_zh-hans.rtf -${__source_path}/licenses/LICENSE_en.pdf|LICENSE_en.pdf -${__source_path}/licenses/LICENSE_en.pdf|LICENSE_zh-hans.pdf -${__source_path}/docs/USER-GUIDES_en.pdf|USER-GUIDES_en.pdf -${__source_path}/docs/USER-GUIDES_en.pdf|USER-GUIDES_zh-hans.pdf -${__source_path}/icons/icon.ico|none -${__source_path}/icons/msi-banner_en.jpg|none -${__source_path}/icons/msi-banner_zh-hans.jpg|none -${__source_path}/icons/msi-dialog_en.jpg|none -${__source_path}/icons/msi-dialog_zh-hans.jpg|none -" - __selections="\ -amd64|en -amd64|zh-hans -arm64|en -arm64|zh-hans -i386|en -i386|zh-hans -arm|en -arm|zh-hans -" - - - # Assemble all files across all languages. Checking is not required - # since it will be checked during the scripting phase. - old_IFS="$IFS" - printf -- '%s' "$__files" | while IFS="" read -r __line || [ -n "$__line" ]; do - ## parse line - __target="${__line%%|*}" - __dest="${__line##*|}" - - ## validate inputs - if [ ! -z "$_dest" ] && [ ! "$__dest" = "none" ]; then - __dest="${_directory}/${__dest}" + # execute + if [ $(FS_Is_Target_A_Source "$_target") -eq 0 ]; then + return 10 # not applicable + elif [ $(FS_Is_Target_A_Docs "$_target") -eq 0 ]; then + return 10 # not applicable + elif [ $(FS_Is_Target_A_Library "$_target") -eq 0 ]; then + # unpack to the designated lib/ directory + __dest="${_directory}/lib" + + if [ $(FS_Is_Target_A_NPM "$_target") -eq 0 ]; then + return 10 # not applicable + elif [ $(FS_Is_Target_A_TARGZ "$_target") -eq 0 ]; then + # unpack library + I18N_Assemble "$_target" "$__dest" + FS_Make_Directory "$__dest" + TAR_Extract_GZ "$__dest" "$_target" + if [ $? -ne 0 ]; then + I18N_Assemble_Failed + return 1 + fi + elif [ $(FS_Is_Target_A_TARXZ "$_target") -eq 0 ]; then + # unpack library + I18N_Assemble "$_target" "$__dest" + FS_Make_Directory "$__dest" + TAR_Extract_XZ "$__dest" "$_target" + if [ $? -ne 0 ]; then + I18N_Assemble_Failed + return 1 + fi + elif [ $(FS_Is_Target_A_ZIP "$_target") -eq 0 ]; then + # unpack library + I18N_Assemble "$_target" "$__dest" + FS_Make_Directory "$__dest" + ZIP_Extract "$__dest" "$_target" + if [ $? -ne 0 ]; then + I18N_Assemble_Failed + return 1 + fi else - __dest="$_directory" - fi - - ## execute - I18N_Assemble "$__target" "$__dest" - if [ -e "$__target" ]; then - FS_Copy_File "$__target" "$__dest" &> /dev/null + # copy library file + __dest="${__dest}/$(FS_Get_File "${_target}")" + I18N_Assemble "$_target" "$__dest" + FS_Make_Directory "$__dest" + FS_Copy_File "$_target" "$__dest" + if [ $? -ne 0 ]; then + I18N_Assemble_Failed + return 1 + fi fi - done - IFS="$__old_IFS" && unset __old_IFS - - - # generate all arch & i18n independent variables and tags - __tag_ICON='Icon.exe' - __const_ICON_SOURCE="${_directory}/icon.ico" - - __tag_DIR_INSTALL='INSTALLDIR' - __tag_ARP_INSTALL_LOCATION='ARPINSTALLLOCATION' - __const_INSTALLER_VERSION='400' # Windows Installer 4.0 (included in Vista) - __const_INSTALLER_COMPRESSED_MODE='yes' # 'yes'|'no' only - __const_INSTALLER_INSTALL_SCOPE='perMachine' - __const_INSTALLER_REGISTRY_KEY="\ -Software\\\\${PROJECT_CONTACT_NAME}\\\\InstalledProducts\\\\${PROJECT_NAME}" - __const_INSTALLER_REGISTRY_NAME='InstallLocation' - - __tag_COMPONENT_BIN='ComponentBin' - __uuid_COMPONENT_BIN="$(RANDOM_Create_UUID)" # replace with persistent one - __tag_COMPONENT_BIN_OPTIONAL='ComponentBinOptional' - __uuid_COMPONENT_BIN_OPTIONAL="$(RANDOM_Create_UUID)" # replace with persistent one - __tag_COMPONENT_CONFIG='ComponentConfig' - __uuid_COMPONENT_CONFIG="$(RANDOM_Create_UUID)" # replace with persistent one - __tag_COMPONENT_CONFIG_OPTIONAL='ComponentConfigOptional' - __uuid_COMPONENT_CONFIG_OPTIONAL="$(RANDOM_Create_UUID)" # replace with persistent one - __tag_COMPONENT_LIB='ComponentLib' - __uuid_COMPONENT_LIB="$(RANDOM_Create_UUID)" # replace with persistent one - __tag_COMPONENT_LIB_OPTIONAL='ComponentLibOptional' - __uuid_COMPONENT_LIB_OPTIONAL="$(RANDOM_Create_UUID)" # replace with persistent one - __tag_COMPONENT_DOCS='ComponentDocs' - __uuid_COMPONENT_DOCS="$(RANDOM_Create_UUID)" # replace with persistent one - __tag_COMPONENT_DOCS_OPTIONAL='ComponentDocsOptional' - __uuid_COMPONENT_DOCS_OPTIONAL="$(RANDOM_Create_UUID)" # replace with persistent one - - __tag_COMPONENT_INSTALLER='INSTALLDIR_comp' - __uuid_COMPONENT_INSTALLER="$(RANDOM_Create_UUID)" # replace with persistent one - __tag_COMPONENT_REGISTRIES='RegValInstallLocation_comp' - __uuid_COMPONENT_REGISTRIES="$(RANDOM_Create_UUID)" # replace with persistent one - - __tag_FEATURE_ID='FeaturesAll' - __tag_FEATURE_MAIN_ID='FeaturesMain' - __tag_FEATURE_BIN_ID='FeaturesBin' - __tag_FEATURE_CONFIG_ID='FeaturesConfig' - __tag_FEATURE_LIB_ID='FeaturesLib' - __tag_FEATURE_DOCS_ID='FeaturesDocs' - - - # script the .wxs XML file (MSItools version) - old_IFS="$IFS" - printf -- '%s' "$__selections" | while IFS="" read -r __line || [ -n "$__line" ]; do - # parse line - __arch="$(STRINGS_To_Lowercase "${__line%%|*}")" - __line="${__line#*|}" - - __i18n="$(STRINGS_To_Lowercase "${__line%%|*}")" - __line="${__line#*|}" - - - # generate all arch-specific variables and validate readiness for compilation - case "$__arch" in - amd64) - __var_DIR_PROGRAM_FILES="ProgramFiles64Folder" - __var_INSTALLER_REQUIRED_VERSION_ERROR_MESSAGE="\ -Unfortunately, you can only install this package on a 64-bit Windows." - __var_INSTALLER_REQUIRED_VERSION_CONDITION="" - ;; - arm64) - __var_DIR_PROGRAM_FILES="ProgramFiles64Folder" - __var_INSTALLER_REQUIRED_VERSION_ERROR_MESSAGE="\ -Unfortunately, you can only install this package on a 64-bit Windows." - __var_INSTALLER_REQUIRED_VERSION_CONDITION="" - ;; - i386) - __var_DIR_PROGRAM_FILES="ProgramFilesFolder" - __var_INSTALLER_REQUIRED_VERSION_ERROR_MESSAGE="\ -Unfortunately, you can only install this package on a 32-bit Windows." - __var_INSTALLER_REQUIRED_VERSION_CONDITION="" - ;; - arm) - __var_DIR_PROGRAM_FILES="ProgramFilesFolder" - __var_INSTALLER_REQUIRED_VERSION_ERROR_MESSAGE="\ -Unfortunately, you can only install this package on a 32-bit Windows." - __var_INSTALLER_REQUIRED_VERSION_CONDITION="" - ;; - *) - return 1 - ;; - esac - + elif [ $(FS_Is_Target_A_WASM_JS "$_target") -eq 0 ]; then + return 10 # not applicable + elif [ $(FS_Is_Target_A_WASM "$_target") -eq 0 ]; then + return 10 # not applicable + elif [ $(FS_Is_Target_A_Chocolatey "$_target") -eq 0 ]; then + return 10 # not applicable + elif [ $(FS_Is_Target_A_Homebrew "$_target") -eq 0 ]; then + return 10 # not applicable + elif [ $(FS_Is_Target_A_Cargo "$_target") -eq 0 ]; then + return 10 # not applicable + elif [ $(FS_Is_Target_A_MSI "$_target") -eq 0 ]; then + return 10 # not applicable + elif [ $(FS_Is_Target_A_PDF "$_target") -eq 0 ]; then + return 10 # not applicable + else + # copy main program to the designated bin/ directory + __dest="${_directory}/bin/${PROJECT_SKU}.exe" - # check required executables for packaging - __var_MAIN_EXE_SOURCE="${_directory}/${PROJECT_SKU}_windows-${__arch}.exe" - I18N_Check "${__var_MAIN_EXE_SOURCE}" - FS_Is_File "$__var_MAIN_EXE_SOURCE" + I18N_Assemble "$_target" "$__dest" + FS_Make_Housing_Directory "$__dest" + FS_Copy_File "$_target" "$__dest" if [ $? -ne 0 ]; then - I18N_Check_Failed_Skipped - continue + I18N_Assemble_Failed + return 1 fi + fi - # generate all i18n variables and validate readiness for compilation - _wxs="${PROJECT_SKU}_${PROJECT_VERSION}" - case "$__i18n" in - zh-hans) - ## Simplified Chinese (International) - __i18n="zh-hans" - - ## NOTE: MSFT uses LCID instead of ISO indicator. Refer: - ## https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f - __var_LANGUAGE_ID='2052' - - ## NOTE: DO NOT change the format. AutomataCI relies on - ## it to parse wix4 culture settings. - ## https://wixtoolset.org/docs/tools/wixext/wixui/#localization - _wxs="${_wxs}_zh-CN" - - __var_INSTALLER_DESCRIPTION="\ -${PROJECT_NAME} (${PROJECT_VERSION}) 安装包" - __var_INSTALLER_COMMENTS="(C) ${PROJECT_CONTACT_NAME}" - - __var_INSTALLER_BANNER_SOURCE="${_directory}/msi-banner_${__i18n}.jpg" - __var_INSTALLER_DIALOG_SOURCE="${_directory}/msi-dialog_${__i18n}.jpg" - - __var_INSTALLER_DOWNGRADE_COMMENT="\ -您的${PROJECT_NAME}已经是同样|更新版本。如此就不需要任何步骤了。谢谢。 -" - - __var_MAIN_LICENSE_SOURCE="${_directory}/LICENSE_zh-hans.pdf" - - __var_USER_GUIDE_ID='DocsUserGuideZHHANS' - __var_USER_GUIDE_SOURCE="${_directory}/USER-GUIDES_zh-hans.pdf" - - __var_FEATURE_TITLE="${PROJECT_NAME}" - __var_FEATURE_DESCRIPTION='完整全部包装。' - - __var_FEATURE_MAIN_TITLE='主要元件配套' - __var_FEATURE_MAIN_DESCRIPTION='所有第一重要无法缺乏的元件。' - - __var_FEATURE_BIN_TITLE='软件类元件配套' - __var_FEATURE_BIN_DESCRIPTION='所有可有可无的可多加软件类元件。' - - __var_FEATURE_CONFIG_TITLE='配置类元件配套' - __var_FEATURE_CONFIG_DESCRIPTION='所有可有可无的可多加配置类元件。' - - __var_FEATURE_LIB_TITLE='代码库类元件配套' - __var_FEATURE_LIB_DESCRIPTION='所有可有可无的可多加代码库类元件。' - - __var_FEATURE_DOCS_TITLE='文件类元件配套' - __var_FEATURE_DOCS_DESCRIPTION='所有可有可无的可多加文件类元件。' - ;; - *) - # default to English (International) - __i18n="en" - - ## NOTE: MSFT uses LCID instead of ISO indicator. Refer: - ## https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f - __var_LANGUAGE_ID='1033' - - ## NOTE: DO NOT change the format. AutomataCI relies on - ## it to parse wix4 culture settings. - ## https://wixtoolset.org/docs/tools/wixext/wixui/#localization - _wxs="${_wxs}_en-US" - - __var_INSTALLER_DESCRIPTION="\ -${PROJECT_NAME} (${PROJECT_VERSION}) Installer" - __var_INSTALLER_COMMENTS="(C) ${PROJECT_CONTACT_NAME}" - - __var_INSTALLER_BANNER_SOURCE="${_directory}/msi-banner_${__i18n}.jpg" - __var_INSTALLER_DIALOG_SOURCE="${_directory}/msi-dialog_${__i18n}.jpg" - - __var_INSTALLER_DOWNGRADE_COMMENT="\ -Your ${PROJECT_NAME} is the same/later version. No further action is required. Thank you. -" - - __var_MAIN_LICENSE_SOURCE="${_directory}/LICENSE_en.pdf" - - __var_USER_GUIDE_ID='DocsUserGuideEN' - __var_USER_GUIDE_SOURCE="${_directory}/USER-GUIDES_en.pdf" - - __var_FEATURE_TITLE="${PROJECT_NAME}" - __var_FEATURE_DESCRIPTION='The complete package.' - - __var_FEATURE_MAIN_TITLE='Main Components' - __var_FEATURE_MAIN_DESCRIPTION='All core and critical components.' - - __var_FEATURE_BIN_TITLE='Additional Components' - __var_FEATURE_BIN_DESCRIPTION='All optional addition components.' - - __var_FEATURE_CONFIG_TITLE='Additional Configurations Components' - __var_FEATURE_CONFIG_DESCRIPTION='All optional configurations components.' - - __var_FEATURE_LIB_TITLE='Additional Libraries Components' - __var_FEATURE_LIB_DESCRIPTION='All optional libraries components.' - - __var_FEATURE_DOCS_TITLE='Documentation Components' - __var_FEATURE_DOCS_DESCRIPTION='All documentations components.' - ;; - esac - _wxs="${_directory}/${_wxs}_windows-${__arch}.wxs" + # copy README.md into the designated docs/ directory + __source="${PROJECT_PATH_ROOT}/${PROJECT_README}" + __dest="${_directory}/docs/${PROJECT_README}" + I18N_Assemble "$__source" "$__dest" + FS_Copy_File "$__source" "$__dest" + if [ $? -ne 0 ]; then + I18N_Assemble_Failed + return 1 + fi - # check required files for packaging - I18N_Check "$__var_MAIN_LICENSE_SOURCE" - FS_Is_File "$__var_MAIN_LICENSE_SOURCE" + # copy user guide files to the designated docs/ directory + for __source in "${PROJECT_PATH_ROOT}/${PROJECT_PATH_SOURCE}/docs/USER-GUIDES"*.pdf; do + FS_Is_Target_Exist "$__source" if [ $? -ne 0 ]; then - I18N_Check_Failed_Skipped continue fi - I18N_Check "$__var_USER_GUIDE_SOURCE" - FS_Is_File "$__var_USER_GUIDE_SOURCE" + __dest="${_directory}/docs/$(FS_Get_File "$__source")" + I18N_Copy "$__source" "$__dest" + FS_Copy_File "$__source" "$__dest" if [ $? -ne 0 ]; then - I18N_Check_Failed_Skipped - continue - fi - - I18N_Check "$_wxs" - FS_Is_File "$_wxs" - if [ $? -eq 0 ]; then - I18N_Check_Failed + I18N_Copy_Failed return 1 fi + done - # creating wxs recipe - I18N_Create "$_wxs" - FS_Write_File "$_wxs" "\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CMDLINE_${__tag_DIR_INSTALL} - - - - - - CMDLINE_${__tag_DIR_INSTALL} - - - - - - - -" + # copy PDF license files to the designated docs/ directory + for __source in "${PROJECT_PATH_ROOT}/${PROJECT_PATH_SOURCE}/licenses/LICENSE"*.pdf; do + FS_Is_Target_Exist "$__source" if [ $? -ne 0 ]; then - I18N_Create_Failed - return 1 + continue fi - - # Assemble Components - FS_Append_File "$_wxs" "\ - - -" + __dest="${_directory}/docs/$(FS_Get_File "$__source")" + I18N_Copy "$__source" "$__dest" + FS_Copy_File "$__source" "$__dest" if [ $? -ne 0 ]; then - I18N_Create_Failed + I18N_Copy_Failed return 1 fi - - if [ "$__packager_type" = "full" ]; then - FS_Append_File "$_wxs" "\ - - - - - -" - if [ $? -ne 0 ]; then - I18N_Create_Failed - return 1 - fi - fi + done - FS_Append_File "$_wxs" "\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" + # copy RTF license files to the designated docs/ directory + for __source in "${PROJECT_PATH_ROOT}/${PROJECT_PATH_SOURCE}/licenses/LICENSE"*.rtf; do + FS_Is_Target_Exist "$__source" if [ $? -ne 0 ]; then - I18N_Create_Failed - return 1 + continue fi - FS_Append_File "$_wxs" "\ - -" + __dest="${_directory}/docs/$(FS_Get_File "$__source")" + I18N_Copy "$__source" "$__dest" + FS_Copy_File "$__source" "$__dest" if [ $? -ne 0 ]; then - I18N_Create_Failed + I18N_Copy_Failed return 1 fi + done - FS_Append_File "$_wxs" "\ - - - - - - - - - - - -" - if [ $? -ne 0 ]; then - I18N_Create_Failed - return 1 - fi + # copy icon ico file to the designated base directory + __source="${PROJECT_PATH_ROOT}/${PROJECT_PATH_SOURCE}/icons/icon.ico" + __dest="${_directory}/icon.ico" + I18N_Assemble "$__source" "$__dest" + FS_Copy_File "$__source" "$__dest" + if [ $? -ne 0 ]; then + I18N_Assemble_Failed + return 1 + fi - # Define all feature components - FS_Append_File "$_wxs" "\ - - - - - - - - - - - - - - - - - - - - -" - if [ $? -ne 0 ]; then - I18N_Create_Failed - return 1 - fi + # copy MSI banner jpg file to the designated base directory + __source="${PROJECT_PATH_ROOT}/${PROJECT_PATH_SOURCE}/icons/msi-banner.jpg" + __dest="${_directory}/msi-banner.jpg" + I18N_Copy "$__source" "$__dest" + FS_Copy_File "$__source" "$__dest" + if [ $? -ne 0 ]; then + I18N_Copy_Failed + return 1 + fi - # conclude the wxs write-up - FS_Append_File "$_wxs" "\ - - -" - if [ $? -ne 0 ]; then - I18N_Create_Failed - return 1 - fi - done - __exit=$? - IFS="$__old_IFS" && unset __old_IFS - case "$__exit" in - 0) - ;; - *) - return $__exit - ;; - esac + # copy MSI dialog jpg file to the designated base directory + __source="${PROJECT_PATH_ROOT}/${PROJECT_PATH_SOURCE}/icons/msi-dialog.jpg" + __dest="${_directory}/msi-dialog.jpg" + I18N_Copy "$__source" "$__dest" + FS_Copy_File "$__source" "$__dest" + if [ $? -ne 0 ]; then + I18N_Copy_Failed + return 1 + fi + + + ## OPTIONAL - create a '[LANG].wxs' recipe if you wish to override one + ## and place it inside the designated base directory. + ## Otherwise, AutomataCI shall create one for you using its + ## packaging structure. # report status diff --git a/src/.ci/_package-msi_windows-any.ps1 b/src/.ci/_package-msi_windows-any.ps1 index d71aa42..1f54d69 100644 --- a/src/.ci/_package-msi_windows-any.ps1 +++ b/src/.ci/_package-msi_windows-any.ps1 @@ -1,15 +1,14 @@ -#!/bin/sh # Copyright 2023 (Holloway) Chew, Kean Ho # # Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at: -# http://www.apache.org/licenses/LICENSE-2.0 +# use this file except in compliance with the License. You may obtain a copy +# of the License at: +# http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. +# License for the specific language governing permissions and limitations +# under the License. @@ -21,10 +20,7 @@ if (-not (Test-Path -Path $env:PROJECT_PATH_ROOT)) { } . "${env:LIBS_AUTOMATACI}\services\io\fs.ps1" -. "${env:LIBS_AUTOMATACI}\services\io\strings.ps1" . "${env:LIBS_AUTOMATACI}\services\i18n\translations.ps1" -. "${env:LIBS_AUTOMATACI}\services\crypto\random.ps1" -. "${env:LIBS_AUTOMATACI}\services\publishers\dotnet.ps1" @@ -39,671 +35,200 @@ function PACKAGE-Assemble-MSI-Content { ) - # package based on target's nature - if ($(FS-Is-Target-A-MSI "${_target}") -ne 0) { - return 10 # not applicable - } - - - # validate critical inputs - if ($(STRINGS-Is-Empty "${env:PRODUCT_APP_UUID}") -eq 0) { - return 1 - } + # validate project + switch ("${_target_os}") { + { $_ -in "any", "windows" } { + # accepted + } default { + return 10 # not supported + }} - - # configure packaging settings - $__build_path = "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_BUILD}" - $__source_path = "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_SOURCE}" - $__files = @( - "${__build_path}\${env:PROJECT_SKU}_windows-amd64.exe|none" - "${__build_path}\${env:PROJECT_SKU}_windows-arm64.exe|none" - "${__build_path}\${env:PROJECT_SKU}_windows-i386.exe|none" - "${__build_path}\${env:PROJECT_SKU}_windows-arm.exe|none" - "${__source_path}\licenses\LICENSE_en.rtf|LICENSE_en.rtf" - "${__source_path}\licenses\LICENSE_en.rtf|LICENSE_zh-hans.rtf" - "${__source_path}\licenses\LICENSE_en.pdf|LICENSE_en.pdf" - "${__source_path}\licenses\LICENSE_en.pdf|LICENSE_zh-hans.pdf" - "${__source_path}\docs\USER-GUIDES_en.pdf|USER-GUIDES_en.pdf" - "${__source_path}\docs\USER-GUIDES_en.pdf|USER-GUIDES_zh-hans.pdf" - "${__source_path}\icons\icon.ico|none" - "${__source_path}\icons\msi-banner_en.jpg|none" - "${__source_path}\icons\msi-banner_zh-hans.jpg|none" - "${__source_path}\icons\msi-dialog_en.jpg|none" - "${__source_path}\icons\msi-dialog_zh-hans.jpg|none" - ) - $__selections = @( - "amd64|en" - "amd64|zh-hans" - "arm64|en" - "arm64|zh-hans" - ) + switch (${_target_arch}) { + { $_ -in "any", "amd64", "arm64", "i386", "arm" } { + # accepted + } default { + return 10 # not supported + }} - # download required UI extensions + # download required UI extensions into designated ext/ directory $__toolkit_ui = 'WixToolset.UI.wixext' - $___process = DOTNET-Add ` - "${__toolkit_ui}" ` - "4.0.3" ` - "${_directory}\ext" ` - "wixext4\${__toolkit_ui}.dll" + $__dest = "wixext4\${__toolkit_ui}.dll" + $null = I18N-Assemble "${__toolkit_ui}" "${_directory}\ext\${__dest}" + $___process = DOTNET-Add "${__toolkit_ui}" "4.0.3" "${_directory}\ext" "${__dest}" if ($___process -ne 0) { + $null = I18N-Assemble-Failed return 1 } - # Assemble all files across all languages. Checking is not required - # since it will be checked during the scripting phase. - foreach ($__line in $__files) { - ## parse line - $__list = $__line -split "\|" - $__target = $__list[0] - $__dest = $__list[1] - - ## validate inputs - if (($(STRINGS-Is-Empty "${__dest}") -ne 0) -and ("${__dest}" -ne "none")) { - $__dest = "${_directory}\${__dest}" + # processing target + if ($(FS-Is-Target-A-Source "${_target}") -eq 0) { + return 10 # not applicable + } elseif ($(FS-Is-Target-A-Docs "${_target}") -eq 0) { + return 10 # not applicable + } elseif ($(FS-Is-Target-A-Library "${_target}") -eq 0) { + # unpack to the designated lib/ directory + $__dest = "${_directory}\lib" + + if ($(FS-Is-Target-A-NPM "${_target}") -eq 0) { + return 10 # not applicable + } elseif ($(FS-Is-Target-A-TARGZ "${_target}") -eq 0) { + # unpack library + $null = I18N-Assemble "${_target}" "${__dest}" + $null = FS-Make-Directory "${__dest}" + $___process = TAR-Extract-GZ "${__dest}" "${_target}" + if ($___process -ne 0) { + $null = I18N-Assemble-Failed + return 1 + } + } elseif ($(FS-Is-Target-A-TARXZ "${_target}") -eq 0) { + # unpack library + $null = I18N-Assemble "${_target}" "${__dest}" + $null = FS-Make-Directory "${__dest}" + $___process = TAR-Extract-XZ "${__dest}" "${_target}" + if ($___process -ne 0) { + $null = I18N-Assemble-Failed + return 1 + } + } elseif ($(FS-Is-Target-A-ZIP "${_target}") -eq 0) { + # unpack library + $null = I18N-Assemble "${_target}" "${__dest}" + $null = FS-Make-Directory "${__dest}" + $___process = ZIP-Extract "${__dest}" "${_target}" + if ($___process -ne 0) { + $null = I18N-Assemble-Failed + return 1 + } } else { - $__dest = "${_directory}" + # copy library file + $__dest = "${__dest}\$(FS-Get-File "${_target}")" + $null = I18N-Assemble "${_target}" "${__dest}" + $null = FS-Make-Directory "${__dest}" + $___process = FS-Copy-File "${_target}" "${__dest}" + if ($___process -ne 0) { + $null = I18N-Assemble-Failed + return 1 + } } + } elseif ($(FS-Is-Target-A-WASM-JS "${_target}") -eq 0) { + return 10 # not applicable + } elseif ($(FS-Is-Target-A-WASM "${_target}") -eq 0) { + return 10 # not applicable + } elseif ($(FS-Is-Target-A-Chocolatey "${_target}") -eq 0) { + return 10 # not applicable + } elseif ($(FS-Is-Target-A-Homebrew "${_target}") -eq 0) { + return 10 # not applicable + } elseif ($(FS-Is-Target-A-Cargo "${_target}") -eq 0) { + return 10 # not applicable + } elseif ($(FS-Is-Target-A-MSI "${_target}") -eq 0) { + return 10 # not applicable + } elseif ($(FS-Is-Target-A-PDF "${_target}") -eq 0) { + return 10 # not applicable + } else { + # copy main program to the designated bin/ directory + $__dest = "${_directory}\bin\${env:PROJECT_SKU}.exe" - ## execute - $null = I18N-Assemble "${__target}" "${__dest}" - if (Test-Path "${__target}") { - $null = FS-Copy-File "${__target}" "${__dest}" ` - -ErrorAction SilentlyContinue - } - } - - - # generate all arch & i18n independent variables and tags - $__tag_ICON = 'Icon.exe' - $__const_ICON_SOURCE = "${_directory}\icon.ico" - - $__tag_DIR_INSTALL = 'INSTALLDIR' - $__tag_ARP_INSTALL_LOCATION = 'ARPINSTALLLOCATION' - $__const_INSTALLER_VERSION = '500' - $__const_INSTALLER_COMPRESSED_MODE = 'yes' # 'yes'|'no' only - $__const_INSTALLER_CODEPAGE = '65001' # UTF-8 - $__const_INSTALLER_INSTALL_SCOPE = 'perMachine' - $__const_INSTALLER_REGISTRY_KEY = @" -Software\\\\${env:PROJECT_CONTACT_NAME}\\\\InstalledProducts\\\\${env:PROJECT_NAME} -"@ - $__const_INSTALLER_REGISTRY_NAME = 'InstallLocation' - - $__tag_COMPONENT_BIN = 'ComponentBin' - $__uuid_COMPONENT_BIN = RANDOM-Create-UUID # replace with persistent one - $__tag_COMPONENT_BIN_OPTIONAL = 'ComponentBinOptional' - $__uuid_COMPONENT_BIN_OPTIONAL = Random-Create-UUID # replace with persistent one - $__tag_COMPONENT_CONFIG = 'ComponentConfig' - $__uuid_COMPONENT_CONFIG = RANDOM-Create-UUID # replace with persistent one - $__tag_COMPONENT_CONFIG_OPTIONAL = 'ComponentConfigOptional' - $__uuid_COMPONENT_CONFIG_OPTIONAL = RANDOM-Create-UUID # replace with persistent one - $__tag_COMPONENT_LIB = 'ComponentLib' - $__uuid_COMPONENT_LIB = RANDOM-Create-UUID # replace with persistent one - $__tag_COMPONENT_LIB_OPTIONAL = 'ComponentLibOptional' - $__uuid_COMPONENT_LIB_OPTIONAL = RANDOM-Create-UUID # replace with persistent one - $__tag_COMPONENT_DOCS = 'ComponentDocs' - $__uuid_COMPONENT_DOCS = RANDOM-Create-UUID # replace with persistent one - $__tag_COMPONENT_DOCS_OPTIONAL = 'ComponentDocsOptional' - $__uuid_COMPONENT_DOCS_OPTIONAL = RANDOM-Create-UUID # replace with persistent one - - $__tag_COMPONENT_INSTALLER = 'INSTALLDIR_comp' - $__uuid_COMPONENT_INSTALLER = RANDOM-Create-UUID # replace with persistent one - $__tag_COMPONENT_REGISTRIES = 'ComponentRegistries' - $__uuid_COMPONENT_REGISTRIES = RANDOM-Create-UUID # replace with persistent one - - $__tag_FEATURE_ID = 'FeaturesAll' - $__tag_FEATURE_MAIN_ID = 'FeaturesMain' - $__tag_FEATURE_BIN_ID = 'FeaturesBin' - $__tag_FEATURE_CONFIG_ID = 'FeaturesConfig' - $__tag_FEATURE_LIB_ID = 'FeaturesLib' - $__tag_FEATURE_DOCS_ID = 'FeaturesDocs' - - $__const_OPTIONALITY = " AllowAbsent='yes'" - $__const_DIR_PROGRAM_FILES = "ProgramFiles6432Folder" - - - # script the .wxs XML file - foreach ($__line in $__selections) { - # parse line - $__list = $__line -split "\|" - $__arch = STRINGS-To-Lowercase $__list[0] - $__i18n = STRINGS-To-Lowercase $__list[1] - - - # generate all arch-specific variables and validate readiness for compilation - switch ($__arch) { - amd64 { - $__var_INSTALLER_REQUIRED_VERSION_ERROR_MESSAGE = @" -Unfortunately, you can only install this package on a 64-bit Windows. -"@ - $__var_INSTALLER_REQUIRED_VERSION_CONDITION = "VersionNT64" - } arm64 { - $__var_INSTALLER_REQUIRED_VERSION_ERROR_MESSAGE = @" -Unfortunately, you can only install this package on a 64-bit Windows. -"@ - $__var_INSTALLER_REQUIRED_VERSION_CONDITION = "VersionNT64" - } i386 { - $__var_INSTALLER_REQUIRED_VERSION_ERROR_MESSAGE = @" -Unfortunately, you can only install this package on a 32-bit Windows. -"@ - $__var_INSTALLER_REQUIRED_VERSION_CONDITION = "Not VersionNT64" - } arm { - $__var_INSTALLER_REQUIRED_VERSION_ERROR_MESSAGE = @" -Unfortunately, you can only install this package on a 32-bit Windows. -"@ - $__var_INSTALLER_REQUIRED_VERSION_CONDITION = "Not VersionNT64" - } default { - return 1 - }} - - - # check required executables for packaging - $__var_MAIN_EXE_SOURCE = "${_directory}\${env:PROJECT_SKU}_windows-${__arch}.exe" - $null = I18N-Check "${__var_MAIN_EXE_SOURCE}" - $___process = FS-Is-File "${__var_MAIN_EXE_SOURCE}" - if ($___process -ne 0) { - $null = I18N-Check-Failed-Skipped - continue - } - - - # generate all i18n variables and validate readiness for compilation - $_wxs = "${env:PROJECT_SKU}_${env:PROJECT_VERSION}" - switch ($__i18n) { - zh-hans { - ## Simplified Chinese (International) - $__i18n = "zh-hans" - - ## NOTE: MSFT uses LCID instead of ISO indicator. Refer: - ## https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f - $__var_LANGUAGE_ID = '2052' - - ## NOTE: DO NOT change the format. AutomataCI relies on - ## it to parse wix4 culture settings. - ## https://wixtoolset.org/docs/tools/wixext/wixui/#localization - $_wxs = "${_wxs}_zh-cn" - - $__var_INSTALLER_DESCRIPTION = @" -${env:PROJECT_NAME} (${env:PROJECT_VERSION}) 安装包 -"@ - $__var_INSTALLER_COMMENTS = "(C) ${env:PROJECT_CONTACT_NAME}" - $__var_INSTALLER_BANNER_SOURCE = "${_directory}\msi-banner_${__i18n}.jpg" - $__var_INSTALLER_DIALOG_SOURCE = "${_directory}\msi-dialog_${__i18n}.jpg" - $__var_INSTALLER_DOWNGRADE_COMMENT = @" -您的${env:PROJECT_NAME}已经是同样|更新版本。如此就不需要任何步骤了。谢谢。 -"@ - $__var_MAIN_LICENSE_SOURCE = "${_directory}\LICENSE_zh-hans.pdf" - - $__var_USER_GUIDE_ID = 'DocsUserGuideZHHANS' - $__var_USER_GUIDE_SOURCE = "${_directory}\USER-GUIDES_zh-hans.pdf" - - $__var_FEATURE_TITLE = "${env:PROJECT_NAME}" - $__var_FEATURE_DESCRIPTION = '完整全部包装。' - - $__var_FEATURE_MAIN_TITLE = '主要元件配套' - $__var_FEATURE_MAIN_DESCRIPTION = '所有第一重要无法缺乏的元件。' - - $__var_FEATURE_BIN_TITLE = '软件类元件配套' - $__var_FEATURE_BIN_DESCRIPTION = '所有可有可无的可多加软件类元件。' - - $__var_FEATURE_CONFIG_TITLE = '配置类元件配套' - $__var_FEATURE_CONFIG_DESCRIPTION = '所有可有可无的可多加配置类元件。' - - $__var_FEATURE_LIB_TITLE = '代码库类元件配套' - $__var_FEATURE_LIB_DESCRIPTION = '所有可有可无的可多加代码库类元件。' - - $__var_FEATURE_DOCS_TITLE = '文件类元件配套' - $__var_FEATURE_DOCS_DESCRIPTION = '所有可有可无的可多加文件类元件。' - } default { - ## default to English (International) - $__i18n = "en" - - ## NOTE: MSFT uses LCID instead of ISO indicator. Refer: - ## https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f - $__var_LANGUAGE_ID = '1033' - - ## NOTE: DO NOT change the format. AutomataCI relies on - ## it to parse wix4 culture settings. Refer: - ## https://wixtoolset.org/docs/tools/wixext/wixui/#localization - $_wxs = "${_wxs}_en-us" - - $__var_INSTALLER_DESCRIPTION=@" -${env:PROJECT_NAME} (${env:PROJECT_VERSION}) Installer -"@ - $__var_INSTALLER_COMMENTS = "(C) ${env:PROJECT_CONTACT_NAME}" - - $__var_INSTALLER_BANNER_SOURCE = "${_directory}\msi-banner_${__i18n}.jpg" - $__var_INSTALLER_DIALOG_SOURCE = "${_directory}\msi-dialog_${__i18n}.jpg" - - $__var_INSTALLER_DOWNGRADE_COMMENT = @" -Your ${env:PROJECT_NAME} is the same/later version. No further action is required. Thank you. -"@ - - $__var_MAIN_LICENSE_SOURCE = "${_directory}\LICENSE_en.pdf" - - $__var_USER_GUIDE_ID = 'DocsUserGuideEN' - $__var_USER_GUIDE_SOURCE = "${_directory}\USER-GUIDES_en.pdf" - - $__var_FEATURE_TITLE = "${env:PROJECT_NAME}" - $__var_FEATURE_DESCRIPTION = 'The complete package.' - - $__var_FEATURE_MAIN_TITLE = 'Main Components' - $__var_FEATURE_MAIN_DESCRIPTION = 'All core and critical components.' - - $__var_FEATURE_BIN_TITLE = 'Additional Components' - $__var_FEATURE_BIN_DESCRIPTION = 'All optional addition components.' - - $__var_FEATURE_CONFIG_TITLE = 'Additional Configurations Components' - $__var_FEATURE_CONFIG_DESCRIPTION = 'All optional configurations components.' - - $__var_FEATURE_LIB_TITLE = 'Additional Libraries Components' - $__var_FEATURE_LIB_DESCRIPTION = 'All optional libraries components.' - - $__var_FEATURE_DOCS_TITLE = 'Documentation Components' - $__var_FEATURE_DOCS_DESCRIPTION = 'All documentations components.' - }} - $__var_UI_LICENSE_SOURCE = "${_directory}\LICENSE_${__i18n}.rtf" - $_wxs = "${_directory}\${_wxs}_windows-${__arch}.wxs" - - - # check required files for packaging - $null = I18N-Check "${__var_MAIN_LICENSE_SOURCE}" - $___process = FS-Is-File "${__var_MAIN_LICENSE_SOURCE}" - if ($___process -ne 0) { - $null = I18N-Check-Failed-Skipped - continue - } - - $null = I18N-Check "${__var_USER_GUIDE_SOURCE}" - $___process = FS-Is-File "${__var_USER_GUIDE_SOURCE}" - if ($___process -ne 0) { - $null = I18N-Check-Failed-Skipped - continue - } - - $null = I18N-Check "${__var_UI_LICENSE_SOURCE}" - $___process = FS-Is-File "${__var_UI_LICENSE_SOURCE}" - if ($___process -ne 0) { - $null = I18N-Check-Failed-Skipped - continue - } - - $null = I18N-Check "${_wxs}" - if (Test-Path "${_wxs}") { - $null = I18N-Check-Failed - return 1 - } - - - # creating wxs recipe - $null = I18N-Create "${_wxs}" - $___process = FS-Write-File "${_wxs}" @" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"@ + $null = I18N-Assemble "${_target}" "${__dest}" + $null = FS-Make-Housing-Directory "${__dest}" + $___process = FS-Copy-File "${_target}" "${__dest}" if ($___process -ne 0) { - $null = I18N-Create-Failed + $null = I18N-Assemble-Failed return 1 } + } - # Define filesystem - $___process = FS-Append-File "${_wxs}" @" - - - - - - - - - - - - - -"@ - if ($___process -ne 0) { - $null = I18N-Create-Failed - return 1 - } + # copy README.md into the designated docs/ directory + $__source = "${env:PROJECT_PATH_ROOT}\${env:PROJECT_README}" + $__dest = "${_directory}\docs\${env:PROJECT_README}" + $null = I18N-Assemble "${__source}" "${__dest}" + $___process = FS-Copy-File "${__source}" "${__dest}" + if ($___process -ne 0) { + $null = I18N-Assemble-Failed + return 1 + } - ## BEGIN - Assemble components - $___process = FS-Append-File "${_wxs}" @" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"@ + # copy user guide files to the designated docs/ directory + Get-ChildItem -Path "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_SOURCE}\docs" ` + | Where-Object { ($_.Name -like "USER-GUIDES*.pdf") } ` + | ForEach-Object { $__source = $_.FullName + $__dest = "${_directory}\docs\$(FS-Get-File "${__source}")" + $null = I18N-Assemble "${__source}" "${__dest}" + $___process = FS-Copy-File "${__source}" "${__dest}" if ($___process -ne 0) { - $null = I18N-Create-Failed + $null = I18N-Assemble-Failed return 1 } + } - # create registry key - $___process = FS-Append-File "${_wxs}" @" - - - - - - - - - - -"@ + # copy PDF license files to the designated docs/ directory + Get-ChildItem -Path "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_SOURCE}\licenses" ` + | Where-Object { ($_.Name -like "LICENSE*.pdf") } ` + | ForEach-Object { $__source = $_.FullName + $__dest = "${_directory}\docs\$(FS-Get-File "${__source}")" + $null = I18N-Assemble "${__source}" "${__dest}" + $___process = FS-Copy-File "${__source}" "${__dest}" if ($___process -ne 0) { - $null = I18N-Create-Failed + $null = I18N-Assemble-Failed return 1 } + } - # Define all feature components - $___process = FS-Append-File "${_wxs}" @" - - - - - - - - - - - - - - - - - - - - - - - -"@ + # copy RTF license files to the designated docs/ directory + Get-ChildItem -Path "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_SOURCE}\licenses" ` + | Where-Object { ($_.Name -like "LICENSE*.rtf") } ` + | ForEach-Object { $__source = $_.FullName + $__dest = "${_directory}\docs\$(FS-Get-File "${__source}")" + $null = I18N-Assemble "${__source}" "${__dest}" + $___process = FS-Copy-File "${__source}" "${__dest}" if ($___process -ne 0) { - $null = I18N-Create-Failed + $null = I18N-Assemble-Failed return 1 } + } - # Add standard UI support - $___process = FS-Append-File "${_wxs}" @" - - - - - + # copy icon.ico file to the designated base directory + $__source = "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_SOURCE}\icons\icon.ico" + $__dest = "${_directory}\icon.ico" + $null = I18N-Assemble "${__source}" "${__dest}" + $___process = FS-Copy-File "${__source}" "${__dest}" + if ($___process -ne 0) { + $null = I18N-Assemble-Failed + return 1 + } -"@ - if ($___process -ne 0) { - $null = I18N-Create-Failed - return 1 - } + # copy MSI banner jpg file to the designated base directory + $__source = "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_SOURCE}\icons\msi-banner.jpg" + $__dest = "${_directory}\msi-banner.jpg" + $null = I18N-Assemble "${__source}" "${__dest}" + $___process = FS-Copy-File "${__source}" "${__dest}" + if ($___process -ne 0) { + $null = I18N-Assemble-Failed + return 1 + } - # conclude the wxs write-up - $___process = FS-Append-File "${_wxs}" @" - - -"@ - if ($___process -ne 0) { - $null = I18N-Create-Failed - return 1 - } + # copy MSI dialog jpg file to the designated base directory + $__source = "${env:PROJECT_PATH_ROOT}\${env:PROJECT_PATH_SOURCE}\icons\msi-dialog.jpg" + $__dest = "${_directory}\msi-dialog.jpg" + $null = I18N-Assemble "${__source}" "${__dest}" + $___process = FS-Copy-File "${__source}" "${__dest}" + if ($___process -ne 0) { + $null = I18N-Assemble-Failed + return 1 } + ## OPTIONAL - create a '[LANG].wxs' recipe if you wish to override one + ## and place it inside the designated base directory. + ## Otherwise, AutomataCI shall create one for you using its + ## packaging structure. + # report status return 0 diff --git a/src/.ci/_x-package-msi_windows-any.ps1 b/src/.ci/_x-package-msi_windows-any.ps1 new file mode 100644 index 0000000..99e462b --- /dev/null +++ b/src/.ci/_x-package-msi_windows-any.ps1 @@ -0,0 +1,12 @@ + switch ($__i18n) { + zh-hans { + ## NOTE: DO NOT change the format. AutomataCI relies on + ## it to parse wix4 culture settings. + ## https://wixtoolset.org/docs/tools/wixext/wixui/#localization + $_wxs = "${_wxs}_zh-cn" + } default { + ## NOTE: DO NOT change the format. AutomataCI relies on + ## it to parse wix4 culture settings. Refer: + ## https://wixtoolset.org/docs/tools/wixext/wixui/#localization + $_wxs = "${_wxs}_en-us" + }} diff --git a/src/icons/msi-banner_en.jpg b/src/icons/msi-banner.jpg similarity index 100% rename from src/icons/msi-banner_en.jpg rename to src/icons/msi-banner.jpg diff --git a/src/icons/msi-banner_zh-hans.jpg b/src/icons/msi-banner_zh-hans.jpg deleted file mode 100644 index 03238ef5c683fbe7f03d36dad05403c42462d3b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7233 zcmb7obzGF+)Alax!U7BI!V=QmC`*UZh)ahwNJ^)Kl!SDbDBUI95(0vhl!SB$DB%)< zfHb_z_xt-j&-3ql?(^9{?m1^>?sJ`)xpr>nZdU;?rN^kp03Z+uFvC26+eLsJ02>SI zZej)qGrXI&4Fdpxr#V(#_pTQAJLCkf7TcYLR9+fh z&;{n~k4OZjBRli3276htnKam7-StBD&eybRvHFG}as9AlPHT}VevqAs_)Jv_OWtE8 z&#eVJKdXPL9=KeqpN8KAjPw`pbyKyl~OYyA2*F1_?=^DPlk@9_03lpfGMN{n%n%_h-c zX2mw2ZbT+|L7TcPMfWf7U06xgEw?{)&Vs5L&07D(A_~9)^=Js}dUA<;yvp#LOc}R) zEKUzOs++j5<}D1-hs|$Wezg!aCr0h^!3D1AJ9Ayn-wo7iC_&6dLRGWyOB~y8G8;Dk zqE};Cw+9Np3Ix&$O0bO)m~g2q>=Nc7m7<{c5~FG(^5zSjv#Z^{T;`W;l^AYyCX_@j zQ!#t`2;V0OsZ0(|7h@a!;7qi;>pQwx?2?j{%MW^1oXaU7*{ZUBq2QakeG;heaHUcB z>roI#`Yix+mv~?R;9Uq{V&Ffw4I79B0)R>Q+%#^mlxyrS*v`wT{&y{iI%_{)Lvyt%rn zZ3bMdO7KU$=Mt`{HN0#|Oik_w_mAQJ!v8UEXDB{acqHK}^Z?#qiNYEXk<1Eyf356V zo&Evsae2nOb>e7$;$e?=2>)jGPlU; zif3{0u=rcb$}TKm6nUi*|1k8e3G|0Uik|-R+j(wa^@Ka_8~y!v41Kia0D0v%Q*XR7 zeV+Uv{pA$7Q*KBe+Zt(z$g{?=1~a!h%dk9HT_C| zq!|>K1SrUvlg>4xdW|X_Ln7Gied>}O0|}Tu(qtTHIeb#e^EhuXDcQ9!Tyxo2VRvM# zX=UI|gp-XIGokHv%e2n84pP?~KF>zwMFGTEwJDip2~FJj)D9C|SWO$v`C)>#?~puy|a(DyOHq_=@{azAd z;ztk;0D=J6AY5D!_P@FME;)nXBuFq!=71Ez$jqXpO~%BpX&#)OD|`{+5N zmvDym*&?&CQ{(aUjU9PhQSB5c?S5(`vsY}=SU4NMTBeWwv+g1Oe$IBDL_lr~|4Mqz zJVOjb=G~@u4L>AV`^1@>y`15U*Tvfng8w!>#w#pI5dpl$w+$WP;i~&p=xHZJb3=v) zbrvf6=F)DZ6WWykCf;izjJR^yx~WRi=%!G*1w<{Dq)rW51(dojn-1vmV0WHU6fOGab06J0kLVki4B>Lcca!y(EhB|mh1QQ(!!Moqp70X&=J4R%UHo{ZxNO z_I$9n#+F#sbM2>mb1(SJ{I!c8t_w&61lQ+@9GH*ixIA3<=EzPD%AK(3te;bhzRXTf z6saZKZ9u2)rl4~IcDVn(YFVJoB(v$>!$Hv>O@k;f;Pb%&01!3~HZJ&oN-^*s@L{A3 zj7S*-vla`#rnY&~0ho+QHdyc<;IZz2e;vvZ_1=ahac%YC*PPE0!AFvQ;O@qfQAe&9 zu%$Cke#0nb9>_+Mz!GbHNin|BA)>HX$zV-$Qik0lDthG?MZ$5+DeSqo0pxXlZ$~XE z>CG@m&ml^gV^N#9zfIlvbIA)D^>6+K=hyIZ4qa_X!d|V*l2}eS9jd#_&;uU#R-IX{ zDf~BrIO}IK0~)QXTlz4fgy^CJOX<*kuF9>wcal=#8#VWwEYGBM&);Uw8`?tMwdy{o z3wLM!@wQ*dZ?YAg_?A*#2i?-(oLM3#x+2CE1)Sjpe6x!%zD`Cp;RQ}xde&BFZ;0=F z+EwrkXAz^|n_78zW4#aK=C_Rp0%heQrCTl45||%0CMH@`FS)$bGTDP^;m+l$av7(f z_J_2nX<0%}IVJBQ%eec&{S?w-55JUa;cW`!%t2_AagtV~9XHcg{nGvzJ^~rW7d09X z0WJm>zm6cvi5NjjS)Z>nklc!UE*Ov`Fcl8N@-P$)f?-B?<1RwsND@YVQU)eI0U5WX ze2}cBc>%LvaNQaVA+2Tc;`M~KWpej_3LcIWmP}p2oab}a567wh&gO01#eChhwkiLo zVvbwBQ8%Vn-`b{09j8?$Ec8=#bUa_{s5L3DMOAWRbx)h2n_p=(&#T($8gdwXe#EQH z?}yqR?vwgW(qO5IQ%izMBv`(d@oT*W;&&FEb{DZU!Tg7e1q#YcHxQB`fTR z%iZ^oGcJh+?6ir!6^x2x`4vkyJiGeU^!J?VKYK(UII{wRFk?F~EIn zv60_8A9YhldsaWnXwkP83tgTjJp2XaEx3MME=Qn;mI^xJ+BlNm!o?5!x#q2AzEtGa zydGOCewh8vbt+1YfMsfT?S%XOS}946j8(>~EXh(nL%JE({hOwHUU3u_>-G1=RZ78L z!YlBm22VY|u6XRUe9-UU578lF27MkSR1#P*AVm8}dywevp5pW>x^@`M`CrDxzk)nXaqgG|+Uy zud8OeNfJi@t<(728xaP^=^;r za(o=>qe#~;aOXy-m7jj}e;UtLnU`N)YcF(}ik0)bVOWDwq=qf#HOtC+P-K7WG)q`G z1w(E3Pjbk^*WI{@TCmlWPmEO5Rs+V;OPaeil8!ftdps1>xtZNtnpd(eB-y)01HDDasJC1@4^bsD1+2A zcY_6YPplmzJ7`gKaVIp@>?`fkS74;QvF`?ck z>959Q90JAzdFjx*{qJaLhRXcS`Fd(?gtdH#kvs3vkJRnZ;?cD>(GwNyRteL)Qi`?L zIiF81@u@0}y9#mQOWs~Z3+v#DzM|9E-gps?v2zbFoEZ&Ise_@pLNN(T+SQex8pl4W z>IN}%=b{x}=L4*W&*U2>TgW8k@<$-WRfa>j_rO~v6H=i-$_ZZi$?fdn^s*zlyVWyE z0_|cbidntxszRHWPi}qn+m6nGfC3%^qyQ@_rtzZ$k)cJf?f7jr-( zHWxZ@yJG6yp#<~o-63Fh8AgQwf`pybOPopQxrK_(izCZF1i!|!HtlhcK9wECHwteO zLsMIjvCrSwTahfKZ5SOqP6=xjL^c)WjP+y|a$wGbdv|>LJucU8bDc`(5j~+hARK>3 z2r<@Sj>^z%5Umth&8MXAKz%1@fWG;{tgjMo(LcBO)S%ZTg%P#=3FB!>0dnzcUF>F` zSVt#{%YnYik8;dkJLAGX)}I~r;$y2QMj4}Hn$ci$LS}E8!^2ZSIqM18hLM!8DMY@5 z9j`pXuWX3Gz+{Nb-3#Lq<&Yl!d)FvxeoHHV8V2oP?(AB=DOZdgORnpVP~TfXnfQKT zKDQqI#Hn|(?=iQaR=-f@oWC!i)Y3*&^nW7wIP5TqBp>2`N zl)#jW9Li9R3s<$1|Ky%gb$1lVbrB<&T|=C0JyXq~`Sai>9IOnb;r0$(<#H=ZtT*o% zORBbgZCeTL8H$ zew!_5P5J#>io{E-OZ2%Q%Z>yx)}OL>(T-L4a|lLdyqj}0BR&}^`(Ph-l=e9slerI% zk+Bx+#q<*yGv-#KbZ_qr`;+5^1jkygmrhEa-B}}34>(-XMis8=a6WlS*hg^!#eDgc zUAJnl5^B9{YrfRQO{u`%eis>QgGmPe^dac3+6{EF8M6Q7wXt^=C>v(vsPD!C zqP0F$x#9|ls=TsVa44znn0K}5YYu`qe2A+MblOrEO!lsIlVv3zc$_0ma@0<)IG^J9 z{R{1}@Mu*me)$QB-KZwd9N{4HEE{@*4F5CF%JGIN-wTQDX&)lIB*AO4%5 z?zlLN?TKjO)Y3gjc7y2xLCOq7j$JggLi$-b36H}1;R?=3mK9VMD&y-P4CSE}xbMpo z%48PB77c*{#hBZ(Lb8$(ikX#pn`p8j8~W#DVc}GEKTW`?-I2Ed0IOIqlF8CmXe2J2 z#0FUz`G)Smzyzy=h+%8ws~K2BI{l0Cq6<-In0fIlVTA%4htn~}AZXIVw!{~wYceb- zU{IEr07o4b6|)1)ehAJmxuD!I+jrCGk^Zd6dLY=O41A-i`%7JPc(Fiqba(`xP-U!H znrY-`UM8ZkLi0+_5n!Lr4`nK zq!qknVXF|HwY1njL}kh-NN6BlVJ$Wz}2e@LN;L87=e}v#-vIc1R-!LS2JM_ z3j)2AiZePBp>fy#?#oh+okKBoVO1;zWsZr5?L<&)K&y1$8zrtnENSaVJIo&vwba8I z;zNYnr^x9D`QL?T@GU-f<48%P*$@R!AW=&$20d2zU3vMx=-rhUq|6<5=Klfj zf9N#K{+y~Q=bWpdWl(dtk}JmGYLLJO5@iF?3`qS|RI zSy*#3zru22ZAxZ3-sq5>>d3$|j;*l*(qbe;_7-4DR{Eh?nB|v2=I(Uej@*OB&*v3d zOQUBfh`jQkRJ(5y+f9Xvo;ac8``OdEP)(E6VfF{b_`QsTcu^LxP$6}o)@xX4^Fn0% z_GZGFvBj8=EG!Pxbk$n_bEWy>lGxhzC|0tooA6oDkqks`oA%<2<4?Qk`SLy0t+nKv z0BGgg6B0oXBjTy2hM>5j5FP=ENu&})R6w%f+VWe-9m+C&iAK6fQ0Z*h%AXQ1&hox7S2}M0S_S+ zM#vWQ7Jy^e-Pe==N;_|5yZ^nYoJTvSTEI7ZiPu=FEmHBHI*(z?KrEd9?MD6^MlejF z4^Emm$nRdO`%f5QT0>H>w~Z~&P(Iv>29By3D(}flQg+hfeb$569w))nktY<{@twIl zy@4pBzZHixhJ6UlAHmiyU8X17mY;fb>1AB#^cXAaPB`H%7EKUO6&cCx9SX|q9g>e< zSiks-=;c~Y8{4k?bcAqoAg>!6=-MeV9e1(c@uV#p#zOeSh~F$*EOstiN8WT;yi?zq z;jr93Nx)nis@*!DxvAVy6UC{Ao;8!V0HHg(mcg4GU7BW}M-|6jDsMP=b|y}Bz2YUh zkpD$hS#@yA3|_9nE+6-_WE5bUoq8Bi02EMBg$WL7X}#yZXWwtXG0H&o0~MHHTpUDp zB*v~;+B<@uCn$-y8fv+GIghrZ6D4O#Kst1nHQ0529$04Wu&CI(zEXQV++Md1Xn=Lh zK4L#5?v>QNQVJ~X&HwYMu#m}xR|1-qWpUbf>iPXFT+Tqx z(t;$KQ$}5zKR0AUD&|~upmc*c%s)>Ww}kH|XIG=Nk@@HAjDW2CONr!-cdZMO1@X@D z98If(mPJBSYkZ#1v~fiph650Ujb(8T&yb}$8!+8T!57^3%KccXop`PO{9Ug~=y5`4 zl}J=rirfP7x5W-HC$;1y$Qktepjw;-)?Bw-^3dS7f60rU+R+yOE`lNZlJd5I{*Hkx zHwPL`#mI$Ht!2BTb!t+lWv!!)=QtqG`vWT)(fN;Px0V1wU|=0W+ru48w~_yRQB@jI#e!=IhP!kjL^KkA?Y zGh0tQ^|+T~QdyRT54bHyjc7i6Y%PgDZ4|Z=4?+OD6-5-dY@c6Jd3*SE=kv`|=o!zv z%IsMW&B(io0ygwj>%BvA_m(2bgqx&n@a;2FLYW9R9-LN(d~W4S4b$~BXdlxY=T3W>CeTduxYuwX zvS7qJfnnV-F)!8SLjsXHbisxi=gZP-*>b~(T`6X&#@4@tSM+_Z98K|@q4q&G`hUM# za8_gK3R1+;bH*`h*gVC&5b9T(8$Yl;cjdLLoEkE=nq3z|f20*9w=4{{wmh__EF})! z^%<^^uitv|cfdYlzb!Ulfv$%L30R=QKHMt01%#YO2hyi)cM*@w2S}x>0v99nOah)y zZ_)g!_n!UM`2Lk|_$|PAGasf`(tR2I5Ytyvr~x$ZsU7~YE09|Xc~D?Gy)VvnN_LaC zXTaf^K4n?=v4h4uz_0%DQ9}3S3As0&MYLF(?QT)e-QpyM%Xt1ovxdICwbIWk zq-cyl4K-*t9jesaR;jtp8@SrEib)H#IE_Wqj^c5W%x0psLj*tHalull$ZazPk{p`E zr&LUuw8{4=jYJOBJy#+gXK%u*-we`T{H6u!(2nXCtop>zP#1*CwInDvA}YTWT^cMa zPF<;&p1)13z)-F!%OE-vY#aqcN_E78LODezIm_7l)AfrB{

Yi9foh%=@ya( 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%0D_|@b`a%c%Yajodb0P)IuDK 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