| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | # ex:ts=4:sw=4:sts=4:et | 
 | 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | 
 | 3 | # | 
 | 4 | # BitBake 'Build' implementation | 
 | 5 | # | 
 | 6 | # Core code for function execution and task handling in the | 
 | 7 | # BitBake build tools. | 
 | 8 | # | 
 | 9 | # Copyright (C) 2003, 2004  Chris Larson | 
 | 10 | # | 
 | 11 | # Based on Gentoo's portage.py. | 
 | 12 | # | 
 | 13 | # This program is free software; you can redistribute it and/or modify | 
 | 14 | # it under the terms of the GNU General Public License version 2 as | 
 | 15 | # published by the Free Software Foundation. | 
 | 16 | # | 
 | 17 | # This program is distributed in the hope that it will be useful, | 
 | 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 20 | # GNU General Public License for more details. | 
 | 21 | # | 
 | 22 | # You should have received a copy of the GNU General Public License along | 
 | 23 | # with this program; if not, write to the Free Software Foundation, Inc., | 
 | 24 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 
 | 25 | # | 
 | 26 | # Based on functions from the base bb module, Copyright 2003 Holger Schurig | 
 | 27 |  | 
 | 28 | import os | 
 | 29 | import sys | 
 | 30 | import logging | 
 | 31 | import shlex | 
 | 32 | import glob | 
 | 33 | import time | 
 | 34 | import stat | 
 | 35 | import bb | 
 | 36 | import bb.msg | 
 | 37 | import bb.process | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 38 | import bb.progress | 
 | 39 | from bb import data, event, utils | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 40 |  | 
 | 41 | bblogger = logging.getLogger('BitBake') | 
 | 42 | logger = logging.getLogger('BitBake.Build') | 
 | 43 |  | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 44 | __mtime_cache = {} | 
 | 45 |  | 
 | 46 | def cached_mtime_noerror(f): | 
 | 47 |     if f not in __mtime_cache: | 
 | 48 |         try: | 
 | 49 |             __mtime_cache[f] = os.stat(f)[stat.ST_MTIME] | 
 | 50 |         except OSError: | 
 | 51 |             return 0 | 
 | 52 |     return __mtime_cache[f] | 
 | 53 |  | 
 | 54 | def reset_cache(): | 
 | 55 |     global __mtime_cache | 
 | 56 |     __mtime_cache = {} | 
 | 57 |  | 
 | 58 | # When we execute a Python function, we'd like certain things | 
 | 59 | # in all namespaces, hence we add them to __builtins__. | 
 | 60 | # If we do not do this and use the exec globals, they will | 
 | 61 | # not be available to subfunctions. | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 62 | if hasattr(__builtins__, '__setitem__'): | 
 | 63 |     builtins = __builtins__ | 
 | 64 | else: | 
 | 65 |     builtins = __builtins__.__dict__ | 
 | 66 |  | 
 | 67 | builtins['bb'] = bb | 
 | 68 | builtins['os'] = os | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 69 |  | 
 | 70 | class FuncFailed(Exception): | 
 | 71 |     def __init__(self, name = None, logfile = None): | 
 | 72 |         self.logfile = logfile | 
 | 73 |         self.name = name | 
 | 74 |         if name: | 
 | 75 |             self.msg = 'Function failed: %s' % name | 
 | 76 |         else: | 
 | 77 |             self.msg = "Function failed" | 
 | 78 |  | 
 | 79 |     def __str__(self): | 
 | 80 |         if self.logfile and os.path.exists(self.logfile): | 
 | 81 |             msg = ("%s (log file is located at %s)" % | 
 | 82 |                    (self.msg, self.logfile)) | 
 | 83 |         else: | 
 | 84 |             msg = self.msg | 
 | 85 |         return msg | 
 | 86 |  | 
 | 87 | class TaskBase(event.Event): | 
 | 88 |     """Base class for task events""" | 
 | 89 |  | 
 | 90 |     def __init__(self, t, logfile, d): | 
 | 91 |         self._task = t | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 92 |         self._package = d.getVar("PF") | 
 | 93 |         self._mc = d.getVar("BB_CURRENT_MC") | 
 | 94 |         self.taskfile = d.getVar("FILE") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 95 |         self.taskname = self._task | 
 | 96 |         self.logfile = logfile | 
 | 97 |         self.time = time.time() | 
 | 98 |         event.Event.__init__(self) | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 99 |         self._message = "recipe %s: task %s: %s" % (d.getVar("PF"), t, self.getDisplayName()) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 100 |  | 
 | 101 |     def getTask(self): | 
 | 102 |         return self._task | 
 | 103 |  | 
 | 104 |     def setTask(self, task): | 
 | 105 |         self._task = task | 
 | 106 |  | 
 | 107 |     def getDisplayName(self): | 
 | 108 |         return bb.event.getName(self)[4:] | 
 | 109 |  | 
 | 110 |     task = property(getTask, setTask, None, "task property") | 
 | 111 |  | 
 | 112 | class TaskStarted(TaskBase): | 
 | 113 |     """Task execution started""" | 
 | 114 |     def __init__(self, t, logfile, taskflags, d): | 
 | 115 |         super(TaskStarted, self).__init__(t, logfile, d) | 
 | 116 |         self.taskflags = taskflags | 
 | 117 |  | 
 | 118 | class TaskSucceeded(TaskBase): | 
 | 119 |     """Task execution completed""" | 
 | 120 |  | 
 | 121 | class TaskFailed(TaskBase): | 
 | 122 |     """Task execution failed""" | 
 | 123 |  | 
 | 124 |     def __init__(self, task, logfile, metadata, errprinted = False): | 
 | 125 |         self.errprinted = errprinted | 
 | 126 |         super(TaskFailed, self).__init__(task, logfile, metadata) | 
 | 127 |  | 
 | 128 | class TaskFailedSilent(TaskBase): | 
 | 129 |     """Task execution failed (silently)""" | 
 | 130 |     def getDisplayName(self): | 
 | 131 |         # Don't need to tell the user it was silent | 
 | 132 |         return "Failed" | 
 | 133 |  | 
 | 134 | class TaskInvalid(TaskBase): | 
 | 135 |  | 
 | 136 |     def __init__(self, task, metadata): | 
 | 137 |         super(TaskInvalid, self).__init__(task, None, metadata) | 
 | 138 |         self._message = "No such task '%s'" % task | 
 | 139 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 140 | class TaskProgress(event.Event): | 
 | 141 |     """ | 
 | 142 |     Task made some progress that could be reported to the user, usually in | 
 | 143 |     the form of a progress bar or similar. | 
 | 144 |     NOTE: this class does not inherit from TaskBase since it doesn't need | 
 | 145 |     to - it's fired within the task context itself, so we don't have any of | 
 | 146 |     the context information that you do in the case of the other events. | 
 | 147 |     The event PID can be used to determine which task it came from. | 
 | 148 |     The progress value is normally 0-100, but can also be negative | 
 | 149 |     indicating that progress has been made but we aren't able to determine | 
 | 150 |     how much. | 
 | 151 |     The rate is optional, this is simply an extra string to display to the | 
 | 152 |     user if specified. | 
 | 153 |     """ | 
 | 154 |     def __init__(self, progress, rate=None): | 
 | 155 |         self.progress = progress | 
 | 156 |         self.rate = rate | 
 | 157 |         event.Event.__init__(self) | 
 | 158 |  | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 159 |  | 
 | 160 | class LogTee(object): | 
 | 161 |     def __init__(self, logger, outfile): | 
 | 162 |         self.outfile = outfile | 
 | 163 |         self.logger = logger | 
 | 164 |         self.name = self.outfile.name | 
 | 165 |  | 
 | 166 |     def write(self, string): | 
 | 167 |         self.logger.plain(string) | 
 | 168 |         self.outfile.write(string) | 
 | 169 |  | 
 | 170 |     def __enter__(self): | 
 | 171 |         self.outfile.__enter__() | 
 | 172 |         return self | 
 | 173 |  | 
 | 174 |     def __exit__(self, *excinfo): | 
 | 175 |         self.outfile.__exit__(*excinfo) | 
 | 176 |  | 
 | 177 |     def __repr__(self): | 
 | 178 |         return '<LogTee {0}>'.format(self.name) | 
 | 179 |     def flush(self): | 
 | 180 |         self.outfile.flush() | 
 | 181 |  | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 182 | # | 
 | 183 | # pythonexception allows the python exceptions generated to be raised | 
 | 184 | # as the real exceptions (not FuncFailed) and without a backtrace at the  | 
 | 185 | # origin of the failure. | 
 | 186 | # | 
 | 187 | def exec_func(func, d, dirs = None, pythonexception=False): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 188 |     """Execute a BB 'function'""" | 
 | 189 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 190 |     try: | 
 | 191 |         oldcwd = os.getcwd() | 
 | 192 |     except: | 
 | 193 |         oldcwd = None | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 194 |  | 
 | 195 |     flags = d.getVarFlags(func) | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 196 |     cleandirs = flags.get('cleandirs') if flags else None | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 197 |     if cleandirs: | 
 | 198 |         for cdir in d.expand(cleandirs).split(): | 
 | 199 |             bb.utils.remove(cdir, True) | 
 | 200 |             bb.utils.mkdirhier(cdir) | 
 | 201 |  | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 202 |     if flags and dirs is None: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 203 |         dirs = flags.get('dirs') | 
 | 204 |         if dirs: | 
 | 205 |             dirs = d.expand(dirs).split() | 
 | 206 |  | 
 | 207 |     if dirs: | 
 | 208 |         for adir in dirs: | 
 | 209 |             bb.utils.mkdirhier(adir) | 
 | 210 |         adir = dirs[-1] | 
 | 211 |     else: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 212 |         adir = None | 
 | 213 |  | 
 | 214 |     body = d.getVar(func, False) | 
 | 215 |     if not body: | 
 | 216 |         if body is None: | 
 | 217 |             logger.warning("Function %s doesn't exist", func) | 
 | 218 |         return | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 219 |  | 
 | 220 |     ispython = flags.get('python') | 
 | 221 |  | 
 | 222 |     lockflag = flags.get('lockfiles') | 
 | 223 |     if lockflag: | 
 | 224 |         lockfiles = [f for f in d.expand(lockflag).split()] | 
 | 225 |     else: | 
 | 226 |         lockfiles = None | 
 | 227 |  | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 228 |     tempdir = d.getVar('T') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 229 |  | 
 | 230 |     # or func allows items to be executed outside of the normal | 
 | 231 |     # task set, such as buildhistory | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 232 |     task = d.getVar('BB_RUNTASK') or func | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 233 |     if task == func: | 
 | 234 |         taskfunc = task | 
 | 235 |     else: | 
 | 236 |         taskfunc = "%s.%s" % (task, func) | 
 | 237 |  | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 238 |     runfmt = d.getVar('BB_RUNFMT') or "run.{func}.{pid}" | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 239 |     runfn = runfmt.format(taskfunc=taskfunc, task=task, func=func, pid=os.getpid()) | 
 | 240 |     runfile = os.path.join(tempdir, runfn) | 
 | 241 |     bb.utils.mkdirhier(os.path.dirname(runfile)) | 
 | 242 |  | 
 | 243 |     # Setup the courtesy link to the runfn, only for tasks | 
 | 244 |     # we create the link 'just' before the run script is created | 
 | 245 |     # if we create it after, and if the run script fails, then the | 
 | 246 |     # link won't be created as an exception would be fired. | 
 | 247 |     if task == func: | 
 | 248 |         runlink = os.path.join(tempdir, 'run.{0}'.format(task)) | 
 | 249 |         if runlink: | 
 | 250 |             bb.utils.remove(runlink) | 
 | 251 |  | 
 | 252 |             try: | 
 | 253 |                 os.symlink(runfn, runlink) | 
 | 254 |             except OSError: | 
 | 255 |                 pass | 
 | 256 |  | 
 | 257 |     with bb.utils.fileslocked(lockfiles): | 
 | 258 |         if ispython: | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 259 |             exec_func_python(func, d, runfile, cwd=adir, pythonexception=pythonexception) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 260 |         else: | 
 | 261 |             exec_func_shell(func, d, runfile, cwd=adir) | 
 | 262 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 263 |     try: | 
 | 264 |         curcwd = os.getcwd() | 
 | 265 |     except: | 
 | 266 |         curcwd = None | 
 | 267 |  | 
 | 268 |     if oldcwd and curcwd != oldcwd: | 
 | 269 |         try: | 
 | 270 |             bb.warn("Task %s changed cwd to %s" % (func, curcwd)) | 
 | 271 |             os.chdir(oldcwd) | 
 | 272 |         except: | 
 | 273 |             pass | 
 | 274 |  | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 275 | _functionfmt = """ | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 276 | {function}(d) | 
 | 277 | """ | 
 | 278 | logformatter = bb.msg.BBLogFormatter("%(levelname)s: %(message)s") | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 279 | def exec_func_python(func, d, runfile, cwd=None, pythonexception=False): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 280 |     """Execute a python BB 'function'""" | 
 | 281 |  | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 282 |     code = _functionfmt.format(function=func) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 283 |     bb.utils.mkdirhier(os.path.dirname(runfile)) | 
 | 284 |     with open(runfile, 'w') as script: | 
 | 285 |         bb.data.emit_func_python(func, script, d) | 
 | 286 |  | 
 | 287 |     if cwd: | 
 | 288 |         try: | 
 | 289 |             olddir = os.getcwd() | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 290 |         except OSError as e: | 
 | 291 |             bb.warn("%s: Cannot get cwd: %s" % (func, e)) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 292 |             olddir = None | 
 | 293 |         os.chdir(cwd) | 
 | 294 |  | 
 | 295 |     bb.debug(2, "Executing python function %s" % func) | 
 | 296 |  | 
 | 297 |     try: | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 298 |         text = "def %s(d):\n%s" % (func, d.getVar(func, False)) | 
 | 299 |         fn = d.getVarFlag(func, "filename", False) | 
 | 300 |         lineno = int(d.getVarFlag(func, "lineno", False)) | 
 | 301 |         bb.methodpool.insert_method(func, text, fn, lineno - 1) | 
 | 302 |  | 
 | 303 |         comp = utils.better_compile(code, func, "exec_python_func() autogenerated") | 
 | 304 |         utils.better_exec(comp, {"d": d}, code, "exec_python_func() autogenerated", pythonexception=pythonexception) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 305 |     except (bb.parse.SkipRecipe, bb.build.FuncFailed): | 
 | 306 |         raise | 
