1*4882a593Smuzhiyun#!/usr/bin/env python3 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# Conversion script to add new override syntax to existing bitbake metadata 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun# Copyright (C) 2021 Richard Purdie 6*4882a593Smuzhiyun# 7*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 8*4882a593Smuzhiyun# 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun# 11*4882a593Smuzhiyun# To use this script on a new layer you need to list the overrides the 12*4882a593Smuzhiyun# layer is known to use in the list below. 13*4882a593Smuzhiyun# 14*4882a593Smuzhiyun# Known constraint: Matching is 'loose' and in particular will find variable 15*4882a593Smuzhiyun# and function names with "_append" and "_remove" in them. Those need to be 16*4882a593Smuzhiyun# filtered out manually or in the skip list below. 17*4882a593Smuzhiyun# 18*4882a593Smuzhiyun 19*4882a593Smuzhiyunimport re 20*4882a593Smuzhiyunimport os 21*4882a593Smuzhiyunimport sys 22*4882a593Smuzhiyunimport tempfile 23*4882a593Smuzhiyunimport shutil 24*4882a593Smuzhiyunimport mimetypes 25*4882a593Smuzhiyunimport argparse 26*4882a593Smuzhiyun 27*4882a593Smuzhiyunparser = argparse.ArgumentParser(description="Convert override syntax") 28*4882a593Smuzhiyunparser.add_argument("--override", "-o", action="append", default=[], help="Add additional strings to consider as an override (e.g. custom machines/distros") 29*4882a593Smuzhiyunparser.add_argument("--skip", "-s", action="append", default=[], help="Add additional string to skip and not consider an override") 30*4882a593Smuzhiyunparser.add_argument("--skip-ext", "-e", action="append", default=[], help="Additional file suffixes to skip when processing (e.g. '.foo')") 31*4882a593Smuzhiyunparser.add_argument("--package-vars", action="append", default=[], help="Additional variables to treat as package variables") 32*4882a593Smuzhiyunparser.add_argument("--image-vars", action="append", default=[], help="Additional variables to treat as image variables") 33*4882a593Smuzhiyunparser.add_argument("--short-override", action="append", default=[], help="Additional strings to treat as short overrides") 34*4882a593Smuzhiyunparser.add_argument("path", nargs="+", help="Paths to convert") 35*4882a593Smuzhiyun 36*4882a593Smuzhiyunargs = parser.parse_args() 37*4882a593Smuzhiyun 38*4882a593Smuzhiyun# List of strings to treat as overrides 39*4882a593Smuzhiyunvars = args.override 40*4882a593Smuzhiyunvars += ["append", "prepend", "remove"] 41*4882a593Smuzhiyunvars += ["qemuarm", "qemux86", "qemumips", "qemuppc", "qemuriscv", "qemuall"] 42*4882a593Smuzhiyunvars += ["genericx86", "edgerouter", "beaglebone-yocto"] 43*4882a593Smuzhiyunvars += ["armeb", "arm", "armv5", "armv6", "armv4", "powerpc64", "aarch64", "riscv32", "riscv64", "x86", "mips64", "powerpc"] 44*4882a593Smuzhiyunvars += ["mipsarch", "x86-x32", "mips16e", "microblaze", "e5500-64b", "mipsisa32", "mipsisa64"] 45*4882a593Smuzhiyunvars += ["class-native", "class-target", "class-cross-canadian", "class-cross", "class-devupstream"] 46*4882a593Smuzhiyunvars += ["tune-", "pn-", "forcevariable"] 47*4882a593Smuzhiyunvars += ["libc-musl", "libc-glibc", "libc-newlib","libc-baremetal"] 48*4882a593Smuzhiyunvars += ["task-configure", "task-compile", "task-install", "task-clean", "task-image-qa", "task-rm_work", "task-image-complete", "task-populate-sdk"] 49*4882a593Smuzhiyunvars += ["toolchain-clang", "mydistro", "nios2", "sdkmingw32", "overrideone", "overridetwo"] 50*4882a593Smuzhiyunvars += ["linux-gnux32", "linux-muslx32", "linux-gnun32", "mingw32", "poky", "darwin", "linuxstdbase"] 51*4882a593Smuzhiyunvars += ["linux-gnueabi", "eabi"] 52*4882a593Smuzhiyunvars += ["virtclass-multilib", "virtclass-mcextend"] 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun# List of strings to treat as overrides but only with whitespace following or another override (more restricted matching). 55*4882a593Smuzhiyun# Handles issues with arc matching arch. 56*4882a593Smuzhiyunshortvars = ["arc", "mips", "mipsel", "sh4"] + args.short_override 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun# Variables which take packagenames as an override 59*4882a593Smuzhiyunpackagevars = ["FILES", "RDEPENDS", "RRECOMMENDS", "SUMMARY", "DESCRIPTION", "RSUGGESTS", "RPROVIDES", "RCONFLICTS", "PKG", "ALLOW_EMPTY", 60*4882a593Smuzhiyun "pkg_postrm", "pkg_postinst_ontarget", "pkg_postinst", "INITSCRIPT_NAME", "INITSCRIPT_PARAMS", "DEBIAN_NOAUTONAME", "ALTERNATIVE", 61*4882a593Smuzhiyun "PKGE", "PKGV", "PKGR", "USERADD_PARAM", "GROUPADD_PARAM", "CONFFILES", "SYSTEMD_SERVICE", "LICENSE", "SECTION", "pkg_preinst", 62*4882a593Smuzhiyun "pkg_prerm", "RREPLACES", "GROUPMEMS_PARAM", "SYSTEMD_AUTO_ENABLE", "SKIP_FILEDEPS", "PRIVATE_LIBS", "PACKAGE_ADD_METADATA", 63*4882a593Smuzhiyun "INSANE_SKIP", "DEBIANNAME", "SYSTEMD_SERVICE_ESCAPED"] + args.package_vars 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun# Expressions to skip if encountered, these are not overrides 66*4882a593Smuzhiyunskips = args.skip 67*4882a593Smuzhiyunskips += ["parser_append", "recipe_to_append", "extra_append", "to_remove", "show_appends", "applied_appends", "file_appends", "handle_remove"] 68*4882a593Smuzhiyunskips += ["expanded_removes", "color_remove", "test_remove", "empty_remove", "toaster_prepend", "num_removed", "licfiles_append", "_write_append"] 69*4882a593Smuzhiyunskips += ["no_report_remove", "test_prepend", "test_append", "multiple_append", "test_remove", "shallow_remove", "do_remove_layer", "first_append"] 70*4882a593Smuzhiyunskips += ["parser_remove", "to_append", "no_remove", "bblayers_add_remove", "bblayers_remove", "apply_append", "is_x86", "base_dep_prepend"] 71*4882a593Smuzhiyunskips += ["autotools_dep_prepend", "go_map_arm", "alt_remove_links", "systemd_append_file", "file_append", "process_file_darwin"] 72*4882a593Smuzhiyunskips += ["run_loaddata_poky", "determine_if_poky_env", "do_populate_poky_src", "libc_cv_include_x86_isa_level", "test_rpm_remove", "do_install_armmultilib"] 73*4882a593Smuzhiyunskips += ["get_appends_for_files", "test_doubleref_remove", "test_bitbakelayers_add_remove", "elf32_x86_64", "colour_remove", "revmap_remove"] 74*4882a593Smuzhiyunskips += ["test_rpm_remove", "test_bitbakelayers_add_remove", "recipe_append_file", "log_data_removed", "recipe_append", "systemd_machine_unit_append"] 75*4882a593Smuzhiyunskips += ["recipetool_append", "changetype_remove", "try_appendfile_wc", "test_qemux86_directdisk", "test_layer_appends", "tgz_removed"] 76*4882a593Smuzhiyun 77*4882a593Smuzhiyunimagevars = ["IMAGE_CMD", "EXTRA_IMAGECMD", "IMAGE_TYPEDEP", "CONVERSION_CMD", "COMPRESS_CMD"] + args.image_vars 78*4882a593Smuzhiyunpackagevars += imagevars 79*4882a593Smuzhiyun 80*4882a593Smuzhiyunskip_ext = [".html", ".patch", ".m4", ".diff"] + args.skip_ext 81*4882a593Smuzhiyun 82*4882a593Smuzhiyunvars_re = {} 83*4882a593Smuzhiyunfor exp in vars: 84*4882a593Smuzhiyun vars_re[exp] = (re.compile('((^|[#\'"\s\-\+])[A-Za-z0-9_\-:${}\.]+)_' + exp), r"\1:" + exp) 85*4882a593Smuzhiyun 86*4882a593Smuzhiyunshortvars_re = {} 87*4882a593Smuzhiyunfor exp in shortvars: 88*4882a593Smuzhiyun shortvars_re[exp] = (re.compile('((^|[#\'"\s\-\+])[A-Za-z0-9_\-:${}\.]+)_' + exp + '([\(\'"\s:])'), r"\1:" + exp + r"\3") 89*4882a593Smuzhiyun 90*4882a593Smuzhiyunpackage_re = {} 91*4882a593Smuzhiyunfor exp in packagevars: 92*4882a593Smuzhiyun package_re[exp] = (re.compile('(^|[#\'"\s\-\+]+)' + exp + '_' + '([$a-z"\'\s%\[<{\\\*].)'), r"\1" + exp + r":\2") 93*4882a593Smuzhiyun 94*4882a593Smuzhiyun# Other substitutions to make 95*4882a593Smuzhiyunsubs = { 96*4882a593Smuzhiyun 'r = re.compile("([^:]+):\s*(.*)")' : 'r = re.compile("(^.+?):\s+(.*)")', 97*4882a593Smuzhiyun "val = d.getVar('%s_%s' % (var, pkg))" : "val = d.getVar('%s:%s' % (var, pkg))", 98*4882a593Smuzhiyun "f.write('%s_%s: %s\\n' % (var, pkg, encode(val)))" : "f.write('%s:%s: %s\\n' % (var, pkg, encode(val)))", 99*4882a593Smuzhiyun "d.getVar('%s_%s' % (scriptlet_name, pkg))" : "d.getVar('%s:%s' % (scriptlet_name, pkg))", 100*4882a593Smuzhiyun 'ret.append(v + "_" + p)' : 'ret.append(v + ":" + p)', 101*4882a593Smuzhiyun} 102*4882a593Smuzhiyun 103*4882a593Smuzhiyundef processfile(fn): 104*4882a593Smuzhiyun print("processing file '%s'" % fn) 105*4882a593Smuzhiyun try: 106*4882a593Smuzhiyun fh, abs_path = tempfile.mkstemp() 107*4882a593Smuzhiyun with os.fdopen(fh, 'w') as new_file: 108*4882a593Smuzhiyun with open(fn, "r") as old_file: 109*4882a593Smuzhiyun for line in old_file: 110*4882a593Smuzhiyun skip = False 111*4882a593Smuzhiyun for s in skips: 112*4882a593Smuzhiyun if s in line: 113*4882a593Smuzhiyun skip = True 114*4882a593Smuzhiyun if "ptest_append" in line or "ptest_remove" in line or "ptest_prepend" in line: 115*4882a593Smuzhiyun skip = False 116*4882a593Smuzhiyun for sub in subs: 117*4882a593Smuzhiyun if sub in line: 118*4882a593Smuzhiyun line = line.replace(sub, subs[sub]) 119*4882a593Smuzhiyun skip = True 120*4882a593Smuzhiyun if not skip: 121*4882a593Smuzhiyun for pvar in packagevars: 122*4882a593Smuzhiyun line = package_re[pvar][0].sub(package_re[pvar][1], line) 123*4882a593Smuzhiyun for var in vars: 124*4882a593Smuzhiyun line = vars_re[var][0].sub(vars_re[var][1], line) 125*4882a593Smuzhiyun for shortvar in shortvars: 126*4882a593Smuzhiyun line = shortvars_re[shortvar][0].sub(shortvars_re[shortvar][1], line) 127*4882a593Smuzhiyun if "pkg_postinst:ontarget" in line: 128*4882a593Smuzhiyun line = line.replace("pkg_postinst:ontarget", "pkg_postinst_ontarget") 129*4882a593Smuzhiyun new_file.write(line) 130*4882a593Smuzhiyun shutil.copymode(fn, abs_path) 131*4882a593Smuzhiyun os.remove(fn) 132*4882a593Smuzhiyun shutil.move(abs_path, fn) 133*4882a593Smuzhiyun except UnicodeDecodeError: 134*4882a593Smuzhiyun pass 135*4882a593Smuzhiyun 136*4882a593Smuzhiyunourname = os.path.basename(sys.argv[0]) 137*4882a593Smuzhiyunourversion = "0.9.3" 138*4882a593Smuzhiyun 139*4882a593Smuzhiyunfor p in args.path: 140*4882a593Smuzhiyun if os.path.isfile(p): 141*4882a593Smuzhiyun processfile(p) 142*4882a593Smuzhiyun else: 143*4882a593Smuzhiyun print("processing directory '%s'" % p) 144*4882a593Smuzhiyun for root, dirs, files in os.walk(p): 145*4882a593Smuzhiyun for name in files: 146*4882a593Smuzhiyun if name == ourname: 147*4882a593Smuzhiyun continue 148*4882a593Smuzhiyun fn = os.path.join(root, name) 149*4882a593Smuzhiyun if os.path.islink(fn): 150*4882a593Smuzhiyun continue 151*4882a593Smuzhiyun if "/.git/" in fn or any(fn.endswith(ext) for ext in skip_ext): 152*4882a593Smuzhiyun continue 153*4882a593Smuzhiyun processfile(fn) 154*4882a593Smuzhiyun 155*4882a593Smuzhiyunprint("All files processed with version %s" % ourversion) 156