#!/usr/bin/env python import sys import os import base64 import re import pipes import optparse SLAVE_TYPE_FILE = "/var/run/build-tools/slave-type" SLAVE_TYPE_RESTRICTED = "restricted builds" # sf-safe build config is written to this file BUILD_CONFIG_FILE = "/var/run/build-tools/build-config" class BuildConfigMismatchException(Exception): pass def shell_unquote(s): # Primitive implementation, but we didn't really advertize # support for shell quoting, and I never saw it used if len(s) < 2: return s if s[0] == '"' and s[-1] == '"': return s[1:-1] if s[0] == "'" and s[-1] == "'": return s[1:-1] return s def get_slave_type(): slave_type = "" try: f = open(SLAVE_TYPE_FILE) slave_type = f.read().rstrip() f.close() except: pass return slave_type def validate_config(config, slave_type): """Validate various constraints on the config params and overall environment.""" full_job_name = os.environ.get("JOB_NAME") owner, job_subname = full_job_name.split("_", 1) # Deduce parameter "categories" which we can directly match # against each other if SLAVE_TYPE_RESTRICTED in slave_type: slave_type_cat = "restricted" else: slave_type_cat = "normal" if owner.endswith("-restricted"): owner_cat = "restricted" else: owner_cat = "normal" if config.get("BUILD_TYPE", "build-android") in ["build-android-private", "build-android-restricted", "build-android-toolchain-linaro-restricted", "build-android-testsuite-restricted"]: build_type_cat = "restricted" else: build_type_cat = "normal" # Now, process few most expected mismatches in adhoc way, # to provide better error messages if slave_type_cat == "restricted" and owner_cat != "restricted": raise BuildConfigMismatchException("Only jobs owned by ~linaro-android-*-restricted may run on this build slave type") if owner_cat == "restricted" and build_type_cat != "restricted": raise BuildConfigMismatchException("Jobs owned by ~linaro-android-*-restricted must use BUILD_TYPE=build-android-*-restricted") # Finally, generic mismatch detection if slave_type_cat != owner_cat or slave_type_cat != build_type_cat: raise BuildConfigMismatchException("Incompatible slave type, job owner and build type") def convert_config_to_shell(config_text, out_filename): config = {} out = open(out_filename, "w") for l in config_text.split("\n"): l = l.strip() if not l or l[0] == "#": continue if not re.match(r"[A-Za-z][A-Za-z0-9_]*=", l): print "Invalid build config syntax: " + l sys.exit(1) var, val = l.split("=", 1) val = shell_unquote(val) config[var] = val out.write("%s=%s\n" % (var, pipes.quote(val))) out.close() return config def main(config_in, is_base64): if is_base64: config_in = base64.b64decode(config_in) config = convert_config_to_shell(config_in, BUILD_CONFIG_FILE) try: validate_config(config, get_slave_type()) except BuildConfigMismatchException, e: print str(e) sys.exit(1) if __name__ == "__main__": optparser = optparse.OptionParser(usage="%prog") optparser.add_option("--base64", action="store_true", help="Process only jobs matching regex pattern") options, args = optparser.parse_args(sys.argv[1:]) if len(args) != 1: optparser.error("Wrong number of arguments") main(args[0], options.base64)