1eb8dc403SDave Cobbley#!/usr/bin/env python3 2eb8dc403SDave Cobbley 3eb8dc403SDave Cobbley# Development tool - utility functions for plugins 4eb8dc403SDave Cobbley# 5eb8dc403SDave Cobbley# Copyright (C) 2014 Intel Corporation 6eb8dc403SDave Cobbley# 7c342db35SBrad Bishop# SPDX-License-Identifier: GPL-2.0-only 8eb8dc403SDave Cobbley# 9eb8dc403SDave Cobbley"""Devtool plugins module""" 10eb8dc403SDave Cobbley 11eb8dc403SDave Cobbleyimport os 12eb8dc403SDave Cobbleyimport sys 13eb8dc403SDave Cobbleyimport subprocess 14eb8dc403SDave Cobbleyimport logging 15eb8dc403SDave Cobbleyimport re 16eb8dc403SDave Cobbleyimport codecs 17eb8dc403SDave Cobbley 18eb8dc403SDave Cobbleylogger = logging.getLogger('devtool') 19eb8dc403SDave Cobbley 20eb8dc403SDave Cobbleyclass DevtoolError(Exception): 21eb8dc403SDave Cobbley """Exception for handling devtool errors""" 22eb8dc403SDave Cobbley def __init__(self, message, exitcode=1): 23eb8dc403SDave Cobbley super(DevtoolError, self).__init__(message) 24eb8dc403SDave Cobbley self.exitcode = exitcode 25eb8dc403SDave Cobbley 26eb8dc403SDave Cobbley 27eb8dc403SDave Cobbleydef exec_build_env_command(init_path, builddir, cmd, watch=False, **options): 28eb8dc403SDave Cobbley """Run a program in bitbake build context""" 29eb8dc403SDave Cobbley import bb 30eb8dc403SDave Cobbley if not 'cwd' in options: 31eb8dc403SDave Cobbley options["cwd"] = builddir 32eb8dc403SDave Cobbley if init_path: 33eb8dc403SDave Cobbley # As the OE init script makes use of BASH_SOURCE to determine OEROOT, 34eb8dc403SDave Cobbley # and can't determine it when running under dash, we need to set 35eb8dc403SDave Cobbley # the executable to bash to correctly set things up 36eb8dc403SDave Cobbley if not 'executable' in options: 37eb8dc403SDave Cobbley options['executable'] = 'bash' 38eb8dc403SDave Cobbley logger.debug('Executing command: "%s" using init path %s' % (cmd, init_path)) 39eb8dc403SDave Cobbley init_prefix = '. %s %s > /dev/null && ' % (init_path, builddir) 40eb8dc403SDave Cobbley else: 41eb8dc403SDave Cobbley logger.debug('Executing command "%s"' % cmd) 42eb8dc403SDave Cobbley init_prefix = '' 43eb8dc403SDave Cobbley if watch: 44eb8dc403SDave Cobbley if sys.stdout.isatty(): 45eb8dc403SDave Cobbley # Fool bitbake into thinking it's outputting to a terminal (because it is, indirectly) 46eb8dc403SDave Cobbley cmd = 'script -e -q -c "%s" /dev/null' % cmd 47eb8dc403SDave Cobbley return exec_watch('%s%s' % (init_prefix, cmd), **options) 48eb8dc403SDave Cobbley else: 49eb8dc403SDave Cobbley return bb.process.run('%s%s' % (init_prefix, cmd), **options) 50eb8dc403SDave Cobbley 51eb8dc403SDave Cobbleydef exec_watch(cmd, **options): 52eb8dc403SDave Cobbley """Run program with stdout shown on sys.stdout""" 53eb8dc403SDave Cobbley import bb 54eb8dc403SDave Cobbley if isinstance(cmd, str) and not "shell" in options: 55eb8dc403SDave Cobbley options["shell"] = True 56eb8dc403SDave Cobbley 57eb8dc403SDave Cobbley process = subprocess.Popen( 58eb8dc403SDave Cobbley cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **options 59eb8dc403SDave Cobbley ) 60eb8dc403SDave Cobbley 61eb8dc403SDave Cobbley reader = codecs.getreader('utf-8')(process.stdout) 62eb8dc403SDave Cobbley buf = '' 63eb8dc403SDave Cobbley while True: 64eb8dc403SDave Cobbley out = reader.read(1, 1) 65eb8dc403SDave Cobbley if out: 66eb8dc403SDave Cobbley sys.stdout.write(out) 67eb8dc403SDave Cobbley sys.stdout.flush() 68eb8dc403SDave Cobbley buf += out 69eb8dc403SDave Cobbley elif out == '' and process.poll() != None: 70eb8dc403SDave Cobbley break 71eb8dc403SDave Cobbley 72eb8dc403SDave Cobbley if process.returncode != 0: 73eb8dc403SDave Cobbley raise bb.process.ExecutionError(cmd, process.returncode, buf, None) 74eb8dc403SDave Cobbley 75eb8dc403SDave Cobbley return buf, None 76eb8dc403SDave Cobbley 77eb8dc403SDave Cobbleydef exec_fakeroot(d, cmd, **kwargs): 78eb8dc403SDave Cobbley """Run a command under fakeroot (pseudo, in fact) so that it picks up the appropriate file permissions""" 79eb8dc403SDave Cobbley # Grab the command and check it actually exists 80eb8dc403SDave Cobbley fakerootcmd = d.getVar('FAKEROOTCMD') 81*73bd93f1SPatrick Williams fakerootenv = d.getVar('FAKEROOTENV') 82*73bd93f1SPatrick Williams exec_fakeroot_no_d(fakerootcmd, fakerootenv, cmd, kwargs) 83*73bd93f1SPatrick Williams 84*73bd93f1SPatrick Williamsdef exec_fakeroot_no_d(fakerootcmd, fakerootenv, cmd, **kwargs): 85eb8dc403SDave Cobbley if not os.path.exists(fakerootcmd): 86eb8dc403SDave Cobbley logger.error('pseudo executable %s could not be found - have you run a build yet? pseudo-native should install this and if you have run any build then that should have been built') 87eb8dc403SDave Cobbley return 2 88eb8dc403SDave Cobbley # Set up the appropriate environment 89eb8dc403SDave Cobbley newenv = dict(os.environ) 90eb8dc403SDave Cobbley for varvalue in fakerootenv.split(): 91eb8dc403SDave Cobbley if '=' in varvalue: 92eb8dc403SDave Cobbley splitval = varvalue.split('=', 1) 93eb8dc403SDave Cobbley newenv[splitval[0]] = splitval[1] 94eb8dc403SDave Cobbley return subprocess.call("%s %s" % (fakerootcmd, cmd), env=newenv, **kwargs) 95eb8dc403SDave Cobbley 96eb8dc403SDave Cobbleydef setup_tinfoil(config_only=False, basepath=None, tracking=False): 97eb8dc403SDave Cobbley """Initialize tinfoil api from bitbake""" 98eb8dc403SDave Cobbley import scriptpath 99eb8dc403SDave Cobbley orig_cwd = os.path.abspath(os.curdir) 100eb8dc403SDave Cobbley try: 101eb8dc403SDave Cobbley if basepath: 102eb8dc403SDave Cobbley os.chdir(basepath) 103eb8dc403SDave Cobbley bitbakepath = scriptpath.add_bitbake_lib_path() 104eb8dc403SDave Cobbley if not bitbakepath: 105eb8dc403SDave Cobbley logger.error("Unable to find bitbake by searching parent directory of this script or PATH") 106eb8dc403SDave Cobbley sys.exit(1) 107eb8dc403SDave Cobbley 108eb8dc403SDave Cobbley import bb.tinfoil 109eb8dc403SDave Cobbley tinfoil = bb.tinfoil.Tinfoil(tracking=tracking) 110eb8dc403SDave Cobbley try: 111eb8dc403SDave Cobbley tinfoil.logger.setLevel(logger.getEffectiveLevel()) 112eb8dc403SDave Cobbley tinfoil.prepare(config_only) 113eb8dc403SDave Cobbley except bb.tinfoil.TinfoilUIException: 114eb8dc403SDave Cobbley tinfoil.shutdown() 115eb8dc403SDave Cobbley raise DevtoolError('Failed to start bitbake environment') 116eb8dc403SDave Cobbley except: 117eb8dc403SDave Cobbley tinfoil.shutdown() 118eb8dc403SDave Cobbley raise 119eb8dc403SDave Cobbley finally: 120eb8dc403SDave Cobbley os.chdir(orig_cwd) 121eb8dc403SDave Cobbley return tinfoil 122eb8dc403SDave Cobbley 123eb8dc403SDave Cobbleydef parse_recipe(config, tinfoil, pn, appends, filter_workspace=True): 124eb8dc403SDave Cobbley """Parse the specified recipe""" 125eb8dc403SDave Cobbley try: 126eb8dc403SDave Cobbley recipefile = tinfoil.get_recipe_file(pn) 127eb8dc403SDave Cobbley except bb.providers.NoProvider as e: 128eb8dc403SDave Cobbley logger.error(str(e)) 129eb8dc403SDave Cobbley return None 130eb8dc403SDave Cobbley if appends: 131eb8dc403SDave Cobbley append_files = tinfoil.get_file_appends(recipefile) 132eb8dc403SDave Cobbley if filter_workspace: 133eb8dc403SDave Cobbley # Filter out appends from the workspace 134eb8dc403SDave Cobbley append_files = [path for path in append_files if 135eb8dc403SDave Cobbley not path.startswith(config.workspace_path)] 136eb8dc403SDave Cobbley else: 137eb8dc403SDave Cobbley append_files = None 138eb8dc403SDave Cobbley try: 139eb8dc403SDave Cobbley rd = tinfoil.parse_recipe_file(recipefile, appends, append_files) 140eb8dc403SDave Cobbley except Exception as e: 141eb8dc403SDave Cobbley logger.error(str(e)) 142eb8dc403SDave Cobbley return None 143eb8dc403SDave Cobbley return rd 144eb8dc403SDave Cobbley 145eb8dc403SDave Cobbleydef check_workspace_recipe(workspace, pn, checksrc=True, bbclassextend=False): 146eb8dc403SDave Cobbley """ 147eb8dc403SDave Cobbley Check that a recipe is in the workspace and (optionally) that source 148eb8dc403SDave Cobbley is present. 149eb8dc403SDave Cobbley """ 150eb8dc403SDave Cobbley 151eb8dc403SDave Cobbley workspacepn = pn 152eb8dc403SDave Cobbley 153eb8dc403SDave Cobbley for recipe, value in workspace.items(): 154eb8dc403SDave Cobbley if recipe == pn: 155eb8dc403SDave Cobbley break 156eb8dc403SDave Cobbley if bbclassextend: 157eb8dc403SDave Cobbley recipefile = value['recipefile'] 158eb8dc403SDave Cobbley if recipefile: 159eb8dc403SDave Cobbley targets = get_bbclassextend_targets(recipefile, recipe) 160eb8dc403SDave Cobbley if pn in targets: 161eb8dc403SDave Cobbley workspacepn = recipe 162eb8dc403SDave Cobbley break 163eb8dc403SDave Cobbley else: 164eb8dc403SDave Cobbley raise DevtoolError("No recipe named '%s' in your workspace" % pn) 165eb8dc403SDave Cobbley 166eb8dc403SDave Cobbley if checksrc: 167eb8dc403SDave Cobbley srctree = workspace[workspacepn]['srctree'] 168eb8dc403SDave Cobbley if not os.path.exists(srctree): 169eb8dc403SDave Cobbley raise DevtoolError("Source tree %s for recipe %s does not exist" % (srctree, workspacepn)) 170eb8dc403SDave Cobbley if not os.listdir(srctree): 171eb8dc403SDave Cobbley raise DevtoolError("Source tree %s for recipe %s is empty" % (srctree, workspacepn)) 172eb8dc403SDave Cobbley 173eb8dc403SDave Cobbley return workspacepn 174eb8dc403SDave Cobbley 175eb8dc403SDave Cobbleydef use_external_build(same_dir, no_same_dir, d): 176eb8dc403SDave Cobbley """ 177eb8dc403SDave Cobbley Determine if we should use B!=S (separate build and source directories) or not 178eb8dc403SDave Cobbley """ 179eb8dc403SDave Cobbley b_is_s = True 180eb8dc403SDave Cobbley if no_same_dir: 181eb8dc403SDave Cobbley logger.info('Using separate build directory since --no-same-dir specified') 182eb8dc403SDave Cobbley b_is_s = False 183eb8dc403SDave Cobbley elif same_dir: 184eb8dc403SDave Cobbley logger.info('Using source tree as build directory since --same-dir specified') 185eb8dc403SDave Cobbley elif bb.data.inherits_class('autotools-brokensep', d): 186eb8dc403SDave Cobbley logger.info('Using source tree as build directory since recipe inherits autotools-brokensep') 187eb8dc403SDave Cobbley elif os.path.abspath(d.getVar('B')) == os.path.abspath(d.getVar('S')): 188eb8dc403SDave Cobbley logger.info('Using source tree as build directory since that would be the default for this recipe') 189eb8dc403SDave Cobbley else: 190eb8dc403SDave Cobbley b_is_s = False 191eb8dc403SDave Cobbley return b_is_s 192eb8dc403SDave Cobbley 193eb8dc403SDave Cobbleydef setup_git_repo(repodir, version, devbranch, basetag='devtool-base', d=None): 194eb8dc403SDave Cobbley """ 195eb8dc403SDave Cobbley Set up the git repository for the source tree 196eb8dc403SDave Cobbley """ 197eb8dc403SDave Cobbley import bb.process 198eb8dc403SDave Cobbley import oe.patch 199eb8dc403SDave Cobbley if not os.path.exists(os.path.join(repodir, '.git')): 200eb8dc403SDave Cobbley bb.process.run('git init', cwd=repodir) 20119323693SBrad Bishop bb.process.run('git config --local gc.autodetach 0', cwd=repodir) 2024ed12e16SAndrew Geissler bb.process.run('git add -f -A .', cwd=repodir) 203eb8dc403SDave Cobbley commit_cmd = ['git'] 204eb8dc403SDave Cobbley oe.patch.GitApplyTree.gitCommandUserOptions(commit_cmd, d=d) 205eb8dc403SDave Cobbley commit_cmd += ['commit', '-q'] 206eb8dc403SDave Cobbley stdout, _ = bb.process.run('git status --porcelain', cwd=repodir) 207eb8dc403SDave Cobbley if not stdout: 208eb8dc403SDave Cobbley commit_cmd.append('--allow-empty') 209eb8dc403SDave Cobbley commitmsg = "Initial empty commit with no upstream sources" 210eb8dc403SDave Cobbley elif version: 211eb8dc403SDave Cobbley commitmsg = "Initial commit from upstream at version %s" % version 212eb8dc403SDave Cobbley else: 213eb8dc403SDave Cobbley commitmsg = "Initial commit from upstream" 214eb8dc403SDave Cobbley commit_cmd += ['-m', commitmsg] 215eb8dc403SDave Cobbley bb.process.run(commit_cmd, cwd=repodir) 216eb8dc403SDave Cobbley 217eb8dc403SDave Cobbley # Ensure singletask.lock (as used by externalsrc.bbclass) is ignored by git 2184c19ea12SAndrew Geissler gitinfodir = os.path.join(repodir, '.git', 'info') 2194c19ea12SAndrew Geissler try: 2204c19ea12SAndrew Geissler os.mkdir(gitinfodir) 2214c19ea12SAndrew Geissler except FileExistsError: 2224c19ea12SAndrew Geissler pass 223eb8dc403SDave Cobbley excludes = [] 2244c19ea12SAndrew Geissler excludefile = os.path.join(gitinfodir, 'exclude') 225eb8dc403SDave Cobbley try: 226eb8dc403SDave Cobbley with open(excludefile, 'r') as f: 227eb8dc403SDave Cobbley excludes = f.readlines() 228eb8dc403SDave Cobbley except FileNotFoundError: 229eb8dc403SDave Cobbley pass 230eb8dc403SDave Cobbley if 'singletask.lock\n' not in excludes: 231eb8dc403SDave Cobbley excludes.append('singletask.lock\n') 232eb8dc403SDave Cobbley with open(excludefile, 'w') as f: 233eb8dc403SDave Cobbley for line in excludes: 234eb8dc403SDave Cobbley f.write(line) 235eb8dc403SDave Cobbley 236eb8dc403SDave Cobbley bb.process.run('git checkout -b %s' % devbranch, cwd=repodir) 237eb8dc403SDave Cobbley bb.process.run('git tag -f %s' % basetag, cwd=repodir) 238eb8dc403SDave Cobbley 239da295319SPatrick Williams # if recipe unpacks another git repo inside S, we need to declare it as a regular git submodule now, 240da295319SPatrick Williams # so we will be able to tag branches on it and extract patches when doing finish/update on the recipe 241da295319SPatrick Williams stdout, _ = bb.process.run("git status --porcelain", cwd=repodir) 242da295319SPatrick Williams found = False 243da295319SPatrick Williams for line in stdout.splitlines(): 244da295319SPatrick Williams if line.endswith("/"): 245da295319SPatrick Williams new_dir = line.split()[1] 246da295319SPatrick Williams for root, dirs, files in os.walk(os.path.join(repodir, new_dir)): 247da295319SPatrick Williams if ".git" in dirs + files: 248da295319SPatrick Williams (stdout, _) = bb.process.run('git remote', cwd=root) 249da295319SPatrick Williams remote = stdout.splitlines()[0] 250da295319SPatrick Williams (stdout, _) = bb.process.run('git remote get-url %s' % remote, cwd=root) 251da295319SPatrick Williams remote_url = stdout.splitlines()[0] 252da295319SPatrick Williams logger.error(os.path.relpath(os.path.join(root, ".."), root)) 253da295319SPatrick Williams bb.process.run('git submodule add %s %s' % (remote_url, os.path.relpath(root, os.path.join(root, ".."))), cwd=os.path.join(root, "..")) 254da295319SPatrick Williams found = True 255da295319SPatrick Williams if found: 256*73bd93f1SPatrick Williams oe.patch.GitApplyTree.commitIgnored("Add additional submodule from SRC_URI", dir=os.path.join(root, ".."), d=d) 257da295319SPatrick Williams found = False 258da295319SPatrick Williams if os.path.exists(os.path.join(repodir, '.gitmodules')): 259da295319SPatrick Williams bb.process.run('git submodule foreach --recursive "git tag -f %s"' % basetag, cwd=repodir) 260da295319SPatrick Williams 261eb8dc403SDave Cobbleydef recipe_to_append(recipefile, config, wildcard=False): 262eb8dc403SDave Cobbley """ 263eb8dc403SDave Cobbley Convert a recipe file to a bbappend file path within the workspace. 264eb8dc403SDave Cobbley NOTE: if the bbappend already exists, you should be using 265eb8dc403SDave Cobbley workspace[args.recipename]['bbappend'] instead of calling this 266eb8dc403SDave Cobbley function. 267eb8dc403SDave Cobbley """ 268eb8dc403SDave Cobbley appendname = os.path.splitext(os.path.basename(recipefile))[0] 269eb8dc403SDave Cobbley if wildcard: 270eb8dc403SDave Cobbley appendname = re.sub(r'_.*', '_%', appendname) 271eb8dc403SDave Cobbley appendpath = os.path.join(config.workspace_path, 'appends') 272eb8dc403SDave Cobbley appendfile = os.path.join(appendpath, appendname + '.bbappend') 273eb8dc403SDave Cobbley return appendfile 274eb8dc403SDave Cobbley 275eb8dc403SDave Cobbleydef get_bbclassextend_targets(recipefile, pn): 276eb8dc403SDave Cobbley """ 277eb8dc403SDave Cobbley Cheap function to get BBCLASSEXTEND and then convert that to the 278eb8dc403SDave Cobbley list of targets that would result. 279eb8dc403SDave Cobbley """ 280eb8dc403SDave Cobbley import bb.utils 281eb8dc403SDave Cobbley 282eb8dc403SDave Cobbley values = {} 283eb8dc403SDave Cobbley def get_bbclassextend_varfunc(varname, origvalue, op, newlines): 284eb8dc403SDave Cobbley values[varname] = origvalue 285eb8dc403SDave Cobbley return origvalue, None, 0, True 286eb8dc403SDave Cobbley with open(recipefile, 'r') as f: 287eb8dc403SDave Cobbley bb.utils.edit_metadata(f, ['BBCLASSEXTEND'], get_bbclassextend_varfunc) 288eb8dc403SDave Cobbley 289eb8dc403SDave Cobbley targets = [] 290eb8dc403SDave Cobbley bbclassextend = values.get('BBCLASSEXTEND', '').split() 291eb8dc403SDave Cobbley if bbclassextend: 292eb8dc403SDave Cobbley for variant in bbclassextend: 293eb8dc403SDave Cobbley if variant == 'nativesdk': 294eb8dc403SDave Cobbley targets.append('%s-%s' % (variant, pn)) 295eb8dc403SDave Cobbley elif variant in ['native', 'cross', 'crosssdk']: 296eb8dc403SDave Cobbley targets.append('%s-%s' % (pn, variant)) 297eb8dc403SDave Cobbley return targets 298eb8dc403SDave Cobbley 299eb8dc403SDave Cobbleydef replace_from_file(path, old, new): 300eb8dc403SDave Cobbley """Replace strings on a file""" 301eb8dc403SDave Cobbley 302eb8dc403SDave Cobbley def read_file(path): 303eb8dc403SDave Cobbley data = None 304eb8dc403SDave Cobbley with open(path) as f: 305eb8dc403SDave Cobbley data = f.read() 306eb8dc403SDave Cobbley return data 307eb8dc403SDave Cobbley 308eb8dc403SDave Cobbley def write_file(path, data): 309eb8dc403SDave Cobbley if data is None: 310eb8dc403SDave Cobbley return 311eb8dc403SDave Cobbley wdata = data.rstrip() + "\n" 312eb8dc403SDave Cobbley with open(path, "w") as f: 313eb8dc403SDave Cobbley f.write(wdata) 314eb8dc403SDave Cobbley 315eb8dc403SDave Cobbley # In case old is None, return immediately 316eb8dc403SDave Cobbley if old is None: 317eb8dc403SDave Cobbley return 318eb8dc403SDave Cobbley try: 319eb8dc403SDave Cobbley rdata = read_file(path) 320eb8dc403SDave Cobbley except IOError as e: 321eb8dc403SDave Cobbley # if file does not exit, just quit, otherwise raise an exception 322eb8dc403SDave Cobbley if e.errno == errno.ENOENT: 323eb8dc403SDave Cobbley return 324eb8dc403SDave Cobbley else: 325eb8dc403SDave Cobbley raise 326eb8dc403SDave Cobbley 327eb8dc403SDave Cobbley old_contents = rdata.splitlines() 328eb8dc403SDave Cobbley new_contents = [] 329eb8dc403SDave Cobbley for old_content in old_contents: 330eb8dc403SDave Cobbley try: 331eb8dc403SDave Cobbley new_contents.append(old_content.replace(old, new)) 332eb8dc403SDave Cobbley except ValueError: 333eb8dc403SDave Cobbley pass 334eb8dc403SDave Cobbley write_file(path, "\n".join(new_contents)) 335eb8dc403SDave Cobbley 336eb8dc403SDave Cobbley 337eb8dc403SDave Cobbleydef update_unlockedsigs(basepath, workspace, fixed_setup, extra=None): 338eb8dc403SDave Cobbley """ This function will make unlocked-sigs.inc match the recipes in the 339eb8dc403SDave Cobbley workspace plus any extras we want unlocked. """ 340eb8dc403SDave Cobbley 341eb8dc403SDave Cobbley if not fixed_setup: 342eb8dc403SDave Cobbley # Only need to write this out within the eSDK 343eb8dc403SDave Cobbley return 344eb8dc403SDave Cobbley 345eb8dc403SDave Cobbley if not extra: 346eb8dc403SDave Cobbley extra = [] 347eb8dc403SDave Cobbley 348eb8dc403SDave Cobbley confdir = os.path.join(basepath, 'conf') 349eb8dc403SDave Cobbley unlockedsigs = os.path.join(confdir, 'unlocked-sigs.inc') 350eb8dc403SDave Cobbley 351eb8dc403SDave Cobbley # Get current unlocked list if any 352eb8dc403SDave Cobbley values = {} 353eb8dc403SDave Cobbley def get_unlockedsigs_varfunc(varname, origvalue, op, newlines): 354eb8dc403SDave Cobbley values[varname] = origvalue 355eb8dc403SDave Cobbley return origvalue, None, 0, True 356eb8dc403SDave Cobbley if os.path.exists(unlockedsigs): 357eb8dc403SDave Cobbley with open(unlockedsigs, 'r') as f: 358eb8dc403SDave Cobbley bb.utils.edit_metadata(f, ['SIGGEN_UNLOCKED_RECIPES'], get_unlockedsigs_varfunc) 359eb8dc403SDave Cobbley unlocked = sorted(values.get('SIGGEN_UNLOCKED_RECIPES', [])) 360eb8dc403SDave Cobbley 361eb8dc403SDave Cobbley # If the new list is different to the current list, write it out 362eb8dc403SDave Cobbley newunlocked = sorted(list(workspace.keys()) + extra) 363eb8dc403SDave Cobbley if unlocked != newunlocked: 364eb8dc403SDave Cobbley bb.utils.mkdirhier(confdir) 365eb8dc403SDave Cobbley with open(unlockedsigs, 'w') as f: 366eb8dc403SDave Cobbley f.write("# DO NOT MODIFY! YOUR CHANGES WILL BE LOST.\n" + 367eb8dc403SDave Cobbley "# This layer was created by the OpenEmbedded devtool" + 368eb8dc403SDave Cobbley " utility in order to\n" + 369eb8dc403SDave Cobbley "# contain recipes that are unlocked.\n") 370eb8dc403SDave Cobbley 371eb8dc403SDave Cobbley f.write('SIGGEN_UNLOCKED_RECIPES += "\\\n') 372eb8dc403SDave Cobbley for pn in newunlocked: 373eb8dc403SDave Cobbley f.write(' ' + pn) 374eb8dc403SDave Cobbley f.write('"') 375eb8dc403SDave Cobbley 376eb8dc403SDave Cobbleydef check_prerelease_version(ver, operation): 377eb8dc403SDave Cobbley if 'pre' in ver or 'rc' in ver: 378eb8dc403SDave Cobbley logger.warning('Version "%s" looks like a pre-release version. ' 379eb8dc403SDave Cobbley 'If that is the case, in order to ensure that the ' 380eb8dc403SDave Cobbley 'version doesn\'t appear to go backwards when you ' 381eb8dc403SDave Cobbley 'later upgrade to the final release version, it is ' 382eb8dc403SDave Cobbley 'recommmended that instead you use ' 383eb8dc403SDave Cobbley '<current version>+<pre-release version> e.g. if ' 384eb8dc403SDave Cobbley 'upgrading from 1.9 to 2.0-rc2 use "1.9+2.0-rc2". ' 385eb8dc403SDave Cobbley 'If you prefer not to reset and re-try, you can change ' 386eb8dc403SDave Cobbley 'the version after %s succeeds using "devtool rename" ' 387eb8dc403SDave Cobbley 'with -V/--version.' % (ver, operation)) 388eb8dc403SDave Cobbley 389eb8dc403SDave Cobbleydef check_git_repo_dirty(repodir): 390eb8dc403SDave Cobbley """Check if a git repository is clean or not""" 391eb8dc403SDave Cobbley stdout, _ = bb.process.run('git status --porcelain', cwd=repodir) 392eb8dc403SDave Cobbley return stdout 393eb8dc403SDave Cobbley 394eb8dc403SDave Cobbleydef check_git_repo_op(srctree, ignoredirs=None): 395eb8dc403SDave Cobbley """Check if a git repository is in the middle of a rebase""" 396eb8dc403SDave Cobbley stdout, _ = bb.process.run('git rev-parse --show-toplevel', cwd=srctree) 397eb8dc403SDave Cobbley topleveldir = stdout.strip() 398eb8dc403SDave Cobbley if ignoredirs and topleveldir in ignoredirs: 399eb8dc403SDave Cobbley return 400eb8dc403SDave Cobbley gitdir = os.path.join(topleveldir, '.git') 401eb8dc403SDave Cobbley if os.path.exists(os.path.join(gitdir, 'rebase-merge')): 402eb8dc403SDave Cobbley raise DevtoolError("Source tree %s appears to be in the middle of a rebase - please resolve this first" % srctree) 403eb8dc403SDave Cobbley if os.path.exists(os.path.join(gitdir, 'rebase-apply')): 404eb8dc403SDave Cobbley raise DevtoolError("Source tree %s appears to be in the middle of 'git am' or 'git apply' - please resolve this first" % srctree) 405