commit: 7b8f57335c43054fe4008b7401d6ac2b3f710c1a Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Wed Nov 6 08:03:36 2019 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Wed Nov 6 20:05:27 2019 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=7b8f5733
FileCopier: capture exceptions Use ForkExecutor to capture exceptions instead of showing a full traceback. FileCopier callers will now be responsible for displaying relevant exception messages. Bug: https://bugs.gentoo.org/699400 Signed-off-by: Zac Medico <zmedico <AT> gentoo.org> lib/portage/tests/util/test_file_copier.py | 44 ++++++++++++++++++++++++++++++ lib/portage/util/_async/FileCopier.py | 16 ++++++----- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/lib/portage/tests/util/test_file_copier.py b/lib/portage/tests/util/test_file_copier.py new file mode 100644 index 000000000..01dfba494 --- /dev/null +++ b/lib/portage/tests/util/test_file_copier.py @@ -0,0 +1,44 @@ +# Copyright 2019 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +import errno +import os +import shutil +import tempfile + +from portage.tests import TestCase +from portage.util._async.FileCopier import FileCopier +from portage.util._eventloop.global_event_loop import global_event_loop + + +class FileCopierTestCase(TestCase): + + def testFileCopier(self): + loop = global_event_loop() + tempdir = tempfile.mkdtemp() + try: + + # regular successful copy + src_path = os.path.join(tempdir, 'src') + dest_path = os.path.join(tempdir, 'dest') + content = b'foo' + with open(src_path, 'wb') as f: + f.write(content) + copier = FileCopier(src_path=src_path, dest_path=dest_path, scheduler=loop) + copier.start() + loop.run_until_complete(copier.async_wait()) + self.assertEqual(copier.returncode, 0) + copier.future.result() + with open(dest_path, 'rb') as f: + self.assertEqual(f.read(), content) + + # failure due to nonexistent src_path + src_path = os.path.join(tempdir, 'does-not-exist') + copier = FileCopier(src_path=src_path, dest_path=dest_path, scheduler=loop) + copier.start() + loop.run_until_complete(copier.async_wait()) + self.assertEqual(copier.returncode, 1) + self.assertEqual(copier.future.exception().errno, errno.ENOENT) + self.assertEqual(copier.future.exception().filename, src_path.encode('utf8')) + finally: + shutil.rmtree(tempdir) diff --git a/lib/portage/util/_async/FileCopier.py b/lib/portage/util/_async/FileCopier.py index 27e5ab4c0..3a0be4b63 100644 --- a/lib/portage/util/_async/FileCopier.py +++ b/lib/portage/util/_async/FileCopier.py @@ -1,17 +1,19 @@ -# Copyright 2013 Gentoo Foundation +# Copyright 2013-2019 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 -from portage import os from portage import shutil -from portage.util._async.ForkProcess import ForkProcess +from portage.util.futures import asyncio +from portage.util.futures.executor.fork import ForkExecutor +from portage.util._async.AsyncTaskFuture import AsyncTaskFuture -class FileCopier(ForkProcess): +class FileCopier(AsyncTaskFuture): """ Asynchronously copy a file. """ __slots__ = ('src_path', 'dest_path') - def _run(self): - shutil.copy(self.src_path, self.dest_path) - return os.EX_OK + def _start(self): + self.future = asyncio.ensure_future(self.scheduler.run_in_executor(ForkExecutor(loop=self.scheduler), + shutil.copy, self.src_path, self.dest_path)) + super(FileCopier, self)._start()