Created
June 11, 2025 02:58
-
-
Save mgaffigan/8465e9504132c01e2883dcba7540eee4 to your computer and use it in GitHub Desktop.
Mirth Server Launch Script
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
| import os | |
| import sys | |
| import re | |
| def substitute_env_vars(s: str) -> str: | |
| """ | |
| Substitutes `${VAR_NAME}` patterns within a given string `s`. | |
| """ | |
| def replace_match(match) -> str: | |
| var_name = match.group(1) | |
| # Use os.getenv with a default of an empty string if the variable is not found. | |
| return os.getenv(var_name, "") | |
| return re.sub(r"\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}", replace_match, s) | |
| class ParsedVmOptions: | |
| """ | |
| Represents the result of parsing a vmoptions file. | |
| Contains the options, classpath, java command path, and parsed file set | |
| """ | |
| def __init__(self, vm_options=None, classpath=None, java_cmd_path=None, parsed_files=None): | |
| self.vm_options = vm_options or [] | |
| self.classpath = classpath or [] | |
| self.java_cmd_path = java_cmd_path | |
| self.parsed_files = parsed_files or set() | |
| def add_file(self, filepath: str): | |
| """ | |
| Recursively parses a vmoptions file and any files included via `-include-options`. | |
| Accumulates JVM options, classpath segments, and the effective Java command path. | |
| """ | |
| # Prevent infinite recursion for circular includes | |
| if filepath in self.parsed_files: | |
| raise ValueError(f"Detected circular include for file: {filepath}") | |
| self.parsed_files.add(filepath) | |
| # Parse the file line by line | |
| with open(filepath, 'r') as f: | |
| for line in f: | |
| try: | |
| self.add_option(line) | |
| except Exception as e: | |
| raise ValueError(f"Error parsing line in {filepath}: {line}") from e | |
| def add_option(self, line: str): | |
| # Skip empty lines and comments | |
| line = line.strip() | |
| if not line or line.startswith('#'): | |
| continue | |
| # Parse line into the first word and the rest | |
| first_word, _, rest = line.partition(' ') | |
| rest = rest.strip() | |
| if first_word = "-include-options": | |
| # Apply environment variable substitution to the included path | |
| self.add_file(substitute_env_vars(rest)) | |
| elif first_word = "-java-cmd": | |
| self.java_cmd_path = substitute_env_vars(rest) | |
| elif first_word = "-classpath": | |
| # Apply environment variable substitution and replace the entire classpath | |
| self.classpath.clear() | |
| self.classpath.append(substitute_env_vars(rest)) | |
| elif line = "-classpath/a": | |
| self.classpath.append(substitute_env_vars(rest)) | |
| elif line = "-classpath/p": | |
| self.classpath.insert(0, substitute_env_vars(rest)) | |
| else: | |
| # Assume any other non-comment, non-blank line is a standard JVM option. | |
| # Apply environment variable substitution and add to options list. | |
| self.vm_options.append(substitute_env_vars(line)) | |
| def get_executable() -> str: | |
| """ | |
| Determines the default Java executable from options, JAVA_HOME, or system PATH. | |
| """ | |
| if self.java_cmd_path: | |
| return os.path.abspath(self.java_cmd_path) | |
| java_home = os.getenv("JAVA_HOME", "").strip() | |
| if java_home: | |
| # Canonicalize the JAVA_HOME path to ensure it is absolute and normalized | |
| return os.path.abspath(os.path.join(java_home, "bin", "java")) | |
| # JAVA_HOME not set, use default 'java' (relying on system PATH) | |
| return "java" | |
| def get_invocation(main_class: str, app_args: list[str]) -> list[str]: | |
| """ | |
| Constructs the complete command to launch the Java application. | |
| """ | |
| command = [self.get_executable()] | |
| command.extend(self.vm_options) | |
| command.extend(["-cp", os.pathsep.join(self.classpath)]) | |
| command.append(main_class) | |
| command.extend(app_args) | |
| return command | |
| if __name__ == "__main__": | |
| # Parse vmoptions file | |
| parse_result = ParsedVmOptions(classpath=["com.mirth.connect.server.launcher.MirthLauncher"]) | |
| parse_result.add_file("engine.vmoptions") | |
| # Get additional arguments passed to the launcher script itself | |
| # sys.argv[0] is the script name, so we slice from index 1 onwards for application arguments. | |
| app_args = sys.argv[1:] | |
| # Assemble the complete command list using the helper function | |
| command = parse_result.get_invocation(MAIN_CLASS, app_args) | |
| # execl the command to replace the current process | |
| print("Launching Engine with command:", " ".join(command)) | |
| os.execvp(command[0], command) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment