Merge pull request #657 from ddalcino/topic/catch-OSError-n-PermissionError

Catch exceptions when destination directory is not writable/insufficient space
This commit is contained in:
Hiroshi Miura
2023-03-15 07:30:08 +09:00
committed by GitHub
3 changed files with 64 additions and 7 deletions

View File

@@ -102,3 +102,11 @@ class UpdaterError(AqtException):
class OutOfMemory(AqtException): class OutOfMemory(AqtException):
pass pass
class OutOfDiskSpace(AqtException):
pass
class DiskAccessNotPermitted(AqtException):
pass

View File

@@ -22,6 +22,7 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import argparse import argparse
import errno
import gc import gc
import multiprocessing import multiprocessing
import os import os
@@ -47,6 +48,8 @@ from aqt.exceptions import (
ArchiveListError, ArchiveListError,
CliInputError, CliInputError,
CliKeyboardInterrupt, CliKeyboardInterrupt,
DiskAccessNotPermitted,
OutOfDiskSpace,
OutOfMemory, OutOfMemory,
) )
from aqt.helper import ( from aqt.helper import (
@@ -1127,6 +1130,23 @@ def run_installer(archives: List[QtPackage], base_dir: str, sevenzip: Optional[s
pool.starmap(installer, tasks) pool.starmap(installer, tasks)
pool.close() pool.close()
pool.join() pool.join()
except PermissionError as e: # subclass of OSError
close_worker_pool_on_exception(e)
raise DiskAccessNotPermitted(
f"Failed to write to base directory at {base_dir}",
suggested_action=[
"Check that the destination is writable and does not already contain files owned by another user."
],
) from e
except OSError as e:
close_worker_pool_on_exception(e)
if e.errno == errno.ENOSPC:
raise OutOfDiskSpace(
"Insufficient disk space to complete installation.",
suggested_action=["Check available disk space.", "Check size requirements for installation."],
) from e
else:
raise
except KeyboardInterrupt as e: except KeyboardInterrupt as e:
close_worker_pool_on_exception(e) close_worker_pool_on_exception(e)
raise CliKeyboardInterrupt("Installer halted by keyboard interrupt.") from e raise CliKeyboardInterrupt("Installer halted by keyboard interrupt.") from e

View File

@@ -1,3 +1,4 @@
import errno
import hashlib import hashlib
import logging import logging
import os import os
@@ -1156,10 +1157,10 @@ def test_install_nonexistent_archives(monkeypatch, capsys, cmd, xml_file: Option
@pytest.mark.parametrize( @pytest.mark.parametrize(
"exception_class, settings_file, expect_end_msg, expect_return", "exception, settings_file, expect_end_msg, expect_return",
( (
( (
RuntimeError, RuntimeError(),
"../aqt/settings.ini", "../aqt/settings.ini",
"===========================PLEASE FILE A BUG REPORT===========================\n" "===========================PLEASE FILE A BUG REPORT===========================\n"
"You have discovered a bug in aqt.\n" "You have discovered a bug in aqt.\n"
@@ -1168,14 +1169,14 @@ def test_install_nonexistent_archives(monkeypatch, capsys, cmd, xml_file: Option
Cli.UNHANDLED_EXCEPTION_CODE, Cli.UNHANDLED_EXCEPTION_CODE,
), ),
( (
KeyboardInterrupt, KeyboardInterrupt(),
"../aqt/settings.ini", "../aqt/settings.ini",
"WARNING : Caught KeyboardInterrupt, terminating installer workers\n" "WARNING : Caught KeyboardInterrupt, terminating installer workers\n"
"ERROR : Installer halted by keyboard interrupt.", "ERROR : Installer halted by keyboard interrupt.",
1, 1,
), ),
( (
MemoryError, MemoryError(),
"../aqt/settings.ini", "../aqt/settings.ini",
"WARNING : Caught MemoryError, terminating installer workers\n" "WARNING : Caught MemoryError, terminating installer workers\n"
"ERROR : Out of memory when downloading and extracting archives in parallel.\n" "ERROR : Out of memory when downloading and extracting archives in parallel.\n"
@@ -1187,7 +1188,7 @@ def test_install_nonexistent_archives(monkeypatch, capsys, cmd, xml_file: Option
1, 1,
), ),
( (
MemoryError, MemoryError(),
"data/settings_no_concurrency.ini", "data/settings_no_concurrency.ini",
"WARNING : Caught MemoryError, terminating installer workers\n" "WARNING : Caught MemoryError, terminating installer workers\n"
"ERROR : Out of memory when downloading and extracting archives.\n" "ERROR : Out of memory when downloading and extracting archives.\n"
@@ -1197,11 +1198,39 @@ def test_install_nonexistent_archives(monkeypatch, capsys, cmd, xml_file: Option
"(see https://aqtinstall.readthedocs.io/en/latest/cli.html#cmdoption-list-tool-external)", "(see https://aqtinstall.readthedocs.io/en/latest/cli.html#cmdoption-list-tool-external)",
1, 1,
), ),
(
OSError(errno.ENOSPC, "No space left on device"),
"../aqt/settings.ini",
"WARNING : Caught OSError, terminating installer workers\n"
"ERROR : Insufficient disk space to complete installation.\n"
"==============================Suggested follow-up:==============================\n"
"* Check available disk space.\n"
"* Check size requirements for installation.",
1,
),
(
OSError(),
"../aqt/settings.ini",
"===========================PLEASE FILE A BUG REPORT===========================\n"
"You have discovered a bug in aqt.\n"
"Please file a bug report at https://github.com/miurahr/aqtinstall/issues\n"
"Please remember to include a copy of this program's output in your report.",
Cli.UNHANDLED_EXCEPTION_CODE,
),
(
PermissionError(),
"../aqt/settings.ini",
"WARNING : Caught PermissionError, terminating installer workers\n"
f"ERROR : Failed to write to base directory at {os.getcwd()}\n"
"==============================Suggested follow-up:==============================\n"
"* Check that the destination is writable and does not already contain files owned by another user.",
1,
),
), ),
) )
def test_install_pool_exception(monkeypatch, capsys, exception_class, settings_file, expect_end_msg, expect_return): def test_install_pool_exception(monkeypatch, capsys, exception, settings_file, expect_end_msg, expect_return):
def mock_installer_func(*args): def mock_installer_func(*args):
raise exception_class() raise exception
host, target, ver, arch = "windows", "desktop", "6.1.0", "win64_mingw81" host, target, ver, arch = "windows", "desktop", "6.1.0", "win64_mingw81"
updates_url = "windows_x86/desktop/qt6_610/Updates.xml" updates_url = "windows_x86/desktop/qt6_610/Updates.xml"