1#!/usr/bin/env python3 2# Copyright 2012 The Chromium Authors 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6"""Copies test data files or directories into a given output directory.""" 7 8 9import optparse 10import os 11import shutil 12import sys 13 14class WrongNumberOfArgumentsException(Exception): 15 pass 16 17def EscapePath(path): 18 """Returns a path with spaces escaped.""" 19 return path.replace(" ", "\\ ") 20 21def ListFilesForPath(path): 22 """Returns a list of all the files under a given path.""" 23 output = [] 24 # Ignore revision control metadata directories. 25 if (os.path.basename(path).startswith('.git') or 26 os.path.basename(path).startswith('.svn')): 27 return output 28 29 # Files get returned without modification. 30 if not os.path.isdir(path): 31 output.append(path) 32 return output 33 34 # Directories get recursively expanded. 35 contents = os.listdir(path) 36 for item in contents: 37 full_path = os.path.join(path, item) 38 output.extend(ListFilesForPath(full_path)) 39 return output 40 41def CalcInputs(inputs): 42 """Computes the full list of input files for a set of command-line arguments. 43 """ 44 # |inputs| is a list of paths, which may be directories. 45 output = [] 46 for input in inputs: 47 output.extend(ListFilesForPath(input)) 48 return output 49 50def CopyFiles(relative_filenames, output_basedir): 51 """Copies files to the given output directory.""" 52 for file in relative_filenames: 53 relative_dirname = os.path.dirname(file) 54 output_dir = os.path.join(output_basedir, relative_dirname) 55 output_filename = os.path.join(output_basedir, file) 56 57 # In cases where a directory has turned into a file or vice versa, delete it 58 # before copying it below. 59 if os.path.exists(output_dir) and not os.path.isdir(output_dir): 60 os.remove(output_dir) 61 if os.path.exists(output_filename) and os.path.isdir(output_filename): 62 shutil.rmtree(output_filename) 63 64 if not os.path.exists(output_dir): 65 os.makedirs(output_dir) 66 shutil.copy(file, output_filename) 67 68def DoMain(argv): 69 parser = optparse.OptionParser() 70 usage = 'Usage: %prog -o <output_dir> [--inputs] [--outputs] <input_files>' 71 parser.set_usage(usage) 72 parser.add_option('-o', dest='output_dir') 73 parser.add_option('--inputs', action='store_true', dest='list_inputs') 74 parser.add_option('--outputs', action='store_true', dest='list_outputs') 75 options, arglist = parser.parse_args(argv) 76 77 if len(arglist) == 0: 78 raise WrongNumberOfArgumentsException('<input_files> required.') 79 80 files_to_copy = CalcInputs(arglist) 81 escaped_files = [EscapePath(x) for x in CalcInputs(arglist)] 82 if options.list_inputs: 83 return '\n'.join(escaped_files) 84 85 if not options.output_dir: 86 raise WrongNumberOfArgumentsException('-o required.') 87 88 if options.list_outputs: 89 outputs = [os.path.join(options.output_dir, x) for x in escaped_files] 90 return '\n'.join(outputs) 91 92 CopyFiles(files_to_copy, options.output_dir) 93 return 94 95def main(argv): 96 try: 97 result = DoMain(argv[1:]) 98 except WrongNumberOfArgumentsException as e: 99 print(e, file=sys.stderr) 100 return 1 101 if result: 102 print(result) 103 return 0 104 105if __name__ == '__main__': 106 sys.exit(main(sys.argv)) 107