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 __mtime_cache[f] = os.stat(f)[stat.ST_MTIME] 53 return __mtime_cache[f] 54 55def cached_mtime_noerror(f): 56 if f not in __mtime_cache: 57 try: 58 __mtime_cache[f] = os.stat(f)[stat.ST_MTIME] 59 except OSError: 60 return 0 61 return __mtime_cache[f] 62 63def check_mtime(f, mtime): 64 try: 65 current_mtime = os.stat(f)[stat.ST_MTIME] 66 __mtime_cache[f] = current_mtime 67 except OSError: 68 current_mtime = 0 69 return current_mtime == mtime 70 71def update_mtime(f): 72 try: 73 __mtime_cache[f] = os.stat(f)[stat.ST_MTIME] 74 except OSError: 75 if f in __mtime_cache: 76 del __mtime_cache[f] 77 return 0 78 return __mtime_cache[f] 79 80def update_cache(f): 81 if f in __mtime_cache: 82 logger.debug("Updating mtime cache for %s" % f) 83 update_mtime(f) 84 85def clear_cache(): 86 global __mtime_cache 87 __mtime_cache = {} 88 89def mark_dependency(d, f): 90 if f.startswith('./'): 91 f = "%s/%s" % (os.getcwd(), f[2:]) 92 deps = (d.getVar('__depends', False) or []) 93 s = (f, cached_mtime_noerror(f)) 94 if s not in deps: 95 deps.append(s) 96 d.setVar('__depends', deps) 97 98def check_dependency(d, f): 99 s = (f, cached_mtime_noerror(f)) 100 deps = (d.getVar('__depends', False) or []) 101 return s in deps 102 103def supports(fn, data): 104 """Returns true if we have a handler for this file, false otherwise""" 105 for h in handlers: 106 if h['supports'](fn, data): 107 return 1 108 return 0 109 110def handle(fn, data, include=0, baseconfig=False): 111 """Call the handler that is appropriate for this file""" 112 for h in handlers: 113 if h['supports'](fn, data): 114 with data.inchistory.include(fn): 115 return h['handle'](fn, data, include, baseconfig) 116 raise ParseError("not a BitBake file", fn) 117 118def init(fn, data): 119 for h in handlers: 120 if h['supports'](fn): 121 return h['init'](data) 122 123def init_parser(d): 124 if hasattr(bb.parse, "siggen"): 125 bb.parse.siggen.exit() 126 bb.parse.siggen = bb.siggen.init(d) 127 128def resolve_file(fn, d): 129 if not os.path.isabs(fn): 130 bbpath = d.getVar("BBPATH") 131 newfn, attempts = bb.utils.which(bbpath, fn, history=True) 132 for af in attempts: 133 mark_dependency(d, af) 134 if not newfn: 135 raise IOError(errno.ENOENT, "file %s not found in %s" % (fn, bbpath)) 136 fn = newfn 137 else: 138 mark_dependency(d, fn) 139 140 if not os.path.isfile(fn): 141 raise IOError(errno.ENOENT, "file %s not found" % fn) 142 143 return fn 144 145# Used by OpenEmbedded metadata 146__pkgsplit_cache__={} 147def vars_from_file(mypkg, d): 148 if not mypkg or not mypkg.endswith((".bb", ".bbappend")): 149 return (None, None, None) 150 if mypkg in __pkgsplit_cache__: 151 return __pkgsplit_cache__[mypkg] 152 153 myfile = os.path.splitext(os.path.basename(mypkg)) 154 parts = myfile[0].split('_') 155 __pkgsplit_cache__[mypkg] = parts 156 if len(parts) > 3: 157 raise ParseError("Unable to generate default variables from filename (too many underscores)", mypkg) 158 exp = 3 - len(parts) 159 tmplist = [] 160 while exp != 0: 161 exp -= 1 162 tmplist.append(None) 163 parts.extend(tmplist) 164 return parts 165 166def get_file_depends(d): 167 '''Return the dependent files''' 168 dep_files = [] 169 depends = d.getVar('__base_depends', False) or [] 170 depends = depends + (d.getVar('__depends', False) or []) 171 for (fn, _) in depends: 172 dep_files.append(os.path.abspath(fn)) 173 return " ".join(dep_files) 174 175from bb.parse.parse_py import __version__, ConfHandler, BBHandler 176