| Brad Bishop | 1932369 | 2019-04-05 15:28:33 -0400 | [diff] [blame] | 307 |     except Exception as e: | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 308 |         if pythonexception: | 
 | 309 |             raise | 
| Brad Bishop | 1932369 | 2019-04-05 15:28:33 -0400 | [diff] [blame] | 310 |         logger.error(str(e)) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 311 |         raise FuncFailed(func, None) | 
 | 312 |     finally: | 
 | 313 |         bb.debug(2, "Python function %s finished" % func) | 
 | 314 |  | 
 | 315 |         if cwd and olddir: | 
 | 316 |             try: | 
 | 317 |                 os.chdir(olddir) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 318 |             except OSError as e: | 
 | 319 |                 bb.warn("%s: Cannot restore cwd %s: %s" % (func, olddir, e)) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 320 |  | 
 | 321 | def shell_trap_code(): | 
 | 322 |     return '''#!/bin/sh\n | 
 | 323 | # Emit a useful diagnostic if something fails: | 
 | 324 | bb_exit_handler() { | 
 | 325 |     ret=$? | 
 | 326 |     case $ret in | 
 | 327 |     0)  ;; | 
 | 328 |     *)  case $BASH_VERSION in | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 329 |         "") echo "WARNING: exit code $ret from a shell command.";; | 
 | 330 |         *)  echo "WARNING: ${BASH_SOURCE[0]}:${BASH_LINENO[0]} exit $ret from '$BASH_COMMAND'";; | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 331 |         esac | 
 | 332 |         exit $ret | 
 | 333 |     esac | 
 | 334 | } | 
 | 335 | trap 'bb_exit_handler' 0 | 
 | 336 | set -e | 
 | 337 | ''' | 
 | 338 |  | 
 | 339 | def exec_func_shell(func, d, runfile, cwd=None): | 
 | 340 |     """Execute a shell function from the metadata | 
 | 341 |  | 
 | 342 |     Note on directory behavior.  The 'dirs' varflag should contain a list | 
 | 343 |     of the directories you need created prior to execution.  The last | 
 | 344 |     item in the list is where we will chdir/cd to. | 
 | 345 |     """ | 
 | 346 |  | 
 | 347 |     # Don't let the emitted shell script override PWD | 
 | 348 |     d.delVarFlag('PWD', 'export') | 
 | 349 |  | 
 | 350 |     with open(runfile, 'w') as script: | 
 | 351 |         script.write(shell_trap_code()) | 
 | 352 |  | 
 | 353 |         bb.data.emit_func(func, script, d) | 
 | 354 |  | 
 | 355 |         if bb.msg.loggerVerboseLogs: | 
 | 356 |             script.write("set -x\n") | 
 | 357 |         if cwd: | 
 | 358 |             script.write("cd '%s'\n" % cwd) | 
 | 359 |         script.write("%s\n" % func) | 
 | 360 |         script.write(''' | 
 | 361 | # cleanup | 
 | 362 | ret=$? | 
 | 363 | trap '' 0 | 
 | 364 | exit $ret | 
 | 365 | ''') | 
 | 366 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 367 |     os.chmod(runfile, 0o775) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 368 |  | 
 | 369 |     cmd = runfile | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 370 |     if d.getVarFlag(func, 'fakeroot', False): | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 371 |         fakerootcmd = d.getVar('FAKEROOT') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 372 |         if fakerootcmd: | 
 | 373 |             cmd = [fakerootcmd, runfile] | 
 | 374 |  | 
 | 375 |     if bb.msg.loggerDefaultVerbose: | 
 | 376 |         logfile = LogTee(logger, sys.stdout) | 
 | 377 |     else: | 
 | 378 |         logfile = sys.stdout | 
 | 379 |  | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 380 |     progress = d.getVarFlag(func, 'progress') | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 381 |     if progress: | 
 | 382 |         if progress == 'percent': | 
 | 383 |             # Use default regex | 
 | 384 |             logfile = bb.progress.BasicProgressHandler(d, outfile=logfile) | 
 | 385 |         elif progress.startswith('percent:'): | 
 | 386 |             # Use specified regex | 
 | 387 |             logfile = bb.progress.BasicProgressHandler(d, regex=progress.split(':', 1)[1], outfile=logfile) | 
 | 388 |         elif progress.startswith('outof:'): | 
 | 389 |             # Use specified regex | 
 | 390 |             logfile = bb.progress.OutOfProgressHandler(d, regex=progress.split(':', 1)[1], outfile=logfile) | 
 | 391 |         else: | 
 | 392 |             bb.warn('%s: invalid task progress varflag value "%s", ignoring' % (func, progress)) | 
 | 393 |  | 
 | 394 |     fifobuffer = bytearray() | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 395 |     def readfifo(data): | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 396 |         nonlocal fifobuffer | 
 | 397 |         fifobuffer.extend(data) | 
 | 398 |         while fifobuffer: | 
 | 399 |             message, token, nextmsg = fifobuffer.partition(b"\00") | 
 | 400 |             if token: | 
 | 401 |                 splitval = message.split(b' ', 1) | 
 | 402 |                 cmd = splitval[0].decode("utf-8") | 
 | 403 |                 if len(splitval) > 1: | 
 | 404 |                     value = splitval[1].decode("utf-8") | 
 | 405 |                 else: | 
 | 406 |                     value = '' | 
 | 407 |                 if cmd == 'bbplain': | 
 | 408 |                     bb.plain(value) | 
 | 409 |                 elif cmd == 'bbnote': | 
 | 410 |                     bb.note(value) | 
 | 411 |                 elif cmd == 'bbwarn': | 
 | 412 |                     bb.warn(value) | 
 | 413 |                 elif cmd == 'bberror': | 
 | 414 |                     bb.error(value) | 
 | 415 |                 elif cmd == 'bbfatal': | 
 | 416 |                     # The caller will call exit themselves, so bb.error() is | 
 | 417 |                     # what we want here rather than bb.fatal() | 
 | 418 |                     bb.error(value) | 
 | 419 |                 elif cmd == 'bbfatal_log': | 
 | 420 |                     bb.error(value, forcelog=True) | 
 | 421 |                 elif cmd == 'bbdebug': | 
 | 422 |                     splitval = value.split(' ', 1) | 
 | 423 |                     level = int(splitval[0]) | 
 | 424 |                     value = splitval[1] | 
 | 425 |                     bb.debug(level, value) | 
 | 426 |                 else: | 
 | 427 |                     bb.warn("Unrecognised command '%s' on FIFO" % cmd) | 
 | 428 |                 fifobuffer = nextmsg | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 429 |             else: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 430 |                 break | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 431 |  | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 432 |     tempdir = d.getVar('T') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 433 |     fifopath = os.path.join(tempdir, 'fifo.%s' % os.getpid()) | 
 | 434 |     if os.path.exists(fifopath): | 
 | 435 |         os.unlink(fifopath) | 
 | 436 |     os.mkfifo(fifopath) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 437 |     with open(fifopath, 'r+b', buffering=0) as fifo: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 438 |         try: | 
 | 439 |             bb.debug(2, "Executing shell function %s" % func) | 
 | 440 |  | 
 | 441 |             try: | 
 | 442 |                 with open(os.devnull, 'r+') as stdin: | 
 | 443 |                     bb.process.run(cmd, shell=False, stdin=stdin, log=logfile, extrafiles=[(fifo,readfifo)]) | 
 | 444 |             except bb.process.CmdError: | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 445 |                 logfn = d.getVar('BB_LOGFILE') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 446 |                 raise FuncFailed(func, logfn) | 
 | 447 |         finally: | 
 | 448 |             os.unlink(fifopath) | 
 | 449 |  | 
 | 450 |     bb.debug(2, "Shell function %s finished" % func) | 
 | 451 |  | 
 | 452 | def _task_data(fn, task, d): | 
 | 453 |     localdata = bb.data.createCopy(d) | 
 | 454 |     localdata.setVar('BB_FILENAME', fn) | 
 | 455 |     localdata.setVar('BB_CURRENTTASK', task[3:]) | 
 | 456 |     localdata.setVar('OVERRIDES', 'task-%s:%s' % | 
 | 457 |                      (task[3:].replace('_', '-'), d.getVar('OVERRIDES', False))) | 
 | 458 |     localdata.finalize() | 
 | 459 |     bb.data.expandKeys(localdata) | 
 | 460 |     return localdata | 
 | 461 |  | 
 | 462 | def _exec_task(fn, task, d, quieterr): | 
 | 463 |     """Execute a BB 'task' | 
 | 464 |  | 
 | 465 |     Execution of a task involves a bit more setup than executing a function, | 
 | 466 |     running it with its own local metadata, and with some useful variables set. | 
 | 467 |     """ | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 468 |     if not d.getVarFlag(task, 'task', False): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 469 |         event.fire(TaskInvalid(task, d), d) | 
 | 470 |         logger.error("No such task: %s" % task) | 
 | 471 |         return 1 | 
 | 472 |  | 
 | 473 |     logger.debug(1, "Executing task %s", task) | 
 | 474 |  | 
 | 475 |     localdata = _task_data(fn, task, d) | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 476 |     tempdir = localdata.getVar('T') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 477 |     if not tempdir: | 
 | 478 |         bb.fatal("T variable not set, unable to build") | 
 | 479 |  | 
 | 480 |     # Change nice level if we're asked to | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 481 |     nice = localdata.getVar("BB_TASK_NICE_LEVEL") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 482 |     if nice: | 
 | 483 |         curnice = os.nice(0) | 
 | 484 |         nice = int(nice) - curnice | 
 | 485 |         newnice = os.nice(nice) | 
 | 486 |         logger.debug(1, "Renice to %s " % newnice) | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 487 |     ionice = localdata.getVar("BB_TASK_IONICE_LEVEL") | 
