diff --git a/SABnzbd.py b/SABnzbd.py index 9e0b012..c10f7c2 100755 --- a/SABnzbd.py +++ b/SABnzbd.py @@ -1555,31 +1555,34 @@ def main(): # Or special restart cases like Mac and WindowsService if sabnzbd.TRIGGER_RESTART: logging.info("Performing triggered restart") - # Shutdown sabnzbd.shutdown_program() + # Add arguments and make sure we are in the right directory if sabnzbd.Downloader.paused: sabnzbd.RESTART_ARGS.append("-p") if autorestarted: sabnzbd.RESTART_ARGS.append("--autorestarted") sys.argv = sabnzbd.RESTART_ARGS - os.chdir(org_dir) - # If macOS frozen restart of app instead of embedded python - if hasattr(sys, "frozen") and sabnzbd.DARWIN: - # [[NSProcessInfo processInfo] processIdentifier]] - # logging.info("%s" % (NSProcessInfo.processInfo().processIdentifier())) - my_pid = os.getpid() - my_name = sabnzbd.MY_FULLNAME.replace("/Contents/MacOS/SABnzbd", "") - my_args = " ".join(sys.argv[1:]) - cmd = 'kill -9 %s && open "%s" --args %s' % (my_pid, my_name, my_args) - logging.info("Launching: %s", cmd) - os.system(cmd) + + # Binaries require special restart + if hasattr(sys, "frozen"): + if sabnzbd.DARWIN: + # On macOS restart of app instead of embedded python + my_name = sabnzbd.MY_FULLNAME.replace("/Contents/MacOS/SABnzbd", "") + my_args = " ".join(sys.argv[1:]) + cmd = 'kill -9 %s && open "%s" --args %s' % (os.getpid(), my_name, my_args) + logging.info("Launching: %s", cmd) + os.system(cmd) + elif sabnzbd.WIN32: + # Just a simple restart of the exe + os.execv(sys.executable, ['"%s"' % arg for arg in sys.argv]) elif sabnzbd.WIN_SERVICE: # Use external service handler to do the restart # Wait 5 seconds to clean up subprocess.Popen("timeout 5 & sc start SABnzbd", shell=True) else: + # CherryPy has special logic to include interpreter options such as "-OO" cherrypy.engine._do_execv() # Send our final goodbyes! diff --git a/sabnzbd/misc.py b/sabnzbd/misc.py index f447a4a..942860e 100644 --- a/sabnzbd/misc.py +++ b/sabnzbd/misc.py @@ -963,6 +963,17 @@ def nntp_to_msg(text: Union[List[AnyStr], str]) -> str: return ubtou(lines[0]) +def list2cmdline(lst: List[str]) -> str: + """ convert list to a cmd.exe-compatible command string """ + nlst = [] + for arg in lst: + if not arg: + nlst.append('""') + else: + nlst.append('"%s"' % arg) + return " ".join(nlst) + + def build_and_run_command(command: List[str], flatten_command=False, **kwargs): """Builds and then runs command with nessecary flags and optional IONice and Nice commands. Optional Popen arguments can be supplied. @@ -1000,7 +1011,7 @@ def build_and_run_command(command: List[str], flatten_command=False, **kwargs): if command[0].endswith(".py"): command.insert(0, "python.exe") if flatten_command: - command = sabnzbd.newsunpack.list2cmdline(command) + command = list2cmdline(command) # On some Windows platforms we need to supress a quick pop-up of the command window startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags = win32process.STARTF_USESHOWWINDOW diff --git a/sabnzbd/newsunpack.py b/sabnzbd/newsunpack.py index 6e6f314..abf1b0d 100644 --- a/sabnzbd/newsunpack.py +++ b/sabnzbd/newsunpack.py @@ -2367,17 +2367,6 @@ def pre_queue(nzo: NzbObject, pp, cat): return values -def list2cmdline(lst): - """ convert list to a cmd.exe-compatible command string """ - nlst = [] - for arg in lst: - if not arg: - nlst.append('""') - else: - nlst.append('"%s"' % arg) - return " ".join(nlst) - - def is_sevenfile(path): """ Return True if path has proper extension and 7Zip is installed """ return SEVEN_COMMAND and os.path.splitext(path)[1].lower() == ".7z" diff --git a/tests/test_misc.py b/tests/test_misc.py index 1b3fb50..87a5e4a 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -214,6 +214,22 @@ class TestMisc: os.unlink("test.cert") os.unlink("test.key") + @pytest.mark.parametrize( + "test_input, expected_output", + [ + (["cmd1", 9, "cmd3"], '"cmd1" "9" "cmd3"'), # sending all commands as valid string + (["", "cmd1", "5"], '"" "cmd1" "5"'), # sending blank string + (["cmd1", None, "cmd3", "tail -f"], '"cmd1" "" "cmd3" "tail -f"'), # sending None in command + (["cmd1", 0, "ps ux"], '"cmd1" "" "ps ux"'), # sending 0 + ], + ) + def test_list_to_cmd(self, test_input, expected_output): + """ Test to convert list to a cmd.exe-compatible command string """ + + res = misc.list2cmdline(test_input) + # Make sure the output is cmd.exe-compatible + assert res == expected_output + class TestBuildAndRunCommand: # Path should exist diff --git a/tests/test_newsunpack.py b/tests/test_newsunpack.py index 86a7b85..8f5b924 100644 --- a/tests/test_newsunpack.py +++ b/tests/test_newsunpack.py @@ -25,22 +25,6 @@ from sabnzbd.newsunpack import * class TestNewsUnpack: - @pytest.mark.parametrize( - "test_input, expected_output", - [ - (["cmd1", 9, "cmd3"], '"cmd1" "9" "cmd3"'), # sending all commands as valid string - (["", "cmd1", "5"], '"" "cmd1" "5"'), # sending blank string - (["cmd1", None, "cmd3", "tail -f"], '"cmd1" "" "cmd3" "tail -f"'), # sending None in command - (["cmd1", 0, "ps ux"], '"cmd1" "" "ps ux"'), # sending 0 - ], - ) - def test_list_to_cmd(self, test_input, expected_output): - """ Test to convert list to a cmd.exe-compatible command string """ - - res = list2cmdline(test_input) - # Make sure the output is cmd.exe-compatible - assert res == expected_output - def test_is_sfv_file(self): assert is_sfv_file("tests/data/good_sfv_unicode.sfv") assert is_sfv_file("tests/data/one_line.sfv")