diff --git a/packages/flamenco/flamenco/job_compilers/blender_render.py b/packages/flamenco/flamenco/job_compilers/blender_render.py index 98ef0d4dce6405013c8f96c61682305ae5d53c4a..65a464d4da5340a1500bf3a8151163dabfddbb82 100644 --- a/packages/flamenco/flamenco/job_compilers/blender_render.py +++ b/packages/flamenco/flamenco/job_compilers/blender_render.py @@ -7,10 +7,41 @@ class BlenderRender(AbstractJobCompiler): """Basic Blender render job.""" def compile(self, job): - from flamenco.utils import iter_frame_range, frame_range_merge - self._log.info('Compiling job %s', job['_id']) + move_existing_task_id = self._make_move_out_of_way_task(job) + task_count = 1 + self._make_render_tasks(job, move_existing_task_id) + + self._log.info('Created %i tasks for job %s', task_count, job['_id']) + + def _make_move_out_of_way_task(self, job): + """Creates a MoveOutOfWay command to back up existing frames, and wraps it in a task. + + :returns: the ObjectId of the created task. + :rtype: bson.ObjectId + """ + + import os.path + + # The render path contains a filename pattern, most likely '######' or + # something similar. This has to be removed, so that we end up with + # the directory that will contain the frames. + render_dest_dir = os.path.dirname(job['settings']['render_output']) + cmd = commands.MoveOutOfWay(src=render_dest_dir) + + task_id = self.task_manager.api_create_task( + job, [cmd], 'move-existing-frames') + + return task_id + + def _make_render_tasks(self, job, parent_task_id): + """Creates the render tasks for this job. + + :returns: the number of tasks created + :rtype: int + """ + from flamenco.utils import iter_frame_range, frame_range_merge + job_settings = job['settings'] task_count = 0 @@ -28,7 +59,7 @@ class BlenderRender(AbstractJobCompiler): ] name = 'blender-render-%s' % frame_range - self.task_manager.api_create_task(job, task_cmds, name) + self.task_manager.api_create_task(job, task_cmds, name, parents=[parent_task_id]) task_count += 1 - self._log.info('Created %i tasks for job %s', task_count, job['_id']) + return task_count diff --git a/packages/flamenco/flamenco/job_compilers/commands.py b/packages/flamenco/flamenco/job_compilers/commands.py index 40254d19f46a37a21deeedc5e9baee0959af693c..1bd8df2d49729a4561131ce05d41d005ba2f0b0f 100644 --- a/packages/flamenco/flamenco/job_compilers/commands.py +++ b/packages/flamenco/flamenco/job_compilers/commands.py @@ -48,3 +48,16 @@ class BlenderRender(AbstractCommand): # list of frames to render, as frame range string. frames = attr.ib(validator=attr.validators.instance_of(unicode)) + + +@attr.s +class MoveOutOfWay(AbstractCommand): + """Moves a file or directory out of the way. + + The destination is the same as the source, with the source's modification + timestamp appended to it. + + :ivar src: source path + """ + + src = attr.ib(validator=attr.validators.instance_of(unicode)) diff --git a/packages/flamenco/tests/test_job_manager.py b/packages/flamenco/tests/test_job_manager.py index b2cafb92e55c714943d0f403b86eed5148c5d9c3..f2a266d2bd859cfa288d5d28589e4c3913b6d84e 100644 --- a/packages/flamenco/tests/test_job_manager.py +++ b/packages/flamenco/tests/test_job_manager.py @@ -87,6 +87,7 @@ class JobStatusChangeTest(AbstractFlamencoTest): 'frames': u'12-18, 20-25', 'chunk_size': 2, 'time_in_seconds': 3, + 'render_output': u'/not-relevant-now/####', }, self.proj_id, ctd.EXAMPLE_PROJECT_OWNER_ID, @@ -96,7 +97,10 @@ class JobStatusChangeTest(AbstractFlamencoTest): # Fetch the task IDs and set the task statuses to a fixed list. tasks_coll = self.flamenco.db('tasks') - tasks = tasks_coll.find({'job': self.job_id}, projection={'_id': 1}) + tasks = tasks_coll.find({ + 'job': self.job_id, + 'name': {'$regex': '^blender-render-'}, # don't consider move-out-of-way task. + }, projection={'_id': 1}) self.task_ids = [task['_id'] for task in tasks] self.assertEqual(len(tasks_schema['status']['allowed']), len(self.task_ids))