145 lines
6.2 KiB
Python
145 lines
6.2 KiB
Python
|
# 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)
|