#!/usr/bin/env python3
# Copyright 2012 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Copies test data files or directories into a given output directory."""

import optparse
import os
import shutil
import sys


class WrongNumberOfArgumentsException(Exception):
    pass


def EscapePath(path):
    """Returns a path with spaces escaped."""
    return path.replace(" ", "\\ ")


def ListFilesForPath(path):
    """Returns a list of all the files under a given path."""
    output = []
    # Ignore revision control metadata directories.
    if os.path.basename(path).startswith('.git') or os.path.basename(
        path
    ).startswith('.svn'):
        return output

    # Files get returned without modification.
    if not os.path.isdir(path):
        output.append(path)
        return output

    # Directories get recursively expanded.
    contents = os.listdir(path)
    for item in contents:
        full_path = os.path.join(path, item)
        output.extend(ListFilesForPath(full_path))
    return output


def CalcInputs(inputs):
    """Computes the full list of input files for a set of command-line arguments."""
    # |inputs| is a list of paths, which may be directories.
    output = []
    for input in inputs:
        output.extend(ListFilesForPath(input))
    return output


def CopyFiles(relative_filenames, output_basedir):
    """Copies files to the given output directory."""
    for file in relative_filenames:
        relative_dirname = os.path.dirname(file)
        output_dir = os.path.join(output_basedir, relative_dirname)
        output_filename = os.path.join(output_basedir, file)

        # In cases where a directory has turned into a file or vice versa, delete it
        # before copying it below.
        if os.path.exists(output_dir) and not os.path.isdir(output_dir):
            os.remove(output_dir)
        if os.path.exists(output_filename) and os.path.isdir(output_filename):
            shutil.rmtree(output_filename)

        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
        shutil.copy(file, output_filename)


def DoMain(argv):
    parser = optparse.OptionParser()
    usage = 'Usage: %prog -o <output_dir> [--inputs] [--outputs] <input_files>'
    parser.set_usage(usage)
    parser.add_option('-o', dest='output_dir')
    parser.add_option('--inputs', action='store_true', dest='list_inputs')
    parser.add_option('--outputs', action='store_true', dest='list_outputs')
    options, arglist = parser.parse_args(argv)

    if len(arglist) == 0:
        raise WrongNumberOfArgumentsException('<input_files> required.')

    files_to_copy = CalcInputs(arglist)
    escaped_files = [EscapePath(x) for x in CalcInputs(arglist)]
    if options.list_inputs:
        return '\n'.join(escaped_files)

    if not options.output_dir:
        raise WrongNumberOfArgumentsException('-o required.')

    if options.list_outputs:
        outputs = [os.path.join(options.output_dir, x) for x in escaped_files]
        return '\n'.join(outputs)

    CopyFiles(files_to_copy, options.output_dir)
    return


def main(argv):
    try:
        result = DoMain(argv[1:])
    except WrongNumberOfArgumentsException as e:
        print(e, file=sys.stderr)
        return 1
    if result:
        print(result)
    return 0


if __name__ == '__main__':
    sys.exit(main(sys.argv))