| Patrick Williams | f1e5d69 | 2016-03-30 15:21:19 -0500 | [diff] [blame] | 488 |     if ionice: | 
 | 489 |         try: | 
 | 490 |             cls, prio = ionice.split(".", 1) | 
 | 491 |             bb.utils.ioprio_set(os.getpid(), int(cls), int(prio)) | 
 | 492 |         except: | 
 | 493 |             bb.warn("Invalid ionice level %s" % ionice) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 494 |  | 
 | 495 |     bb.utils.mkdirhier(tempdir) | 
 | 496 |  | 
 | 497 |     # Determine the logfile to generate | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 498 |     logfmt = localdata.getVar('BB_LOGFMT') or 'log.{task}.{pid}' | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 499 |     logbase = logfmt.format(task=task, pid=os.getpid()) | 
 | 500 |  | 
 | 501 |     # Document the order of the tasks... | 
 | 502 |     logorder = os.path.join(tempdir, 'log.task_order') | 
 | 503 |     try: | 
 | 504 |         with open(logorder, 'a') as logorderfile: | 
 | 505 |             logorderfile.write('{0} ({1}): {2}\n'.format(task, os.getpid(), logbase)) | 
 | 506 |     except OSError: | 
 | 507 |         logger.exception("Opening log file '%s'", logorder) | 
 | 508 |         pass | 
 | 509 |  | 
 | 510 |     # Setup the courtesy link to the logfn | 
 | 511 |     loglink = os.path.join(tempdir, 'log.{0}'.format(task)) | 
 | 512 |     logfn = os.path.join(tempdir, logbase) | 
 | 513 |     if loglink: | 
 | 514 |         bb.utils.remove(loglink) | 
 | 515 |  | 
 | 516 |         try: | 
 | 517 |            os.symlink(logbase, loglink) | 
 | 518 |         except OSError: | 
 | 519 |            pass | 
 | 520 |  | 
 | 521 |     prefuncs = localdata.getVarFlag(task, 'prefuncs', expand=True) | 
 | 522 |     postfuncs = localdata.getVarFlag(task, 'postfuncs', expand=True) | 
 | 523 |  | 
 | 524 |     class ErrorCheckHandler(logging.Handler): | 
 | 525 |         def __init__(self): | 
 | 526 |             self.triggered = False | 
 | 527 |             logging.Handler.__init__(self, logging.ERROR) | 
 | 528 |         def emit(self, record): | 
 | 529 |             if getattr(record, 'forcelog', False): | 
 | 530 |                 self.triggered = False | 
 | 531 |             else: | 
 | 532 |                 self.triggered = True | 
 | 533 |  | 
 | 534 |     # Handle logfiles | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 535 |     try: | 
 | 536 |         bb.utils.mkdirhier(os.path.dirname(logfn)) | 
 | 537 |         logfile = open(logfn, 'w') | 
 | 538 |     except OSError: | 
 | 539 |         logger.exception("Opening log file '%s'", logfn) | 
 | 540 |         pass | 
 | 541 |  | 
 | 542 |     # Dup the existing fds so we dont lose them | 
 | 543 |     osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()] | 
 | 544 |     oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()] | 
 | 545 |     ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()] | 
 | 546 |  | 
 | 547 |     # Replace those fds with our own | 
| Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 548 |     with open('/dev/null', 'r') as si: | 
 | 549 |         os.dup2(si.fileno(), osi[1]) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 550 |     os.dup2(logfile.fileno(), oso[1]) | 
 | 551 |     os.dup2(logfile.fileno(), ose[1]) | 
 | 552 |  | 
 | 553 |     # Ensure Python logging goes to the logfile | 
 | 554 |     handler = logging.StreamHandler(logfile) | 
 | 555 |     handler.setFormatter(logformatter) | 
 | 556 |     # Always enable full debug output into task logfiles | 
 | 557 |     handler.setLevel(logging.DEBUG - 2) | 
 | 558 |     bblogger.addHandler(handler) | 
 | 559 |  | 
 | 560 |     errchk = ErrorCheckHandler() | 
 | 561 |     bblogger.addHandler(errchk) | 
 | 562 |  | 
 | 563 |     localdata.setVar('BB_LOGFILE', logfn) | 
 | 564 |     localdata.setVar('BB_RUNTASK', task) | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 565 |     localdata.setVar('BB_TASK_LOGGER', bblogger) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 566 |  | 
 | 567 |     flags = localdata.getVarFlags(task) | 
 | 568 |  | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 569 |     try: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 570 |         try: | 
 | 571 |             event.fire(TaskStarted(task, logfn, flags, localdata), localdata) | 
 | 572 |         except (bb.BBHandledException, SystemExit): | 
 | 573 |             return 1 | 
 | 574 |         except FuncFailed as exc: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 575 |             logger.error(str(exc)) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 576 |             return 1 | 
 | 577 |  | 
 | 578 |         try: | 
 | 579 |             for func in (prefuncs or '').split(): | 
 | 580 |                 exec_func(func, localdata) | 
 | 581 |             exec_func(task, localdata) | 
 | 582 |             for func in (postfuncs or '').split(): | 
 | 583 |                 exec_func(func, localdata) | 
 | 584 |         except FuncFailed as exc: | 
 | 585 |             if quieterr: | 
 | 586 |                 event.fire(TaskFailedSilent(task, logfn, localdata), localdata) | 
 | 587 |             else: | 
 | 588 |                 errprinted = errchk.triggered | 
 | 589 |                 logger.error(str(exc)) | 
 | 590 |                 event.fire(TaskFailed(task, logfn, localdata, errprinted), localdata) | 
 | 591 |             return 1 | 
 | 592 |         except bb.BBHandledException: | 
 | 593 |             event.fire(TaskFailed(task, logfn, localdata, True), localdata) | 
 | 594 |             return 1 | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 595 |     finally: | 
 | 596 |         sys.stdout.flush() | 
 | 597 |         sys.stderr.flush() | 
 | 598 |  | 
 | 599 |         bblogger.removeHandler(handler) | 
 | 600 |  | 
 | 601 |         # Restore the backup fds | 
 | 602 |         os.dup2(osi[0], osi[1]) | 
 | 603 |         os.dup2(oso[0], oso[1]) | 
 | 604 |         os.dup2(ose[0], ose[1]) | 
 | 605 |  | 
 | 606 |         # Close the backup fds | 
 | 607 |         os.close(osi[0]) | 
 | 608 |         os.close(oso[0]) | 
 | 609 |         os.close(ose[0]) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 610 |  | 
 | 611 |         logfile.close() | 
 | 612 |         if os.path.exists(logfn) and os.path.getsize(logfn) == 0: | 
 | 613 |             logger.debug(2, "Zero size logfn %s, removing", logfn) | 
 | 614 |             bb.utils.remove(logfn) | 
 | 615 |             bb.utils.remove(loglink) | 
 | 616 |     event.fire(TaskSucceeded(task, logfn, localdata), localdata) | 
 | 617 |  | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 618 |     if not localdata.getVarFlag(task, 'nostamp', False) and not localdata.getVarFlag(task, 'selfstamp', False): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 619 |         make_stamp(task, localdata) | 
 | 620 |  | 
 | 621 |     return 0 | 
 | 622 |  | 
 | 623 | def exec_task(fn, task, d, profile = False): | 
 | 624 |     try: | 
 | 625 |         quieterr = False | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 626 |         if d.getVarFlag(task, "quieterrors", False) is not None: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 627 |             quieterr = True | 
 | 628 |  | 
 | 629 |         if profile: | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 630 |             profname = "profile-%s.log" % (d.getVar("PN") + "-" + task) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 631 |             try: | 
 | 632 |                 import cProfile as profile | 
 | 633 |             except: | 
 | 634 |                 import profile | 
 | 635 |             prof = profile.Profile() | 
 | 636 |             ret = profile.Profile.runcall(prof, _exec_task, fn, task, d, quieterr) | 
 | 637 |             prof.dump_stats(profname) | 
 | 638 |             bb.utils.process_profilelog(profname) | 
 | 639 |  | 
 | 640 |             return ret | 
 | 641 |         else: | 
 | 642 |             return _exec_task(fn, task, d, quieterr) | 
 | 643 |  | 
 | 644 |     except Exception: | 
 | 645 |         from traceback import format_exc | 
 | 646 |         if not quieterr: | 
 | 647 |             logger.error("Build of %s failed" % (task)) | 
 | 648 |             logger.error(format_exc()) | 
 | 649 |             failedevent = TaskFailed(task, None, d, True) | 
 | 650 |             event.fire(failedevent, d) | 
 | 651 |         return 1 | 
 | 652 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 653 | def stamp_internal(taskname, d, file_name, baseonly=False, noextra=False): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 654 |     """ | 
 | 655 |     Internal stamp helper function | 
 | 656 |     Makes sure the stamp directory exists | 
 | 657 |     Returns the stamp path+filename | 
 | 658 |  | 
 | 659 |     In the bitbake core, d can be a CacheData and file_name will be set. | 
 | 660 |     When called in task context, d will be a data store, file_name will not be set | 
 | 661 |     """ | 
 | 662 |     taskflagname = taskname | 
 | 663 |     if taskname.endswith("_setscene") and taskname != "do_setscene": | 
 | 664 |         taskflagname = taskname.replace("_setscene", "") | 
 | 665 |  | 
 | 666 |     if file_name: | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 667 |         stamp = d.stamp[file_name] | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 668 |         extrainfo = d.stamp_extrainfo[file_name].get(taskflagname) or "" | 
 | 669 |     else: | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 670 |         stamp = d.getVar('STAMP') | 
 | 671 |         file_name = d.getVar('BB_FILENAME') | 
 | 672 |         extrainfo = d.getVarFlag(taskflagname, 'stamp-extra-info') or "" | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 673 |  | 
 | 674 |     if baseonly: | 
 | 675 |         return stamp | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 676 |     if noextra: | 
 | 677 |         extrainfo = "" | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 678 |  | 
 | 679 |     if not stamp: | 
 | 680 |         return | 
 | 681 |  | 
 | 682 |     stamp = bb.parse.siggen.stampfile(stamp, file_name, taskname, extrainfo) | 
 | 683 |  | 
 | 684 |     stampdir = os.path.dirname(stamp) | 
 | 685 |     if cached_mtime_noerror(stampdir) == 0: | 
 | 686 |         bb.utils.mkdirhier(stampdir) | 
 | 687 |  | 
 | 688 |     return stamp | 
 | 689 |  | 
 | 690 | def stamp_cleanmask_internal(taskname, d, file_name): | 
 | 691 |     """ | 
 | 692 |     Internal stamp helper function to generate stamp cleaning mask | 
 | 693 |     Returns the stamp path+filename | 
 | 694 |  | 
 | 695 |     In the bitbake core, d can be a CacheData and file_name will be set. | 
 | 696 |     When called in task context, d will be a data store, file_name will not be set | 
 | 697 |     """ | 
 | 698 |     taskflagname = taskname | 
 | 699 |     if taskname.endswith("_setscene") and taskname != "do_setscene": | 
 | 700 |         taskflagname = taskname.replace("_setscene", "") | 
 | 701 |  | 
 | 702 |     if file_name: | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 703 |         stamp = d.stampclean[file_name] | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 704 |         extrainfo = d.stamp_extrainfo[file_name].get(taskflagname) or "" | 
 | 705 |     else: | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 706 |         stamp = d.getVar('STAMPCLEAN') | 
 | 707 |         file_name = d.getVar('BB_FILENAME') | 
 | 708 |         extrainfo = d.getVarFlag(taskflagname, 'stamp-extra-info') or "" | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 709 |  | 
 | 710 |     if not stamp: | 
 | 711 |         return [] | 
 | 712 |  | 
 | 713 |     cleanmask = bb.parse.siggen.stampcleanmask(stamp, file_name, taskname, extrainfo) | 
 | 714 |  | 
 | 715 |     return [cleanmask, cleanmask.replace(taskflagname, taskflagname + "_setscene")] | 
 | 716 |  | 
 | 717 | def make_stamp(task, d, file_name = None): | 
 | 718 |     """ | 
 | 719 |     Creates/updates a stamp for a given task | 
 | 720 |     (d can be a data dict or dataCache) | 
 | 721 |     """ | 
 | 722 |     cleanmask = stamp_cleanmask_internal(task, d, file_name) | 
 | 723 |     for mask in cleanmask: | 
 | 724 |         for name in glob.glob(mask): | 
 | 725 |             # Preserve sigdata files in the stamps directory | 
