# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import, print_function, unicode_literals

import argparse
import os
import sys
import time

from mozpack.copier import (
    FileCopier,
    FileRegistry,
)
from mozpack.files import (
    BaseFile,
    FileFinder,
)
from mozpack.manifests import (
    InstallManifest,
)
from mozbuild.util import DefinesAction


COMPLETE = 'Elapsed: {elapsed:.2f}s; From {dest}: Kept {existing} existing; ' \
    'Added/updated {updated}; ' \
    'Removed {rm_files} files and {rm_dirs} directories.'


def process_manifest(destdir, paths, track,
        no_symlinks=False,
        defines={}):

    if os.path.exists(track):
        # We use the same format as install manifests for the tracking
        # data.
        manifest = InstallManifest(path=track)
        remove_unaccounted = FileRegistry()
        dummy_file = BaseFile()

        finder = FileFinder(destdir, find_dotfiles=True)
        for dest in manifest._dests:
            for p, f in finder.find(dest):
                remove_unaccounted.add(p, dummy_file)

        remove_empty_directories=True
        remove_all_directory_symlinks=True

    else:
        # If tracking is enabled and there is no file, we don't want to
        # be removing anything.
        remove_unaccounted = False
        remove_empty_directories=False
        remove_all_directory_symlinks=False

    manifest = InstallManifest()
    for path in paths:
        manifest |= InstallManifest(path=path)

    copier = FileCopier()
    link_policy = "copy" if no_symlinks else "symlink"
    manifest.populate_registry(
        copier, defines_override=defines, link_policy=link_policy
    )
    result = copier.copy(destdir,
        remove_unaccounted=remove_unaccounted,
        remove_all_directory_symlinks=remove_all_directory_symlinks,
        remove_empty_directories=remove_empty_directories)

    if track:
        # We should record files that we actually copied.
        # It is too late to expand wildcards when the track file is read.
        manifest.write(path=track, expand_pattern=True)

    return result


def main(argv):
    parser = argparse.ArgumentParser(
        description='Process install manifest files.')

    parser.add_argument('destdir', help='Destination directory.')
    parser.add_argument('manifests', nargs='+', help='Path to manifest file(s).')
    parser.add_argument('--no-symlinks', action='store_true',
        help='Do not install symbolic links. Always copy files')
    parser.add_argument('--track', metavar="PATH", required=True,
        help='Use installed files tracking information from the given path.')
    parser.add_argument('-D', action=DefinesAction,
        dest='defines', metavar="VAR[=VAL]",
        help='Define a variable to override what is specified in the manifest')

    args = parser.parse_args(argv)

    start = time.time()

    result = process_manifest(args.destdir, args.manifests,
        track=args.track,
        no_symlinks=args.no_symlinks,
        defines=args.defines)

    elapsed = time.time() - start

    print(COMPLETE.format(
        elapsed=elapsed,
        dest=args.destdir,
        existing=result.existing_files_count,
        updated=result.updated_files_count,
        rm_files=result.removed_files_count,
        rm_dirs=result.removed_directories_count))

if __name__ == '__main__':
    main(sys.argv[1:])
