1""" 2BitBake Parsers 3 4File parsers for the BitBake build tools. 5 6""" 7 8 9# Copyright (C) 2003, 2004 Chris Larson 10# Copyright (C) 2003, 2004 Phil Blundell 11# 12# SPDX-License-Identifier: GPL-2.0-only 13# 14# Based on functions from the base bb module, Copyright 2003 Holger Schurig 15# 16 17handlers = [] 18 19import errno 20import logging 21import os 22import stat 23import bb 24import bb.utils 25import bb.siggen 26 27logger = logging.getLogger("BitBake.Parsing") 28 29class ParseError(Exception): 30 """Exception raised when parsing fails""" 31 def __init__(self, msg, filename, lineno=0): 32 self.msg = msg 33 self.filename = filename 34 self.lineno = lineno 35 Exception.__init__(self, msg, filename, lineno) 36 37 def __str__(self): 38 if self.lineno: 39 return "ParseError at %s:%d: %s" % (self.filename, self.lineno, self.msg) 40 else: 41 return "ParseError in %s: %s" % (self.filename, self.msg) 42 43class SkipRecipe(Exception): 44 """Exception raised to skip this recipe""" 45 46class SkipPackage(SkipRecipe): 47 """Exception raised to skip this recipe (use SkipRecipe in new code)""" 48 49__mtime_cache = {} 50def cached_mtime(f): 51 if f not in __mtime_cache: 52 res = os.stat(f) 53 __mtime_cache[f] = (res.st_mtime_ns, res.st_size, res.st_ino) 54 return __mtime_cache[f] 55 56def cached_mtime_noerror(f): 57 if f not in __mtime_cache: 58 try: 59 res = os.stat(f) 60 __mtime_cache[f] = (res.st_mtime_ns, res.st_size, res.st_ino) 61 except OSError: 62 return 0 63 return __mtime_cache[f] 64 65def check_mtime(f, mtime): 66 try: 67 res = os.stat(f) 68 current_mtime = (res.st_mtime_ns, res.st_size, res.st_ino) 69 __mtime_cache[f] = current_mtime 70 except OSError: 71 current_mtime = 0 72 return current_mtime == mtime 73 74def update_mtime(f): 75 try: 76 res = os.stat(f) 77 __mtime_cache[f] = (res.st_mtime_ns, res.st_size, res.st_ino) 78 except OSError: 79 if f in __mtime_cache: 80 del __mtime_cache[f] 81 return 0 82 return __mtime_cache[f] 83 84def update_cache(f): 85 if f in __mtime_cache: 86 logger.debug("Updating mtime cache for %s" % f) 87 update_mtime(f) 88 89def clear_cache(): 90 global __mtime_cache 91 __mtime_cache = {} 92 93def mark_dependency(d, f): 94 if f.startswith('./'): 95 f = "%s/%s" % (os.getcwd(), f[2:]) 96 deps = (d.getVar('__depends', False) or []) 97 s = (f, cached_mtime_noerror(f)) 98 if s not in deps: 99 deps.append(s) 100 d.setVar('__depends', deps) 101 102def check_dependency(d, f): 103 s = (f, cached_mtime_noerror(f)) 104 deps = (d.getVar('__depends', False) or []) 105 return s in deps 106 107def supports(fn, data): 108 """Returns true if we have a handler for this file, false otherwise""" 109 for h in handlers: 110 if h['supports'](fn, data): 111 return 1 112 return 0 113 114def handle(fn, data, include=0, baseconfig=False): 115 """Call the handler that is appropriate for this file""" 116 for h in handlers: 117 if h['supports'](fn, data): 118 with data.inchistory.include(fn): 119 return h['handle'](fn, data, include, baseconfig) 120 raise ParseError("not a BitBake file", fn) 121 122def init(fn, data): 123 for h in handlers: 124 if h['supports'](fn): 125 return h['init'](data) 126 127def init_parser(d): 128 if hasattr(bb.parse, "siggen"): 129 bb.parse.siggen.exit() 130 bb.parse.siggen = bb.siggen.init(d) 131 132def resolve_file(fn, d): 133 if not os.path.isabs(fn): 134 bbpath = d.getVar("BBPATH") 135 newfn, attempts = bb.utils.which(bbpath, fn, history=True) 136 for af in attempts: 137 mark_dependency(d, af) 138 if not newfn: 139 raise IOError(errno.ENOENT, "file %s not found in %s" % (fn, bbpath)) 140 fn = newfn 141 else: 142 mark_dependency(d, fn) 143 144 if not os.path.isfile(fn): 145 raise IOError(errno.ENOENT, "file %s not found" % fn) 146 147 return fn 148 149# Used by OpenEmbedded metadata 150__pkgsplit_cache__={} 151def vars_from_file(mypkg, d): 152 if not mypkg or not mypkg.endswith((".bb", ".bbappend")): 153 return (None, None, None) 154 if mypkg in __pkgsplit_cache__: 155 return __pkgsplit_cache__[mypkg] 156 157 myfile = os.path.splitext(os.path.basename(mypkg)) 158 parts = myfile[0].split('_') 159 __pkgsplit_cache__[mypkg] = parts 160 if len(parts) > 3: 161 raise ParseError("Unable to generate default variables from filename (too many underscores)", mypkg) 162 exp = 3 - len(parts) 163 tmplist = [] 164 while exp != 0: 165 exp -= 1 166 tmplist.append(None) 167 parts.extend(tmplist) 168 return parts 169 170def get_file_depends(d): 171 '''Return the dependent files''' 172 dep_files = [] 173 depends = d.getVar('__base_depends', False) or [] 174 depends = depends + (d.getVar('__depends', False) or []) 175 for (fn, _) in depends: 176 dep_files.append(os.path.abspath(fn)) 177 return " ".join(dep_files) 178 179from bb.parse.parse_py import __version__, ConfHandler, BBHandler 180