summaryrefslogtreecommitdiffstats
path: root/scripts/lib
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib')
-rw-r--r--scripts/lib/devtool/__init__.py36
-rw-r--r--scripts/lib/devtool/import.py144
2 files changed, 180 insertions, 0 deletions
diff --git a/scripts/lib/devtool/__init__.py b/scripts/lib/devtool/__init__.py
index b231e46b16..14170cb69e 100644
--- a/scripts/lib/devtool/__init__.py
+++ b/scripts/lib/devtool/__init__.py
@@ -261,3 +261,39 @@ def get_bbclassextend_targets(recipefile, pn):
261 targets.append('%s-%s' % (pn, variant)) 261 targets.append('%s-%s' % (pn, variant))
262 return targets 262 return targets
263 263
264def replace_from_file(path, old, new):
265 """Replace strings on a file"""
266
267 def read_file(path):
268 data = None
269 with open(path) as f:
270 data = f.read()
271 return data
272
273 def write_file(path, data):
274 if data is None:
275 return
276 wdata = data.rstrip() + "\n"
277 with open(path, "w") as f:
278 f.write(wdata)
279
280 # In case old is None, return immediately
281 if old is None:
282 return
283 try:
284 rdata = read_file(path)
285 except IOError as e:
286 # if file does not exit, just quit, otherwise raise an exception
287 if e.errno == errno.ENOENT:
288 return
289 else:
290 raise
291
292 old_contents = rdata.splitlines()
293 new_contents = []
294 for old_content in old_contents:
295 try:
296 new_contents.append(old_content.replace(old, new))
297 except ValueError:
298 pass
299 write_file(path, "\n".join(new_contents))
diff --git a/scripts/lib/devtool/import.py b/scripts/lib/devtool/import.py
new file mode 100644
index 0000000000..c13a180d14
--- /dev/null
+++ b/scripts/lib/devtool/import.py
@@ -0,0 +1,144 @@
1# Development tool - import command plugin
2#
3# Copyright (C) 2014-2017 Intel Corporation
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 2 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc.,
16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17"""Devtool import plugin"""
18
19import os
20import tarfile
21import logging
22import collections
23import json
24import fnmatch
25
26from devtool import standard, setup_tinfoil, replace_from_file, DevtoolError
27from devtool import export
28
29logger = logging.getLogger('devtool')
30
31def devimport(args, config, basepath, workspace):
32 """Entry point for the devtool 'import' subcommand"""
33
34 def get_pn(name):
35 """ Returns the filename of a workspace recipe/append"""
36 metadata = name.split('/')[-1]
37 fn, _ = os.path.splitext(metadata)
38 return fn
39
40 if not os.path.exists(args.file):
41 raise DevtoolError('Tar archive %s does not exist. Export your workspace using "devtool export"' % args.file)
42
43 with tarfile.open(args.file) as tar:
44 # Get exported metadata
45 export_workspace_path = export_workspace = None
46 try:
47 metadata = tar.getmember(export.metadata)
48 except KeyError as ke:
49 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".')
50
51 tar.extract(metadata)
52 with open(metadata.name) as fdm:
53 export_workspace_path, export_workspace = json.load(fdm)
54 os.unlink(metadata.name)
55
56 members = tar.getmembers()
57
58 # Get appends and recipes from the exported archive, these
59 # will be needed to find out those appends without corresponding
60 # recipe pair
61 append_fns, recipe_fns = set(), set()
62 for member in members:
63 if member.name.startswith('appends'):
64 append_fns.add(get_pn(member.name))
65 elif member.name.startswith('recipes'):
66 recipe_fns.add(get_pn(member.name))
67
68 # Setup tinfoil, get required data and shutdown
69 tinfoil = setup_tinfoil(config_only=False, basepath=basepath)
70 try:
71 current_fns = [os.path.basename(recipe[0]) for recipe in tinfoil.cooker.recipecaches[''].pkg_fn.items()]
72 finally:
73 tinfoil.shutdown()
74
75 # Find those appends that do not have recipes in current metadata
76 non_importables = []
77 for fn in append_fns - recipe_fns:
78 # Check on current metadata (covering those layers indicated in bblayers.conf)
79 for current_fn in current_fns:
80 if fnmatch.fnmatch(current_fn, '*' + fn.replace('%', '') + '*'):
81 break
82 else:
83 non_importables.append(fn)
84 logger.warn('No recipe to append %s.bbapppend, skipping' % fn)
85
86 # Extract
87 imported = []
88 for member in members:
89 if member.name == export.metadata:
90 continue
91
92 for nonimp in non_importables:
93 pn = nonimp.split('_')[0]
94 # do not extract data from non-importable recipes or metadata
95 if member.name.startswith('appends/%s' % nonimp) or \
96 member.name.startswith('recipes/%s' % nonimp) or \
97 member.name.startswith('sources/%s' % pn):
98 break
99 else:
100 path = os.path.join(config.workspace_path, member.name)
101 if os.path.exists(path):
102 # by default, no file overwrite is done unless -o is given by the user
103 if args.overwrite:
104 try:
105 tar.extract(member, path=config.workspace_path)
106 except PermissionError as pe:
107 logger.warn(pe)
108 else:
109 logger.warn('File already present. Use --overwrite/-o to overwrite it: %s' % member.name)
110 continue
111 else:
112 tar.extract(member, path=config.workspace_path)
113
114 # Update EXTERNALSRC and the devtool md5 file
115 if member.name.startswith('appends'):
116 if export_workspace_path:
117 # appends created by 'devtool modify' just need to update the workspace
118 replace_from_file(path, export_workspace_path, config.workspace_path)
119
120 # appends created by 'devtool add' need replacement of exported source tree
121 pn = get_pn(member.name).split('_')[0]
122 exported_srctree = export_workspace[pn]['srctree']
123 if exported_srctree:
124 replace_from_file(path, exported_srctree, os.path.join(config.workspace_path, 'sources', pn))
125
126 standard._add_md5(config, pn, path)
127 imported.append(pn)
128
129 if imported:
130 logger.info('Imported recipes into workspace %s: %s' % (config.workspace_path, ', '.join(imported)))
131 else:
132 logger.warn('No recipes imported into the workspace')
133
134 return 0
135
136def register_commands(subparsers, context):
137 """Register devtool import subcommands"""
138 parser = subparsers.add_parser('import',
139 help='Import exported tar archive into workspace',
140 description='Import tar archive previously created by "devtool export" into workspace',
141 group='advanced')
142 parser.add_argument('file', metavar='FILE', help='Name of the tar archive to import')
143 parser.add_argument('--overwrite', '-o', action="store_true", help='Overwrite files when extracting')
144 parser.set_defaults(func=devimport)