| Brad Bishop | 37a0e4d | 2017-12-04 01:01:44 -0500 | [diff] [blame] | 726 |             if "sigdata" in name or "sigbasedata" in name: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 727 |                 continue | 
 | 728 |             # Preserve taint files in the stamps directory | 
 | 729 |             if name.endswith('.taint'): | 
 | 730 |                 continue | 
 | 731 |             os.unlink(name) | 
 | 732 |  | 
 | 733 |     stamp = stamp_internal(task, d, file_name) | 
 | 734 |     # Remove the file and recreate to force timestamp | 
 | 735 |     # change on broken NFS filesystems | 
 | 736 |     if stamp: | 
 | 737 |         bb.utils.remove(stamp) | 
 | 738 |         open(stamp, "w").close() | 
 | 739 |  | 
 | 740 |     # If we're in task context, write out a signature file for each task | 
 | 741 |     # as it completes | 
 | 742 |     if not task.endswith("_setscene") and task != "do_setscene" and not file_name: | 
 | 743 |         stampbase = stamp_internal(task, d, None, True) | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 744 |         file_name = d.getVar('BB_FILENAME') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 745 |         bb.parse.siggen.dump_sigtask(file_name, task, stampbase, True) | 
 | 746 |  | 
 | 747 | def del_stamp(task, d, file_name = None): | 
 | 748 |     """ | 
 | 749 |     Removes a stamp for a given task | 
 | 750 |     (d can be a data dict or dataCache) | 
 | 751 |     """ | 
 | 752 |     stamp = stamp_internal(task, d, file_name) | 
 | 753 |     bb.utils.remove(stamp) | 
 | 754 |  | 
 | 755 | def write_taint(task, d, file_name = None): | 
 | 756 |     """ | 
 | 757 |     Creates a "taint" file which will force the specified task and its | 
 | 758 |     dependents to be re-run the next time by influencing the value of its | 
 | 759 |     taskhash. | 
 | 760 |     (d can be a data dict or dataCache) | 
 | 761 |     """ | 
 | 762 |     import uuid | 
 | 763 |     if file_name: | 
 | 764 |         taintfn = d.stamp[file_name] + '.' + task + '.taint' | 
 | 765 |     else: | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 766 |         taintfn = d.getVar('STAMP') + '.' + task + '.taint' | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 767 |     bb.utils.mkdirhier(os.path.dirname(taintfn)) | 
 | 768 |     # The specific content of the taint file is not really important, | 
 | 769 |     # we just need it to be random, so a random UUID is used | 
 | 770 |     with open(taintfn, 'w') as taintf: | 
 | 771 |         taintf.write(str(uuid.uuid4())) | 
 | 772 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 773 | def stampfile(taskname, d, file_name = None, noextra=False): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 774 |     """ | 
 | 775 |     Return the stamp for a given task | 
 | 776 |     (d can be a data dict or dataCache) | 
 | 777 |     """ | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 778 |     return stamp_internal(taskname, d, file_name, noextra=noextra) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 779 |  | 
 | 780 | def add_tasks(tasklist, d): | 
 | 781 |     task_deps = d.getVar('_task_deps', False) | 
 | 782 |     if not task_deps: | 
 | 783 |         task_deps = {} | 
 | 784 |     if not 'tasks' in task_deps: | 
 | 785 |         task_deps['tasks'] = [] | 
 | 786 |     if not 'parents' in task_deps: | 
 | 787 |         task_deps['parents'] = {} | 
 | 788 |  | 
 | 789 |     for task in tasklist: | 
 | 790 |         task = d.expand(task) | 
 | 791 |  | 
 | 792 |         d.setVarFlag(task, 'task', 1) | 
 | 793 |  | 
 | 794 |         if not task in task_deps['tasks']: | 
 | 795 |             task_deps['tasks'].append(task) | 
 | 796 |  | 
 | 797 |         flags = d.getVarFlags(task) | 
 | 798 |         def getTask(name): | 
 | 799 |             if not name in task_deps: | 
 | 800 |                 task_deps[name] = {} | 
 | 801 |             if name in flags: | 
 | 802 |                 deptask = d.expand(flags[name]) | 
 | 803 |                 task_deps[name][task] = deptask | 
| Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 804 |         getTask('mcdepends') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 805 |         getTask('depends') | 
 | 806 |         getTask('rdepends') | 
 | 807 |         getTask('deptask') | 
 | 808 |         getTask('rdeptask') | 
 | 809 |         getTask('recrdeptask') | 
 | 810 |         getTask('recideptask') | 
 | 811 |         getTask('nostamp') | 
 | 812 |         getTask('fakeroot') | 
 | 813 |         getTask('noexec') | 
 | 814 |         getTask('umask') | 
 | 815 |         task_deps['parents'][task] = [] | 
 | 816 |         if 'deps' in flags: | 
 | 817 |             for dep in flags['deps']: | 
 | 818 |                 dep = d.expand(dep) | 
 | 819 |                 task_deps['parents'][task].append(dep) | 
 | 820 |  | 
 | 821 |     # don't assume holding a reference | 
 | 822 |     d.setVar('_task_deps', task_deps) | 
 | 823 |  | 
 | 824 | def addtask(task, before, after, d): | 
 | 825 |     if task[:3] != "do_": | 
 | 826 |         task = "do_" + task | 
 | 827 |  | 
 | 828 |     d.setVarFlag(task, "task", 1) | 
 | 829 |     bbtasks = d.getVar('__BBTASKS', False) or [] | 
 | 830 |     if task not in bbtasks: | 
 | 831 |         bbtasks.append(task) | 
 | 832 |     d.setVar('__BBTASKS', bbtasks) | 
 | 833 |  | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 834 |     existing = d.getVarFlag(task, "deps", False) or [] | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 835 |     if after is not None: | 
 | 836 |         # set up deps for function | 
 | 837 |         for entry in after.split(): | 
 | 838 |             if entry not in existing: | 
 | 839 |                 existing.append(entry) | 
 | 840 |     d.setVarFlag(task, "deps", existing) | 
 | 841 |     if before is not None: | 
 | 842 |         # set up things that depend on this func | 
 | 843 |         for entry in before.split(): | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 844 |             existing = d.getVarFlag(entry, "deps", False) or [] | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 845 |             if task not in existing: | 
 | 846 |                 d.setVarFlag(entry, "deps", [task] + existing) | 
 | 847 |  | 
 | 848 | def deltask(task, d): | 
 | 849 |     if task[:3] != "do_": | 
 | 850 |         task = "do_" + task | 
 | 851 |  | 
 | 852 |     bbtasks = d.getVar('__BBTASKS', False) or [] | 
 | 853 |     if task in bbtasks: | 
 | 854 |         bbtasks.remove(task) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 855 |         d.delVarFlag(task, 'task') | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 856 |         d.setVar('__BBTASKS', bbtasks) | 
 | 857 |  | 
 | 858 |     d.delVarFlag(task, 'deps') | 
 | 859 |     for bbtask in d.getVar('__BBTASKS', False) or []: | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 860 |         deps = d.getVarFlag(bbtask, 'deps', False) or [] | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 861 |         if task in deps: | 
 | 862 |             deps.remove(task) | 
 | 863 |             d.setVarFlag(bbtask, 'deps', deps) | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 864 |  | 
 | 865 | def preceedtask(task, with_recrdeptasks, d): | 
 | 866 |     """ | 
 | 867 |     Returns a set of tasks in the current recipe which were specified as | 
 | 868 |     precondition by the task itself ("after") or which listed themselves | 
 | 869 |     as precondition ("before"). Preceeding tasks specified via the | 
 | 870 |     "recrdeptask" are included in the result only if requested. Beware | 
 | 871 |     that this may lead to the task itself being listed. | 
 | 872 |     """ | 
 | 873 |     preceed = set() | 
