summaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic/misc.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/misc.py')
-rw-r--r--scripts/lib/wic/misc.py230
1 files changed, 230 insertions, 0 deletions
diff --git a/scripts/lib/wic/misc.py b/scripts/lib/wic/misc.py
new file mode 100644
index 0000000000..46099840ca
--- /dev/null
+++ b/scripts/lib/wic/misc.py
@@ -0,0 +1,230 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3#
4# Copyright (c) 2013, Intel Corporation.
5# All rights reserved.
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License version 2 as
9# published by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program; if not, write to the Free Software Foundation, Inc.,
18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19#
20# DESCRIPTION
21# This module provides a place to collect various wic-related utils
22# for the OpenEmbedded Image Tools.
23#
24# AUTHORS
25# Tom Zanussi <tom.zanussi (at] linux.intel.com>
26#
27"""Miscellaneous functions."""
28
29import logging
30import os
31import re
32
33from collections import defaultdict
34from distutils import spawn
35
36from wic import WicError
37from wic.utils import runner
38
39logger = logging.getLogger('wic')
40
41# executable -> recipe pairs for exec_native_cmd
42NATIVE_RECIPES = {"bmaptool": "bmap-tools",
43 "grub-mkimage": "grub-efi",
44 "isohybrid": "syslinux",
45 "mcopy": "mtools",
46 "mkdosfs": "dosfstools",
47 "mkisofs": "cdrtools",
48 "mkfs.btrfs": "btrfs-tools",
49 "mkfs.ext2": "e2fsprogs",
50 "mkfs.ext3": "e2fsprogs",
51 "mkfs.ext4": "e2fsprogs",
52 "mkfs.vfat": "dosfstools",
53 "mksquashfs": "squashfs-tools",
54 "mkswap": "util-linux",
55 "mmd": "syslinux",
56 "parted": "parted",
57 "sfdisk": "util-linux",
58 "sgdisk": "gptfdisk",
59 "syslinux": "syslinux"
60 }
61
62def _exec_cmd(cmd_and_args, as_shell=False):
63 """
64 Execute command, catching stderr, stdout
65
66 Need to execute as_shell if the command uses wildcards
67 """
68 logger.debug("_exec_cmd: %s", cmd_and_args)
69 args = cmd_and_args.split()
70 logger.debug(args)
71
72 if as_shell:
73 ret, out = runner.runtool(cmd_and_args)
74 else:
75 ret, out = runner.runtool(args)
76 out = out.strip()
77 if ret != 0:
78 raise WicError("_exec_cmd: %s returned '%s' instead of 0\noutput: %s" % \
79 (cmd_and_args, ret, out))
80
81 logger.debug("_exec_cmd: output for %s (rc = %d): %s",
82 cmd_and_args, ret, out)
83
84 return ret, out
85
86
87def exec_cmd(cmd_and_args, as_shell=False):
88 """
89 Execute command, return output
90 """
91 return _exec_cmd(cmd_and_args, as_shell)[1]
92
93
94def exec_native_cmd(cmd_and_args, native_sysroot, pseudo=""):
95 """
96 Execute native command, catching stderr, stdout
97
98 Need to execute as_shell if the command uses wildcards
99
100 Always need to execute native commands as_shell
101 """
102 # The reason -1 is used is because there may be "export" commands.
103 args = cmd_and_args.split(';')[-1].split()
104 logger.debug(args)
105
106 if pseudo:
107 cmd_and_args = pseudo + cmd_and_args
108
109 wtools_sysroot = get_bitbake_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
110
111 native_paths = \
112 "%s/sbin:%s/usr/sbin:%s/usr/bin:%s/sbin:%s/usr/sbin:%s/usr/bin" % \
113 (wtools_sysroot, wtools_sysroot, wtools_sysroot,
114 native_sysroot, native_sysroot, native_sysroot)
115 native_cmd_and_args = "export PATH=%s:$PATH;%s" % \
116 (native_paths, cmd_and_args)
117 logger.debug("exec_native_cmd: %s", native_cmd_and_args)
118
119 # If the command isn't in the native sysroot say we failed.
120 if spawn.find_executable(args[0], native_paths):
121 ret, out = _exec_cmd(native_cmd_and_args, True)
122 else:
123 ret = 127
124 out = "can't find native executable %s in %s" % (args[0], native_paths)
125
126 prog = args[0]
127 # shell command-not-found
128 if ret == 127 \
129 or (pseudo and ret == 1 and out == "Can't find '%s' in $PATH." % prog):
130 msg = "A native program %s required to build the image "\
131 "was not found (see details above).\n\n" % prog
132 recipe = NATIVE_RECIPES.get(prog)
133 if recipe:
134 msg += "Please make sure wic-tools have %s-native in its DEPENDS, bake it with 'bitbake wic-tools' "\
135 "and try again.\n" % recipe
136 else:
137 msg += "Wic failed to find a recipe to build native %s. Please "\
138 "file a bug against wic.\n" % prog
139 raise WicError(msg)
140
141 return ret, out
142
143BOOTDD_EXTRA_SPACE = 16384
144
145class BitbakeVars(defaultdict):
146 """
147 Container for Bitbake variables.
148 """
149 def __init__(self):
150 defaultdict.__init__(self, dict)
151
152 # default_image and vars_dir attributes should be set from outside
153 self.default_image = None
154 self.vars_dir = None
155
156 def _parse_line(self, line, image, matcher=re.compile(r"^(\w+)=(.+)")):
157 """
158 Parse one line from bitbake -e output or from .env file.
159 Put result key-value pair into the storage.
160 """
161 if "=" not in line:
162 return
163 match = matcher.match(line)
164 if not match:
165 return
166 key, val = match.groups()
167 self[image][key] = val.strip('"')
168
169 def get_var(self, var, image=None, cache=True):
170 """
171 Get bitbake variable from 'bitbake -e' output or from .env file.
172 This is a lazy method, i.e. it runs bitbake or parses file only when
173 only when variable is requested. It also caches results.
174 """
175 if not image:
176 image = self.default_image
177
178 if image not in self:
179 if image and self.vars_dir:
180 fname = os.path.join(self.vars_dir, image + '.env')
181 if os.path.isfile(fname):
182 # parse .env file
183 with open(fname) as varsfile:
184 for line in varsfile:
185 self._parse_line(line, image)
186 else:
187 print("Couldn't get bitbake variable from %s." % fname)
188 print("File %s doesn't exist." % fname)
189 return
190 else:
191 # Get bitbake -e output
192 cmd = "bitbake -e"
193 if image:
194 cmd += " %s" % image
195
196 log_level = logger.getEffectiveLevel()
197 logger.setLevel(logging.INFO)
198 ret, lines = _exec_cmd(cmd)
199 logger.setLevel(log_level)
200
201 if ret:
202 logger.error("Couldn't get '%s' output.", cmd)
203 logger.error("Bitbake failed with error:\n%s\n", lines)
204 return
205
206 # Parse bitbake -e output
207 for line in lines.split('\n'):
208 self._parse_line(line, image)
209
210 # Make first image a default set of variables
211 if cache:
212 images = [key for key in self if key]
213 if len(images) == 1:
214 self[None] = self[image]
215
216 result = self[image].get(var)
217 if not cache:
218 self.pop(image, None)
219
220 return result
221
222# Create BB_VARS singleton
223BB_VARS = BitbakeVars()
224
225def get_bitbake_var(var, image=None, cache=True):
226 """
227 Provide old get_bitbake_var API by wrapping
228 get_var method of BB_VARS singleton.
229 """
230 return BB_VARS.get_var(var, image, cache)