Browse Source

Use basic restart for Windows binaries

Python 3.9 changed the output of Py_GetArgcArgv on Windows, causing the restart of the binaries to fail.
pull/1763/head
Safihre 4 years ago
parent
commit
ae30f89a2d
  1. 27
      SABnzbd.py
  2. 13
      sabnzbd/misc.py
  3. 11
      sabnzbd/newsunpack.py
  4. 16
      tests/test_misc.py
  5. 16
      tests/test_newsunpack.py

27
SABnzbd.py

@ -1555,31 +1555,34 @@ def main():
# Or special restart cases like Mac and WindowsService # Or special restart cases like Mac and WindowsService
if sabnzbd.TRIGGER_RESTART: if sabnzbd.TRIGGER_RESTART:
logging.info("Performing triggered restart") logging.info("Performing triggered restart")
# Shutdown
sabnzbd.shutdown_program() sabnzbd.shutdown_program()
# Add arguments and make sure we are in the right directory
if sabnzbd.Downloader.paused: if sabnzbd.Downloader.paused:
sabnzbd.RESTART_ARGS.append("-p") sabnzbd.RESTART_ARGS.append("-p")
if autorestarted: if autorestarted:
sabnzbd.RESTART_ARGS.append("--autorestarted") sabnzbd.RESTART_ARGS.append("--autorestarted")
sys.argv = sabnzbd.RESTART_ARGS sys.argv = sabnzbd.RESTART_ARGS
os.chdir(org_dir) os.chdir(org_dir)
# If macOS frozen restart of app instead of embedded python
if hasattr(sys, "frozen") and sabnzbd.DARWIN: # Binaries require special restart
# [[NSProcessInfo processInfo] processIdentifier]] if hasattr(sys, "frozen"):
# logging.info("%s" % (NSProcessInfo.processInfo().processIdentifier())) if sabnzbd.DARWIN:
my_pid = os.getpid() # On macOS restart of app instead of embedded python
my_name = sabnzbd.MY_FULLNAME.replace("/Contents/MacOS/SABnzbd", "") my_name = sabnzbd.MY_FULLNAME.replace("/Contents/MacOS/SABnzbd", "")
my_args = " ".join(sys.argv[1:]) my_args = " ".join(sys.argv[1:])
cmd = 'kill -9 %s && open "%s" --args %s' % (my_pid, my_name, my_args) cmd = 'kill -9 %s && open "%s" --args %s' % (os.getpid(), my_name, my_args)
logging.info("Launching: %s", cmd) logging.info("Launching: %s", cmd)
os.system(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: elif sabnzbd.WIN_SERVICE:
# Use external service handler to do the restart # Use external service handler to do the restart
# Wait 5 seconds to clean up # Wait 5 seconds to clean up
subprocess.Popen("timeout 5 & sc start SABnzbd", shell=True) subprocess.Popen("timeout 5 & sc start SABnzbd", shell=True)
else: else:
# CherryPy has special logic to include interpreter options such as "-OO"
cherrypy.engine._do_execv() cherrypy.engine._do_execv()
# Send our final goodbyes! # Send our final goodbyes!

13
sabnzbd/misc.py

@ -963,6 +963,17 @@ def nntp_to_msg(text: Union[List[AnyStr], str]) -> str:
return ubtou(lines[0]) 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): def build_and_run_command(command: List[str], flatten_command=False, **kwargs):
"""Builds and then runs command with nessecary flags and optional """Builds and then runs command with nessecary flags and optional
IONice and Nice commands. Optional Popen arguments can be supplied. 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"): if command[0].endswith(".py"):
command.insert(0, "python.exe") command.insert(0, "python.exe")
if flatten_command: 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 # On some Windows platforms we need to supress a quick pop-up of the command window
startupinfo = subprocess.STARTUPINFO() startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags = win32process.STARTF_USESHOWWINDOW startupinfo.dwFlags = win32process.STARTF_USESHOWWINDOW

11
sabnzbd/newsunpack.py

@ -2367,17 +2367,6 @@ def pre_queue(nzo: NzbObject, pp, cat):
return values 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): def is_sevenfile(path):
""" Return True if path has proper extension and 7Zip is installed """ """ Return True if path has proper extension and 7Zip is installed """
return SEVEN_COMMAND and os.path.splitext(path)[1].lower() == ".7z" return SEVEN_COMMAND and os.path.splitext(path)[1].lower() == ".7z"

16
tests/test_misc.py

@ -214,6 +214,22 @@ class TestMisc:
os.unlink("test.cert") os.unlink("test.cert")
os.unlink("test.key") 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: class TestBuildAndRunCommand:
# Path should exist # Path should exist

16
tests/test_newsunpack.py

@ -25,22 +25,6 @@ from sabnzbd.newsunpack import *
class TestNewsUnpack: 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): def test_is_sfv_file(self):
assert is_sfv_file("tests/data/good_sfv_unicode.sfv") assert is_sfv_file("tests/data/good_sfv_unicode.sfv")
assert is_sfv_file("tests/data/one_line.sfv") assert is_sfv_file("tests/data/one_line.sfv")

Loading…
Cancel
Save