# Development tool - import command plugin
#
# Copyright (C) 2014-2017 Intel Corporation
#
# SPDX-License-Identifier: GPL-2.0-only
#
"""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.warning('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.warning(pe)
                    else:
                        logger.warning('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.warning('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)
