#!/usr/bin/env python # Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. import multiprocessing import os import subprocess import sys _DEFAULT_PADDING = 4 class HelperError(Exception): """Exception raised for errors in the helper.""" pass def ZeroPad(number, padding=_DEFAULT_PADDING): """Converts an int into a zero padded string. Args: number(int): The number to convert. padding(int): The number of chars in the output. Note that if you pass for example number=23456 and padding=4, the output will still be '23456', i.e. it will not be cropped. If you pass number=2 and padding=4, the return value will be '0002'. Return: (string): The zero padded number converted to string. """ return str(number).zfill(padding) def RunShellCommand(cmd_list, fail_msg=None): """Executes a command. Args: cmd_list(list): Command list to execute. fail_msg(string): Message describing the error in case the command fails. Return: (string): The standard output from running the command. Raise: HelperError: If command fails. """ process = subprocess.Popen(cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, error = process.communicate() if process.returncode != 0: if fail_msg: print >> sys.stderr, fail_msg raise HelperError('Failed to run %s: command returned %d and printed ' '%s and %s' % (' '.join(cmd_list), process.returncode, output, error)) return output.strip() def PerformActionOnAllFiles(directory, file_pattern, file_extension, start_number, action, **kwargs): """Function that performs a given action on all files matching a pattern. It is assumed that the files are named file_patternxxxx.file_extension, where xxxx are digits starting from start_number. Args: directory(string): The directory where the files live. file_pattern(string): The name pattern of the files. file_extension(string): The files' extension. start_number(int): From where to start to count frames. action(function): The action to be performed over the files. Must return False if the action failed, True otherwise. It should take a file name as the first argument and **kwargs as arguments. The function must be possible to pickle, so it cannot be a bound function (for instance). Return: (bool): Whether performing the action over all files was successful or not. """ file_prefix = os.path.join(directory, file_pattern) file_number = start_number process_pool = multiprocessing.Pool(processes=multiprocessing.cpu_count()) results = [] while True: zero_padded_file_number = ZeroPad(file_number) file_name = file_prefix + zero_padded_file_number + '.' + file_extension if not os.path.isfile(file_name): break future = process_pool.apply_async(action, args=(file_name,), kwds=kwargs) results.append(future) file_number += 1 successful = True for result in results: if not result.get(): print "At least one action %s failed for files %sxxxx.%s." % ( action, file_pattern, file_extension) successful = False process_pool.close() return successful