| Brad Bishop | 316dfdd | 2018-06-25 12:45:53 -0400 | [diff] [blame] | 874 |  | 
 | 875 |     # Ignore tasks which don't exist | 
 | 876 |     tasks = d.getVar('__BBTASKS', False) | 
 | 877 |     if task not in tasks: | 
 | 878 |         return preceed | 
 | 879 |  | 
| Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 880 |     preceed.update(d.getVarFlag(task, 'deps') or []) | 
 | 881 |     if with_recrdeptasks: | 
 | 882 |         recrdeptask = d.getVarFlag(task, 'recrdeptask') | 
 | 883 |         if recrdeptask: | 
 | 884 |             preceed.update(recrdeptask.split()) | 
 | 885 |     return preceed | 
 | 886 |  | 
 | 887 | def tasksbetween(task_start, task_end, d): | 
 | 888 |     """ | 
 | 889 |     Return the list of tasks between two tasks in the current recipe, | 
 | 890 |     where task_start is to start at and task_end is the task to end at | 
 | 891 |     (and task_end has a dependency chain back to task_start). | 
 | 892 |     """ | 
 | 893 |     outtasks = [] | 
 | 894 |     tasks = list(filter(lambda k: d.getVarFlag(k, "task"), d.keys())) | 
 | 895 |     def follow_chain(task, endtask, chain=None): | 
 | 896 |         if not chain: | 
 | 897 |             chain = [] | 
 | 898 |         chain.append(task) | 
 | 899 |         for othertask in tasks: | 
 | 900 |             if othertask == task: | 
 | 901 |                 continue | 
 | 902 |             if task == endtask: | 
 | 903 |                 for ctask in chain: | 
 | 904 |                     if ctask not in outtasks: | 
 | 905 |                         outtasks.append(ctask) | 
 | 906 |             else: | 
 | 907 |                 deps = d.getVarFlag(othertask, 'deps', False) | 
 | 908 |                 if task in deps: | 
 | 909 |                     follow_chain(othertask, endtask, chain) | 
 | 910 |         chain.pop() | 
 | 911 |     follow_chain(task_start, task_end) | 
 | 912 |     return outtasks |