From f6525825796bdb85ee4b37298da3a41c9010b5aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= <sybren@stuvel.eu> Date: Wed, 15 Mar 2017 18:06:32 +0100 Subject: [PATCH] Added move_to_final command to move an intermediate render dir to the final dir --- flamenco_worker/runner.py | 34 +++++++++++ tests/test_runner_move_to_final.py | 94 ++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 tests/test_runner_move_to_final.py diff --git a/flamenco_worker/runner.py b/flamenco_worker/runner.py index a1027eeb..03a2f28d 100644 --- a/flamenco_worker/runner.py +++ b/flamenco_worker/runner.py @@ -356,6 +356,40 @@ class MoveOutOfWayCommand(AbstractCommand): src.rename(dst) +@command_executor('move_to_final') +class MoveToFinalCommand(AbstractCommand): + def validate(self, settings: dict): + _, err1 = self._setting(settings, 'src', True) + _, err2 = self._setting(settings, 'dest', True) + return err1 or err2 + + async def execute(self, settings: dict): + src = Path(settings['src']) + if not src.exists(): + msg = 'Path %s does not exist, not moving' % src + self._log.info(msg) + await self.worker.register_log('%s: %s', self.command_name, msg) + return + + dest = Path(settings['dest']) + if dest.exists(): + backup = _timestamped_path(dest) + self._log.debug('Destination %s exists, moving out of the way to %s', dest, backup) + + if backup.exists(): + self._log.debug('Destination %s exists, finding one that does not', backup) + backup = _unique_path(backup) + self._log.debug('New destination is %s', backup) + + self._log.info('Moving %s to %s', dest, backup) + await self.worker.register_log('%s: Moving %s to %s', self.command_name, dest, backup) + dest.rename(backup) + + self._log.info('Moving %s to %s', src, dest) + await self.worker.register_log('%s: Moving %s to %s', self.command_name, src, dest) + src.rename(dest) + + @attr.s class AbstractSubprocessCommand(AbstractCommand): readline_timeout = attr.ib(default=SUBPROC_READLINE_TIMEOUT) diff --git a/tests/test_runner_move_to_final.py b/tests/test_runner_move_to_final.py new file mode 100644 index 00000000..fe5b3ce1 --- /dev/null +++ b/tests/test_runner_move_to_final.py @@ -0,0 +1,94 @@ +import os +from pathlib import Path + +from test_runner import AbstractCommandTest + + +class MoveToFinalTest(AbstractCommandTest): + def setUp(self): + super().setUp() + + from flamenco_worker.runner import MoveToFinalCommand + import tempfile + + self.tmpdir = tempfile.TemporaryDirectory() + self.tmppath = Path(self.tmpdir.name) + + self.cmd = MoveToFinalCommand( + worker=self.fworker, + task_id='12345', + command_idx=0, + ) + self.cmd.__attrs_post_init__() + + def tearDown(self): + super().tearDown() + del self.tmpdir + + def test_nonexistant_source(self): + src = self.tmppath / 'nonexistant-dir' + dest = self.tmppath / 'dest' + + task = self.cmd.run({'src': str(src), 'dest': str(dest)}) + ok = self.loop.run_until_complete(task) + + # Should be fine. + self.assertTrue(ok) + self.assertFalse(src.exists()) + self.assertFalse(dest.exists()) + + def test_existing_source_and_dest(self): + src = self.tmppath / 'existing-dir' + src.mkdir() + (src / 'src-contents').touch() + + # Make sure that the destination already exists, with some contents. + dest = self.tmppath / 'dest' + dest.mkdir() + (dest / 'dest-contents').touch() + (dest / 'dest-subdir').mkdir() + (dest / 'dest-subdir' / 'sub-contents').touch() + + os.utime(str(dest), (1330712280, 1330712292)) # fixed (atime, mtime) for testing + + # Run the command. + task = self.cmd.run({'src': str(src), 'dest': str(dest)}) + ok = self.loop.run_until_complete(task) + self.assertTrue(ok) + + renamed_dest = dest.with_name('dest-2012-03-02_191812') + + # old 'dest' contents should exist at 'renamed_dest' + self.assertTrue(renamed_dest.exists()) + self.assertTrue((renamed_dest / 'dest-contents').exists()) + self.assertTrue((renamed_dest / 'dest-subdir').exists()) + self.assertTrue((renamed_dest / 'dest-subdir' / 'sub-contents').exists()) + + # old 'src' contents should exist at 'dest' + self.assertTrue(dest.exists()) + self.assertTrue((dest / 'src-contents').exists()) + + # old 'src' should no longer exist. + self.assertFalse(src.exists()) + + def test_nonexistant_dest(self): + src = self.tmppath / 'existing-dir' + src.mkdir() + (src / 'src-contents').touch() + + dest = self.tmppath / 'dest' + self.assertFalse(dest.exists()) + + task = self.cmd.run({'src': str(src), 'dest': str(dest)}) + ok = self.loop.run_until_complete(task) + self.assertTrue(ok) + + # 'dest-{timestamp}' shouldn't exist. + self.assertFalse(list(self.tmppath.glob('dest-*'))) + + # old 'src' contents should exist at 'dest' + self.assertTrue(dest.exists()) + self.assertTrue((dest / 'src-contents').exists()) + + # old 'src' should no longer exist. + self.assertFalse(src.exists()) -- GitLab