summaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic/utils/misc.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/utils/misc.py')
-rw-r--r--scripts/lib/wic/utils/misc.py224
1 files changed, 224 insertions, 0 deletions
diff --git a/scripts/lib/wic/utils/misc.py b/scripts/lib/wic/utils/misc.py
new file mode 100644
index 0000000000..6781d8381a
--- /dev/null
+++ b/scripts/lib/wic/utils/misc.py
@@ -0,0 +1,224 @@
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 os
30import re
31from collections import defaultdict
32from distutils import spawn
33
34from wic import msger
35from wic.utils import runner
36
37# executable -> recipe pairs for exec_native_cmd
38NATIVE_RECIPES = {"bmaptool": "bmap-tools",
39 "grub-mkimage": "grub-efi",
40 "isohybrid": "syslinux",
41 "mcopy": "mtools",
42 "mkdosfs": "dosfstools",
43 "mkisofs": "cdrtools",
44 "mkfs.btrfs": "btrfs-tools",
45 "mkfs.ext2": "e2fsprogs",
46 "mkfs.ext3": "e2fsprogs",
47 "mkfs.ext4": "e2fsprogs",
48 "mkfs.vfat": "dosfstools",
49 "mksquashfs": "squashfs-tools",
50 "mkswap": "util-linux",
51 "mmd": "syslinux",
52 "parted": "parted",
53 "sfdisk": "util-linux",
54 "sgdisk": "gptfdisk",
55 "syslinux": "syslinux"
56 }
57
58def _exec_cmd(cmd_and_args, as_shell=False, catch=3):
59 """
60 Execute command, catching stderr, stdout
61
62 Need to execute as_shell if the command uses wildcards
63 """
64 msger.debug("_exec_cmd: %s" % cmd_and_args)
65 args = cmd_and_args.split()
66 msger.debug(args)
67
68 if as_shell:
69 ret, out = runner.runtool(cmd_and_args, catch)
70 else:
71 ret, out = runner.runtool(args, catch)
72 out = out.strip()
73 if ret != 0:
74 msger.error("_exec_cmd: %s returned '%s' instead of 0\noutput: %s" % \
75 (cmd_and_args, ret, out))
76
77 msger.debug("_exec_cmd: output for %s (rc = %d): %s" % \
78 (cmd_and_args, ret, out))
79
80 return (ret, out)
81
82
83def exec_cmd(cmd_and_args, as_shell=False, catch=3):
84 """
85 Execute command, catching stderr, stdout
86
87 Exits if rc non-zero
88 """
89 ret, out = _exec_cmd(cmd_and_args, as_shell, catch)
90
91 return out
92
93def exec_native_cmd(cmd_and_args, native_sysroot, catch=3, pseudo=""):
94 """
95 Execute native command, catching stderr, stdout
96
97 Need to execute as_shell if the command uses wildcards
98
99 Always need to execute native commands as_shell
100 """
101 # The reason -1 is used is because there may be "export" commands.
102 args = cmd_and_args.split(';')[-1].split()
103 msger.debug(args)
104
105 if pseudo:
106 cmd_and_args = pseudo + cmd_and_args
107 native_paths = \
108 "%s/sbin:%s/usr/sbin:%s/usr/bin" % \
109 (native_sysroot, native_sysroot, native_sysroot)
110 native_cmd_and_args = "export PATH=%s:$PATH;%s" % \
111 (native_paths, cmd_and_args)
112 msger.debug("exec_native_cmd: %s" % cmd_and_args)
113
114 # If the command isn't in the native sysroot say we failed.
115 if spawn.find_executable(args[0], native_paths):
116 ret, out = _exec_cmd(native_cmd_and_args, True, catch)
117 else:
118 ret = 127
119
120 prog = args[0]
121 # shell command-not-found
122 if ret == 127 \
123 or (pseudo and ret == 1 and out == "Can't find '%s' in $PATH." % prog):
124 msg = "A native program %s required to build the image "\
125 "was not found (see details above).\n\n" % prog
126 recipe = NATIVE_RECIPES.get(prog)
127 if recipe:
128 msg += "Please bake it with 'bitbake %s-native' "\
129 "and try again.\n" % recipe
130 else:
131 msg += "Wic failed to find a recipe to build native %s. Please "\
132 "file a bug against wic.\n" % prog
133 msger.error(msg)
134
135 return ret, out
136
137BOOTDD_EXTRA_SPACE = 16384
138
139class BitbakeVars(defaultdict):
140 """
141 Container for Bitbake variables.
142 """
143 def __init__(self):
144 defaultdict.__init__(self, dict)
145
146 # default_image and vars_dir attributes should be set from outside
147 self.default_image = None
148 self.vars_dir = None
149
150 def _parse_line(self, line, image, matcher=re.compile(r"^(\w+)=(.+)")):
151 """
152 Parse one line from bitbake -e output or from .env file.
153 Put result key-value pair into the storage.
154 """
155 if "=" not in line:
156 return
157 match = matcher.match(line)
158 if not match:
159 return
160 key, val = match.groups()
161 self[image][key] = val.strip('"')
162
163 def get_var(self, var, image=None, cache=True):
164 """
165 Get bitbake variable from 'bitbake -e' output or from .env file.
166 This is a lazy method, i.e. it runs bitbake or parses file only when
167 only when variable is requested. It also caches results.
168 """
169 if not image:
170 image = self.default_image
171
172 if image not in self:
173 if image and self.vars_dir:
174 fname = os.path.join(self.vars_dir, image + '.env')
175 if os.path.isfile(fname):
176 # parse .env file
177 with open(fname) as varsfile:
178 for line in varsfile:
179 self._parse_line(line, image)
180 else:
181 print("Couldn't get bitbake variable from %s." % fname)
182 print("File %s doesn't exist." % fname)
183 return
184 else:
185 # Get bitbake -e output
186 cmd = "bitbake -e"
187 if image:
188 cmd += " %s" % image
189
190 log_level = msger.get_loglevel()
191 msger.set_loglevel('normal')
192 ret, lines = _exec_cmd(cmd)
193 msger.set_loglevel(log_level)
194
195 if ret:
196 print("Couldn't get '%s' output." % cmd)
197 print("Bitbake failed with error:\n%s\n" % lines)
198 return
199
200 # Parse bitbake -e output
201 for line in lines.split('\n'):
202 self._parse_line(line, image)
203
204 # Make first image a default set of variables
205 if cache:
206 images = [key for key in self if key]
207 if len(images) == 1:
208 self[None] = self[image]
209
210 result = self[image].get(var)
211 if not cache:
212 self.pop(image, None)
213
214 return result
215
216# Create BB_VARS singleton
217BB_VARS = BitbakeVars()
218
219def get_bitbake_var(var, image=None, cache=True):
220 """
221 Provide old get_bitbake_var API by wrapping
222 get_var method of BB_VARS singleton.
223 """
224 return BB_VARS.get_var(var, image, cache)