diff --git a/launcher/src/main/scripts/bin/launcher.py b/launcher/src/main/scripts/bin/launcher.py index f262898a83..7d576c38ee 100755 --- a/launcher/src/main/scripts/bin/launcher.py +++ b/launcher/src/main/scripts/bin/launcher.py @@ -21,11 +21,11 @@ def find_install_path(f): """Find canonical parent of bin/launcher.py""" - if basename(f) != 'launcher.py': - raise Exception("Expected file '%s' to be 'launcher.py' not '%s'" % (f, basename(f))) + if basename(f) != "launcher.py": + raise Exception(f"Expected file '{f}' to be 'launcher.py' not '{basename(f)}'") p = realpath(dirname(f)) - if basename(p) != 'bin': - raise Exception("Expected file '%s' directory to be 'bin' not '%s" % (f, basename(p))) + if basename(p) != "bin": + raise Exception(f"Expected file '{f}' directory to be 'bin' not '{basename(p)}'") return dirname(p) @@ -42,7 +42,7 @@ def load_properties(f): """Load key/value pairs from a file""" properties = {} for line in load_lines(f): - k, v = line.split('=', 1) + k, v = line.split("=", 1) properties[k.strip()] = v.strip() return properties @@ -50,9 +50,9 @@ def load_properties(f): def load_lines(f): """Load lines from a file, ignoring blank or comment lines""" lines = [] - for line in open(f, 'r').readlines(): + for line in open(f, "r").readlines(): line = line.strip() - if len(line) > 0 and not line.startswith('#'): + if len(line) > 0 and not line.startswith("#"): lines.append(line) return lines @@ -68,7 +68,7 @@ def try_lock(f): def open_read_write(f, mode): """Open file in read/write mode (without truncating it)""" - return os.fdopen(os.open(f, O_RDWR | O_CREAT, mode), 'r+') + return os.fdopen(os.open(f, O_RDWR | O_CREAT, mode), "r+") class Process: @@ -82,13 +82,13 @@ def refresh(self): self.locked = try_lock(self.pid_file) def clear_pid(self): - assert self.locked, 'pid file not locked by us' + assert self.locked, "pid file not locked by us" self.pid_file.seek(0) self.pid_file.truncate() def write_pid(self, pid): self.clear_pid() - self.pid_file.write(str(pid) + '\n') + self.pid_file.write(str(pid) + "\n") self.pid_file.flush() def alive(self): @@ -101,21 +101,21 @@ def alive(self): os.kill(pid, 0) return True except OSError as e: - raise Exception('Signaling pid %s failed: %s' % (pid, e)) + raise Exception(f"Signaling pid {pid} failed: {e}") def read_pid(self): - assert not self.locked, 'pid file is locked by us' + assert not self.locked, "pid file is locked by us" self.pid_file.seek(0) line = self.pid_file.readline().strip() if len(line) == 0: - raise Exception("Pid file '%s' is empty" % self.path) + raise Exception(f"Pid file '{self.path}' is empty") try: pid = int(line) except ValueError: - raise Exception("Pid file '%s' contains garbage: %s" % (self.path, line)) + raise Exception(f"Pid file '{self.path}' contains garbage: {line}") if pid <= 0: - raise Exception("Pid file '%s' contains an invalid pid: %s" % (self.path, pid)) + raise Exception(f"Pid file '{self.path}' contains an invalid pid: {pid}") return pid @@ -143,7 +143,7 @@ def symlink_exists(p): try: st = os.lstat(p) if not S_ISLNK(st.st_mode): - raise Exception('Path exists and is not a symlink: %s' % p) + raise Exception(f"Path exists and is not a symlink: {p}") return True except OSError as e: if e.errno != errno.ENOENT: @@ -161,58 +161,58 @@ def create_symlink(source, target): def create_app_symlinks(options): """ - Symlink the 'etc' and 'plugin' directory into the data directory. + Symlink the "etc" and "plugin" directory into the data directory. - This is needed to support programs that reference 'etc/xyz' from within + This is needed to support programs that reference "etc/xyz" from within their config files: log.levels-file=etc/log.properties """ - if options.etc_dir != pathjoin(options.data_dir, 'etc'): + if options.etc_dir != pathjoin(options.data_dir, "etc"): create_symlink( options.etc_dir, - pathjoin(options.data_dir, 'etc')) + pathjoin(options.data_dir, "etc")) if options.install_path != options.data_dir: create_symlink( - pathjoin(options.install_path, 'plugin'), - pathjoin(options.data_dir, 'plugin')) + pathjoin(options.install_path, "plugin"), + pathjoin(options.data_dir, "plugin")) def build_java_execution(options, daemon): if not exists(options.config_path): - raise Exception('Config file is missing: %s' % options.config_path) + raise Exception(f"Config file is missing: {options.config_path}") if not exists(options.jvm_config): - raise Exception('JVM config file is missing: %s' % options.jvm_config) + raise Exception(f"JVM config file is missing: {options.jvm_config}") if not exists(options.launcher_config): - raise Exception('Launcher config file is missing: %s' % options.launcher_config) + raise Exception(f"Launcher config file is missing: {options.launcher_config}") if options.log_levels_set and not exists(options.log_levels): - raise Exception('Log levels file is missing: %s' % options.log_levels) + raise Exception(f"Log levels file is missing: {options.log_levels}") properties = options.properties.copy() if exists(options.log_levels): - properties['log.levels-file'] = options.log_levels + properties["log.levels-file"] = options.log_levels if daemon: - properties['log.path'] = options.server_log - properties['log.enable-console'] = 'false' + properties["log.path"] = options.server_log + properties["log.enable-console"] = "false" jvm_properties = load_lines(options.jvm_config) launcher_properties = load_properties(options.launcher_config) try: - main_class = launcher_properties['main-class'] + main_class = launcher_properties["main-class"] except KeyError: raise Exception("Launcher config is missing 'main-class' property") - properties['config'] = options.config_path + properties["config"] = options.config_path - system_properties = ['-D%s=%s' % i for i in properties.items()] - classpath = pathjoin(options.install_path, 'lib', '*') + system_properties = [f"-D{key}={value}" for key, value in properties.items()] + classpath = pathjoin(options.install_path, "lib", "*") - java_binary_prefix = '' - if os.getenv('JAVA_HOME'): - java_binary_prefix = os.getenv('JAVA_HOME') + '/bin/' - command = [java_binary_prefix + 'java', '-cp', classpath] + java_binary_prefix = "" + if os.getenv("JAVA_HOME"): + java_binary_prefix = os.getenv("JAVA_HOME") + "/bin/" + command = [java_binary_prefix + "java", "-cp", classpath] command += jvm_properties + system_properties command += [main_class] command += options.arguments @@ -224,20 +224,20 @@ def build_java_execution(options, daemon): env = os.environ.copy() # set process name: https://github.com/electrum/procname - process_name = launcher_properties.get('process-name', '') + process_name = launcher_properties.get("process-name", "") if len(process_name) > 0: - system = platform.system() + '-' + platform.machine() - shim = pathjoin(options.install_path, 'bin', 'procname', system, 'libprocname.so') + system = platform.system() + "-" + platform.machine() + shim = pathjoin(options.install_path, "bin", "procname", system, "libprocname.so") if exists(shim): - env['LD_PRELOAD'] = (env.get('LD_PRELOAD', '') + ':' + shim).strip() - env['PROCNAME'] = process_name + env["LD_PRELOAD"] = (env.get("LD_PRELOAD", "") + ":" + shim).strip() + env["PROCNAME"] = process_name return command, env def run(options): if options.process.alive(): - print('Already running as %s' % options.process.read_pid()) + print(f"Already running as {options.process.read_pid()}") return create_app_symlinks(options) @@ -255,7 +255,7 @@ def run(options): def start(options): if options.process.alive(): - print('Already running as %s' % options.process.read_pid()) + print(f"Already running as {options.process.read_pid()}") return create_app_symlinks(options) @@ -270,7 +270,7 @@ def start(options): pid = os.fork() if pid > 0: options.process.write_pid(pid) - print('Started as %s' % pid) + print(f"Started as {pid}") return if hasattr(os, "set_inheritable"): @@ -289,7 +289,7 @@ def start(options): def _terminate(process, signal, message): if not process.alive(): - print('Not running') + print("Not running") return pid = process.read_pid() @@ -299,7 +299,7 @@ def _terminate(process, signal, message): os.kill(pid, signal) except OSError as e: if e.errno != errno.ESRCH: - raise Exception('Signaling pid %s failed: %s' % (pid, e)) + raise Exception(f"Signaling pid {pid} failed: {e}") if not process.alive(): process.clear_pid() @@ -307,15 +307,15 @@ def _terminate(process, signal, message): sleep(0.1) - print('%s %s' % (message, pid)) + print(f"{message} {pid}") def stop(options): - _terminate(options.process, SIGTERM, 'Stopped') + _terminate(options.process, SIGTERM, "Stopped") def kill(options): - _terminate(options.process, SIGKILL, 'Killed') + _terminate(options.process, SIGKILL, "Killed") def restart(options): @@ -325,46 +325,46 @@ def restart(options): def status(options): if not options.process.alive(): - print('Not running') + print("Not running") sys.exit(LSB_NOT_RUNNING) - print('Running as %s' % options.process.read_pid()) + print(f"Running as {options.process.read_pid()}") def create_parser(): - parser = ArgumentParser(prog='launcher', usage='%(prog)s [options] command') - - parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Run verbosely') - parser.add_argument('--etc-dir', metavar='DIR', help='Defaults to INSTALL_PATH/etc') - parser.add_argument('--launcher-config', metavar='FILE', help='Defaults to INSTALL_PATH/bin/launcher.properties') - parser.add_argument('--node-config', metavar='FILE', help='Defaults to ETC_DIR/node.properties') - parser.add_argument('--jvm-config', metavar='FILE', help='Defaults to ETC_DIR/jvm.config') - parser.add_argument('--config', metavar='FILE', help='Defaults to ETC_DIR/config.properties') - parser.add_argument('--log-levels-file', metavar='FILE', help='Defaults to ETC_DIR/log.properties') - parser.add_argument('--data-dir', metavar='DIR', help='Defaults to INSTALL_PATH') - parser.add_argument('--pid-file', metavar='FILE', help='Defaults to DATA_DIR/var/run/launcher.pid') - parser.add_argument('--arg', action='append', metavar='ARG', dest='arguments', help='Add a program argument of the Java application') - parser.add_argument('--launcher-log-file', metavar='FILE', help='Defaults to DATA_DIR/var/log/launcher.log (only in daemon mode)') - parser.add_argument('--server-log-file', metavar='FILE', help='Defaults to DATA_DIR/var/log/server.log (only in daemon mode)') - parser.add_argument('-D', action='append', metavar='NAME=VALUE', dest='properties', help='Set a Java system property') - - commands = parser.add_subparsers(title='commands') - - command_run = commands.add_parser('run', help='run %(prog)s in the foreground') + parser = ArgumentParser(prog="launcher", usage="%(prog)s [options] command") + + parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Run verbosely") + parser.add_argument("--etc-dir", metavar="DIR", help="Defaults to INSTALL_PATH/etc") + parser.add_argument("--launcher-config", metavar="FILE", help="Defaults to INSTALL_PATH/bin/launcher.properties") + parser.add_argument("--node-config", metavar="FILE", help="Defaults to ETC_DIR/node.properties") + parser.add_argument("--jvm-config", metavar="FILE", help="Defaults to ETC_DIR/jvm.config") + parser.add_argument("--config", metavar="FILE", help="Defaults to ETC_DIR/config.properties") + parser.add_argument("--log-levels-file", metavar="FILE", help="Defaults to ETC_DIR/log.properties") + parser.add_argument("--data-dir", metavar="DIR", help="Defaults to INSTALL_PATH") + parser.add_argument("--pid-file", metavar="FILE", help="Defaults to DATA_DIR/var/run/launcher.pid") + parser.add_argument("--arg", action="append", metavar="ARG", dest="arguments", help="Add a program argument of the Java application") + parser.add_argument("--launcher-log-file", metavar="FILE", help="Defaults to DATA_DIR/var/log/launcher.log (only in daemon mode)") + parser.add_argument("--server-log-file", metavar="FILE", help="Defaults to DATA_DIR/var/log/server.log (only in daemon mode)") + parser.add_argument("-D", action="append", metavar="NAME=VALUE", dest="properties", help="Set a Java system property") + + commands = parser.add_subparsers(title="commands") + + command_run = commands.add_parser("run", help="run %(prog)s in the foreground") command_run.set_defaults(command=run) - command_start = commands.add_parser('start', help='start %(prog)s as a daemon') + command_start = commands.add_parser("start", help="start %(prog)s as a daemon") command_start.set_defaults(command=start) - command_stop = commands.add_parser('stop', help='terminate %(prog)s (SIGTERM)') + command_stop = commands.add_parser("stop", help="terminate %(prog)s (SIGTERM)") command_stop.set_defaults(command=stop) - command_kill = commands.add_parser('kill', help='forcibly terminate %(prog)s (SIGKILL)') + command_kill = commands.add_parser("kill", help="forcibly terminate %(prog)s (SIGKILL)") command_kill.set_defaults(command=kill) - command_restart = commands.add_parser('restart', help='stop and then start %(prog)s') + command_restart = commands.add_parser("restart", help="stop and then start %(prog)s") command_restart.set_defaults(command=restart) - command_status = commands.add_parser('status', help='check if %(prog)s is running') + command_status = commands.add_parser("status", help="check if %(prog)s is running") command_status.set_defaults(command=status) return parser @@ -373,15 +373,15 @@ def create_parser(): def parse_properties(parser, args): properties = {} for arg in args: - if '=' not in arg: - parser.error('property is malformed: %s' % arg) - key, value = [i.strip() for i in arg.split('=', 1)] - if key == 'config': - parser.error('cannot specify config using -D option (use --config)') - if key == 'log.path': - parser.error('cannot specify server log using -D option (use --server-log-file)') - if key == 'log.levels-file': - parser.error('cannot specify log levels using -D option (use --log-levels-file)') + if "=" not in arg: + parser.error(f"property is malformed: {arg}") + key, value = [i.strip() for i in arg.split("=", 1)] + if key == "config": + parser.error("cannot specify config using -D option (use --config)") + if key == "log.path": + parser.error("cannot specify server log using -D option (use --server-log-file)") + if key == "log.levels-file": + parser.error("cannot specify log levels using -D option (use --log-levels-file)") properties[key] = value return properties @@ -389,7 +389,7 @@ def parse_properties(parser, args): def print_options(options): if options.verbose: for i in sorted(vars(options)): - print("%-15s = %s" % (i, getattr(options, i))) + print(f"{i:15} = {getattr(options, i)}") print("") @@ -402,40 +402,40 @@ def main(): args = parser.parse_args() - if 'command' not in args: + if "command" not in args: parser.print_help() sys.exit() try: install_path = find_install_path(sys.argv[0]) except Exception as e: - print('ERROR: %s' % e) + print(f"ERROR: {e}") sys.exit(LSB_STATUS_UNKNOWN) options = Options() options.verbose = args.verbose options.install_path = install_path - options.launcher_config = realpath(args.launcher_config or pathjoin(options.install_path, 'bin/launcher.properties')) - options.etc_dir = realpath(args.etc_dir or pathjoin(options.install_path, 'etc')) - options.node_config = realpath(args.node_config or pathjoin(options.etc_dir, 'node.properties')) - options.jvm_config = realpath(args.jvm_config or pathjoin(options.etc_dir, 'jvm.config')) - options.config_path = realpath(args.config or pathjoin(options.etc_dir, 'config.properties')) - options.log_levels = realpath(args.log_levels_file or pathjoin(options.etc_dir, 'log.properties')) + options.launcher_config = realpath(args.launcher_config or pathjoin(options.install_path, "bin/launcher.properties")) + options.etc_dir = realpath(args.etc_dir or pathjoin(options.install_path, "etc")) + options.node_config = realpath(args.node_config or pathjoin(options.etc_dir, "node.properties")) + options.jvm_config = realpath(args.jvm_config or pathjoin(options.etc_dir, "jvm.config")) + options.config_path = realpath(args.config or pathjoin(options.etc_dir, "config.properties")) + options.log_levels = realpath(args.log_levels_file or pathjoin(options.etc_dir, "log.properties")) options.log_levels_set = bool(args.log_levels_file) if args.node_config and not exists(options.node_config): - parser.error('Node config file is missing: %s' % options.node_config) + parser.error(f"Node config file is missing: {options.node_config}") node_properties = {} if exists(options.node_config): node_properties = load_properties(options.node_config) - data_dir = node_properties.get('node.data-dir') + data_dir = node_properties.get("node.data-dir") options.data_dir = realpath(args.data_dir or data_dir or options.install_path) - options.pid_file = realpath(args.pid_file or pathjoin(options.data_dir, 'var/run/launcher.pid')) - options.launcher_log = realpath(args.launcher_log_file or pathjoin(options.data_dir, 'var/log/launcher.log')) - options.server_log = realpath(args.server_log_file or pathjoin(options.data_dir, 'var/log/server.log')) + options.pid_file = realpath(args.pid_file or pathjoin(options.data_dir, "var/run/launcher.pid")) + options.launcher_log = realpath(args.launcher_log_file or pathjoin(options.data_dir, "var/log/launcher.log")) + options.server_log = realpath(args.server_log_file or pathjoin(options.data_dir, "var/log/server.log")) options.properties = parse_properties(parser, args.properties or {}) for k, v in node_properties.items(): @@ -457,9 +457,9 @@ def main(): if options.verbose: traceback.print_exc() else: - print('ERROR: %s' % e) + print(f"ERROR: {e}") sys.exit(LSB_STATUS_UNKNOWN) -if __name__ == '__main__': +if __name__ == "__main__": main()