# Development tool - import command plugin
#
# Copyright (C) 2014-2017 Intel Corporation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""Devtool import plugin"""

import os
import tarfile
import logging
import collections
import json
import fnmatch

from devtool import standard, setup_tinfoil, replace_from_file, DevtoolError
from devtool import export

logger = logging.getLogger('devtool')

def devimport(args, config, basepath, workspace):
    """Entry point for the devtool 'import' subcommand"""

    def get_pn(name):
        """ Returns the filename of a workspace recipe/append"""
        metadata = name.split('/')[-1]
        fn, _ = os.path.splitext(metadata)
        return fn

    if not os.path.exists(args.file):
        raise DevtoolError('Tar archive %s does not exist. Export your workspace using "devtool export"' % args.file)

    with tarfile.open(args.file) as tar:
        # Get exported metadata
        export_workspace_path = export_workspace = None
        try:
            metadata = tar.getmember(export.metadata)
        except KeyError as ke:
            raise DevtoolError('The export metadata file created by "devtool export" was not found. "devtool import" can only be used to import tar archives created by "devtool export".')

        tar.extract(metadata)
        with open(metadata.name) as fdm:
            export_workspace_path, export_workspace = json.load(fdm)
        os.unlink(metadata.name)

        members = tar.getmembers()

        # Get appends and recipes from the exported archive, these
        # will be needed to find out those appends without corresponding
        # recipe pair
        append_fns, recipe_fns = set(), set()
        for member in members:
            if member.name.startswith('appends'):
                append_fns.add(get_pn(member.name))
            elif member.name.startswith('recipes'):
                recipe_fns.add(get_pn(member.name))

        # Setup tinfoil, get required data and shutdown
        tinfoil = setup_tinfoil(config_only=False, basepath=basepath)
        try:
            current_fns = [os.path.basename(recipe[0]) for recipe in tinfoil.cooker.recipecaches[''].pkg_fn.items()]
        finally:
            tinfoil.shutdown()

        # Find those appends that do not have recipes in current metadata
        non_importables = []
        for fn in append_fns - recipe_fns:
            # Check on current metadata (covering those layers indicated in bblayers.conf)
            for current_fn in current_fns:
                if fnmatch.fnmatch(current_fn, '*' + fn.replace('%', '') + '*'):
                    break
            else:
                non_importables.append(fn)
                logger.warn('No recipe to append %s.bbapppend, skipping' % fn)

        # Extract
        imported = []
        for member in members:
            if member.name == export.metadata:
                continue

            for nonimp in non_importables:
                pn = nonimp.split('_')[0]
                # do not extract data from non-importable recipes or metadata
                if member.name.startswith('appends/%s' % nonimp) or \
                        member.name.startswith('recipes/%s' % nonimp) or \
                        member.name.startswith('sources/%s' % pn):
                    break
            else:
                path = os.path.join(config.workspace_path, member.name)
                if os.path.exists(path):
                    # by default, no file overwrite is done unless -o is given by the user
                    if args.overwrite:
                        try:
                            tar.extract(member, path=config.workspace_path)
                        except PermissionError as pe:
                            logger.warn(pe)
                    else:
                        logger.warn('File already present. Use --overwrite/-o to overwrite it: %s' % member.name)
                        continue
                else:
                    tar.extract(member, path=config.workspace_path)

                # Update EXTERNALSRC and the devtool md5 file
                if member.name.startswith('appends'):
                    if export_workspace_path:
                        # appends created by 'devtool modify' just need to update the workspace
                        replace_from_file(path, export_workspace_path, config.workspace_path)

                        # appends created by 'devtool add' need replacement of exported source tree
                        pn = get_pn(member.name).split('_')[0]
                        exported_srctree = export_workspace[pn]['srctree']
                        if exported_srctree:
                            replace_from_file(path, exported_srctree, os.path.join(config.workspace_path, 'sources', pn))

                    standard._add_md5(config, pn, path)
                    imported.append(pn)

    if imported:
        logger.info('Imported recipes into workspace %s: %s' % (config.workspace_path, ', '.join(imported)))
    else:
        logger.warn('No recipes imported into the workspace')

    return 0

def register_commands(subparsers, context):
    """Register devtool import subcommands"""
    parser = subparsers.add_parser('import',
                                   help='Import exported tar archive into workspace',
                                   description='Import tar archive previously created by "devtool export" into workspace',
                                   group='advanced')
    parser.add_argument('file', metavar='FILE', help='Name of the tar archive to import')
    parser.add_argument('--overwrite', '-o', action="store_true", help='Overwrite files when extracting')
    parser.set_defaults(func=devimport)
