diff --git a/hate_crack/main.py b/hate_crack/main.py index 9c8c51b..c2f1b70 100755 --- a/hate_crack/main.py +++ b/hate_crack/main.py @@ -811,6 +811,38 @@ def ascii_art(): ) +def _run_upgrade(): + """Run `git pull && make clean && make && make install` in the repo root.""" + import subprocess + + print() + # Find the actual git repo root - _repo_root may point to + # site-packages when installed rather than the source checkout. + git_root_result = subprocess.run( + ["git", "rev-parse", "--show-toplevel"], + cwd=_repo_root, + capture_output=True, + text=True, + ) + if git_root_result.returncode != 0: + print( + "\n Could not find a git repository to upgrade from." + "\n Run manually: git pull && make clean && make && make install\n" + ) + raise SystemExit(1) + repo_root = git_root_result.stdout.strip() + result = subprocess.run( + "git pull && make clean && make && make install", + shell=True, + cwd=repo_root, + ) + if result.returncode == 0: + print("\n Upgrade complete. Please restart hate_crack.\n") + else: + print("\n Upgrade failed. Check the output above for errors.\n") + raise SystemExit(0) + + def check_for_updates(): """Check GitHub for a newer release and print a notice if one exists.""" try: @@ -842,34 +874,7 @@ def check_for_updates(): print() return if answer == "y": - import subprocess - - print() - # Find the actual git repo root - _repo_root may point to - # site-packages when installed rather than the source checkout. - git_root_result = subprocess.run( - ["git", "rev-parse", "--show-toplevel"], - cwd=_repo_root, - capture_output=True, - text=True, - ) - if git_root_result.returncode != 0: - print( - "\n Could not find a git repository to upgrade from." - "\n Run manually: git pull && make clean && make && make install\n" - ) - raise SystemExit(1) - repo_root = git_root_result.stdout.strip() - result = subprocess.run( - "git pull && make clean && make && make install", - shell=True, - cwd=repo_root, - ) - if result.returncode == 0: - print("\n Upgrade complete. Please restart hate_crack.\n") - else: - print("\n Upgrade failed. Check the output above for errors.\n") - raise SystemExit(0) + _run_upgrade() except Exception: pass @@ -4159,6 +4164,11 @@ def main(): action="store_true", help="Cleanup .out files, torrents, and extract or remove .7z archives", ) + parser.add_argument( + "--update", + action="store_true", + help="Pull latest changes and reinstall (git pull && make clean && make && make install)", + ) parser.add_argument("--debug", action="store_true", help="Enable debug mode") parser.add_argument( "--potfile-path", @@ -4341,6 +4351,9 @@ def main(): maxruntime = config.maxruntime bandrelbasewords = config.bandrelbasewords + if args.update: + _run_upgrade() + if args.download_torrent: download_weakpass_torrent( download_torrent=download_torrent_file, diff --git a/tests/test_version_check.py b/tests/test_version_check.py index ce06f34..c79aed2 100644 --- a/tests/test_version_check.py +++ b/tests/test_version_check.py @@ -212,6 +212,57 @@ class TestCheckForUpdates: output = capsys.readouterr().out assert "Run manually" in output + +class TestRunUpgrade: + """Tests for _run_upgrade() called directly via --update flag.""" + + def test_run_upgrade_success(self, hc_module, capsys): + git_root_proc = MagicMock() + git_root_proc.returncode = 0 + git_root_proc.stdout = "/fake/repo\n" + + make_proc = MagicMock() + make_proc.returncode = 0 + + with patch("subprocess.run", side_effect=[git_root_proc, make_proc]) as mock_run, pytest.raises(SystemExit) as exc: + hc_module._run_upgrade() + + assert exc.value.code == 0 + assert mock_run.call_count == 2 + make_cmd = mock_run.call_args_list[1][0][0] + assert "git pull" in make_cmd + assert "make install" in make_cmd + assert mock_run.call_args_list[1][1]["cwd"] == "/fake/repo" + output = capsys.readouterr().out + assert "Upgrade complete" in output + + def test_run_upgrade_make_failure(self, hc_module, capsys): + git_root_proc = MagicMock() + git_root_proc.returncode = 0 + git_root_proc.stdout = "/fake/repo\n" + + make_proc = MagicMock() + make_proc.returncode = 1 + + with patch("subprocess.run", side_effect=[git_root_proc, make_proc]), pytest.raises(SystemExit) as exc: + hc_module._run_upgrade() + + assert exc.value.code == 0 + output = capsys.readouterr().out + assert "Upgrade failed" in output + + def test_run_upgrade_no_git_repo(self, hc_module, capsys): + git_root_proc = MagicMock() + git_root_proc.returncode = 128 + git_root_proc.stdout = "" + + with patch("subprocess.run", return_value=git_root_proc), pytest.raises(SystemExit) as exc: + hc_module._run_upgrade() + + assert exc.value.code == 1 + output = capsys.readouterr().out + assert "Run manually" in output + def test_upgrade_prompt_ctrl_c_continues(self, hc_module, capsys): mock_resp = MagicMock() mock_resp.json.return_value = {"tag_name": "v99.0.0"}