Created
June 16, 2025 07:00
-
-
Save engalar/b04be00c2616dbec06b70369f34aba24 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# ==================================================================================== | |
# | |
# Mendix Studio Pro Offline Installer Preparation Tool (v5 - Stderr/Stdout Fix) | |
# | |
# Description: | |
# This script prepares a full offline installer package for Mendix Studio Pro | |
# on a Linux system, for later installation on Windows. | |
# | |
# Fixes in this version: | |
# - Fixed a bug where the interactive menu was not displayed because its stdout | |
# was being captured by command substitution. | |
# - Redirected all user prompts and menus to stderr (>&2) to ensure they | |
# are always visible in interactive mode. | |
# | |
# ==================================================================================== | |
# --- Script Setup --- | |
set -o errexit | |
set -o nounset | |
set -o pipefail | |
# --- Color Definitions for Output --- | |
C_RESET='\033[0m' | |
C_RED='\033[0;31m' | |
C_GREEN='\033[0;32m' | |
C_YELLOW='\033[0;33m' | |
C_BLUE='\033[0;34m' | |
C_BOLD='\033[1m' | |
# --- Global Configuration --- | |
OUTPUT_DIR_BASE="Mendix_Offline_Installer" | |
DEPS_SUBDIR="Dependencies" | |
MENDIX_LISTING_URL="https://cdn.mendix.com/listing.txt" | |
MENDIX_ARTIFACTS_URL="https://artifacts.rnd.mendix.com/modelers" | |
TEMP_LISTING_FILE=$(mktemp) | |
CONNECT_TIMEOUT=15 | |
READ_TIMEOUT=90 | |
# --- Dependency Definitions (Global Associative Array) --- | |
declare -gA DEPS | |
# --- Helper Functions --- | |
log_info() { echo -e "${C_BLUE}INFO:${C_RESET} $1"; } | |
log_success() { echo -e "${C_GREEN}SUCCESS:${C_RESET} $1"; } | |
log_warn() { echo -e "${C_YELLOW}WARN:${C_RESET} $1" >&2; } # Warnings go to stderr | |
log_error() { echo -e "${C_RED}ERROR:${C_RESET} $1" >&2; } # Errors go to stderr | |
check_tools() { | |
log_info "Checking for required tools (wget, curl, etc.)..." | |
local missing=0 | |
for tool in wget curl grep sed cut tail sort; do | |
if ! command -v "${tool}" &>/dev/null; then | |
log_error "Required tool '${tool}' is not installed." | |
missing=1 | |
fi | |
done | |
[[ ${missing} -eq 1 ]] && { | |
log_error "Please install missing tools and try again." | |
exit 1 | |
} | |
log_success "All required tools are present." | |
} | |
check_network() { | |
log_info "Checking network connectivity by trying to reach google.com..." | |
if ! curl -s --head --connect-timeout 10 "https://www.google.com" >/dev/null; then | |
log_error "Network connectivity check failed. The script cannot reach the internet." | |
log_error "Please check your network connection, DNS settings, or corporate firewall/proxy rules." | |
exit 1 | |
fi | |
log_success "Network connectivity is OK." | |
} | |
download_final_file() { | |
local url="$1" | |
local target_path="$2" | |
local filename | |
filename=$(basename "${target_path}") | |
if [[ -f "${target_path}" ]]; then | |
log_warn "File '${filename}' already exists. Skipping download." | |
else | |
log_info "Downloading '${filename}'..." | |
if ! wget --connect-timeout=${CONNECT_TIMEOUT} --read-timeout=${READ_TIMEOUT} -q --show-progress -O "${target_path}" "${url}"; then | |
log_error "Failed to download ${filename}. Please check the URL and your network." | |
rm -f "${target_path}" | |
exit 1 | |
fi | |
log_success "'${filename}' downloaded." | |
fi | |
} | |
resolve_dependencies() { | |
local mendix_version="$1" | |
local major_version | |
major_version=$(echo "${mendix_version}" | cut -d. -f1) | |
log_info "Resolving dependencies for Mendix v${major_version}..." | |
# Common Dependencies | |
DEPS[vcredist2019_url]="https://aka.ms/vs/17/release/vc_redist.x64.exe" | |
DEPS[vcredist2019_target]="vcredist2019_x64.exe" | |
DEPS[native_builder_url]="https://cdn.mendix.com/native-builder/latest.exe" | |
DEPS[native_builder_target]="mendix_native_mobile_builder.exe" | |
DEPS[git_url]="https://github.com/git-for-windows/git/releases/download/v2.45.1.windows.1/Git-2.45.1-64-bit.exe" | |
DEPS[git_target]="git_for_windows_installer.exe" | |
DEPS[webview_url]="https://go.microsoft.com/fwlink/p/?LinkId=2124703" | |
DEPS[webview_target]="MicrosoftEdgeWebView2Setup.exe" | |
case "${major_version}" in | |
10) | |
DEPS[net_runtime_url]="https://download.visualstudio.microsoft.com/download/pr/982c6c39-0186-449e-bab6-1a52319853f8/47a25a322972986f8516d3f3747d32c9/windowsdesktop-runtime-8.0.4-win-x64.exe" | |
DEPS[net_runtime_target]="windowsdesktop-runtime-8.0-x64.exe" | |
DEPS[jdk_url]="https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.3%2B9/OpenJDK21U-jdk_x64_windows_hotspot_21.0.3_9.msi" | |
DEPS[jdk_target]="adoptiumjdk_21_x64.msi" | |
DEPS[gradle_url]="https://services.gradle.org/distributions/gradle-8.5-bin.zip" | |
DEPS[gradle_target]="gradle-8.5-bin.zip" | |
;; | |
9) | |
DEPS[net_runtime_url]="https://download.visualstudio.microsoft.com/download/pr/5681bdf9-0a48-45ac-b7bf-21b7b61657aa/bbdc43bc7bf0d15b97c1a98ae2e82ec0/windowsdesktop-runtime-6.0.5-win-x64.exe" | |
DEPS[net_runtime_target]="windowsdesktop-runtime-6.0-x64.exe" | |
local jdk_mirror_url="https://mirrors.tuna.tsinghua.edu.cn/Adoptium/11/jdk/x64/windows/" | |
log_info "Dynamically finding latest JDK 11 from Tsinghua mirror..." | |
local latest_jdk_file | |
latest_jdk_file=$(curl --connect-timeout=${CONNECT_TIMEOUT} -s "${jdk_mirror_url}" | grep -o 'href="OpenJDK11U-jdk_x64_windows_hotspot_[^"]*\.msi"' | sed 's/href="//;s/"$//' | tail -n 1) | |
if [[ -z "${latest_jdk_file}" ]]; then | |
log_error "Failed to dynamically find the JDK 11 MSI. Aborting." | |
exit 1 | |
fi | |
DEPS[jdk_url]="${jdk_mirror_url}${latest_jdk_file}" | |
DEPS[jdk_target]="adoptopenjdk_11_x64.msi" | |
DEPS[gradle_url]="https://services.gradle.org/distributions/gradle-7.6-bin.zip" | |
DEPS[gradle_target]="gradle-7.6-bin.zip" | |
DEPS[vcredist2010_url]="https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x64.exe" | |
DEPS[vcredist2010_target]="vcredist2010_x64.exe" | |
;; | |
*) | |
log_error "Unsupported Mendix major version: '${major_version}'. This script supports versions 9 and 10." | |
exit 1 | |
;; | |
esac | |
log_success "Dependency list for Mendix v${major_version} resolved." | |
} | |
# --- Core Logic Functions --- | |
get_mendix_version_interactively() { | |
# All logging and user prompts in this function must go to stderr (>&2) | |
# so they are not captured by the command substitution in main(). | |
log_info "Fetching available Mendix Studio Pro versions..." >&2 | |
if ! wget --connect-timeout=${CONNECT_TIMEOUT} --read-timeout=${READ_TIMEOUT} -q -O "${TEMP_LISTING_FILE}" "${MENDIX_LISTING_URL}"; then | |
log_error "Failed to download the Mendix version list. Please check the URL and your network." | |
exit 1 | |
fi | |
log_success "Version list downloaded." >&2 | |
mapfile -t versions < <(grep 'runtime/mendix' "${TEMP_LISTING_FILE}" | sed 's/^runtime\/mendix-\(.*\)\.tar\.gz$/\1/' | sort -rV) | |
if [ ${#versions[@]} -eq 0 ]; then | |
log_error "Could not retrieve any Mendix versions from the listing." | |
exit 1 | |
fi | |
# *** FIX: Redirect menu and prompts to stderr (>&2) *** | |
echo -e "\n${C_BOLD}Please select a Mendix Studio Pro version to prepare:${C_RESET}" >&2 | |
for i in "${!versions[@]}"; do | |
printf "[%3d] %s\n" "$((i + 1))" "${versions[$i]}" >&2 | |
done | |
local choice | |
while true; do | |
# read -p already prints its prompt to stderr, so no need for redirection here. | |
read -p "$(echo -e "\nEnter the number of the version you want: ")" choice | |
if [[ "${choice}" =~ ^[0-9]+$ ]] && [ "${choice}" -ge 1 ] && [ "${choice}" -le "${#versions[@]}" ]; then | |
# *** The final selected version is echoed to STDOUT to be captured by main() *** | |
echo "${versions[$((choice - 1))]}" | |
break | |
else | |
log_warn "Invalid input. Please enter a number between 1 and ${#versions[@]}." | |
fi | |
done | |
} | |
# --- Main Execution Function --- | |
main() { | |
trap 'rm -f "${TEMP_LISTING_FILE}"' EXIT | |
check_tools | |
check_network | |
local mendix_version="" | |
if [ $# -eq 1 ]; then | |
mendix_version="$1" | |
log_info "Direct mode: Preparing offline installer for version ${C_YELLOW}${mendix_version}${C_RESET}." | |
else | |
# The interactive menu is now correctly displayed. | |
mendix_version=$(get_mendix_version_interactively) | |
log_info "Interactive mode: Selected version ${C_YELLOW}${mendix_version}${C_RESET}." | |
fi | |
resolve_dependencies "${mendix_version}" | |
local output_dir="${OUTPUT_DIR_BASE}_v${mendix_version}" | |
local deps_dir="${output_dir}/${DEPS_SUBDIR}" | |
log_info "Creating directory structure in '${output_dir}'..." | |
rm -rf "${output_dir}" | |
mkdir -p "${deps_dir}" | |
log_info "--- Starting Downloads ---" | |
local mendix_setup_url="${MENDIX_ARTIFACTS_URL}/Mendix-${mendix_version}-Setup.exe" | |
local mendix_setup_target="${output_dir}/Mendix-${mendix_version}-Setup.exe" | |
download_final_file "${mendix_setup_url}" "${mendix_setup_target}" | |
log_info "Processing all required dependencies..." | |
for key in "${!DEPS[@]}"; do | |
if [[ $key == *_url ]]; then | |
local prefix="${key%_url}" | |
local url="${DEPS[${prefix}_url]}" | |
local target_filename="${DEPS[${prefix}_target]}" | |
local target_path="${deps_dir}/${target_filename}" | |
download_final_file "${url}" "${target_path}" | |
fi | |
done | |
echo | |
log_success "=========================================================" | |
log_success "✅ Offline Installer Preparation for Mendix ${mendix_version} Complete! ✅" | |
log_success "=========================================================" | |
echo -e "Resources are located in the '${C_YELLOW}${output_dir}${C_RESET}' directory." | |
echo -e "\nFinal directory structure:" | |
if command -v tree &>/dev/null; then | |
tree "${output_dir}" | |
else | |
ls -lR "${output_dir}" | |
fi | |
echo -e "\n${C_BOLD}Next Steps:${C_RESET}" | |
echo -e "1. Copy the entire '${C_YELLOW}${output_dir}${C_RESET}' directory to your Windows machine." | |
echo -e "2. On Windows, run the Mendix Setup executable from that folder." | |
} | |
# --- SCRIPT ENTRY POINT --- | |
main "$@v" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment