# -*- python -*- # ex: set syntax=python: import os import re import subprocess import ConfigParser from buildbot import locks # This is a sample buildmaster config file. It must be installed as # 'master.cfg' in your buildmaster's base directory. ini = ConfigParser.ConfigParser() ini.read("./config.ini") # This is the dictionary that the buildmaster pays attention to. We also use # a shorter alias to save typing. c = BuildmasterConfig = {} ####### BUILDSLAVES # The 'slaves' list defines the set of recognized buildslaves. Each element is # a BuildSlave object, specifying a unique slave name and password. The same # slave name and password must be configured on the slave. from buildbot.buildslave import BuildSlave c['slaves'] = [] for section in ini.sections(): if section.startswith("slave "): if ini.has_option(section, "name") and ini.has_option(section, "password"): name = ini.get(section, "name") password = ini.get(section, "password") max_builds = 1 if ini.has_option(section, "builds"): max_builds = ini.getint(section, "builds") c['slaves'].append(BuildSlave(name, password, max_builds = max_builds)) # 'slavePortnum' defines the TCP port to listen on for connections from slaves. # This must match the value configured into the buildslaves (with their # --master option) c['slavePortnum'] = 9989 # coalesce builds c['mergeRequests'] = True ####### CHANGESOURCES home_dir = os.path.abspath(ini.get("general", "homedir")) repo_url = ini.get("repo", "url") rsync_url = ini.get("rsync", "url") rsync_key = ini.get("rsync", "password") # find targets targets = [ ] findtargets = subprocess.Popen([home_dir+'/dumpinfo.pl', 'targets'], stdout = subprocess.PIPE, cwd = home_dir+'/source.git') while True: line = findtargets.stdout.readline() if not line: break ta = line.strip().split(' ') targets.append(ta[0]) # the 'change_source' setting tells the buildmaster how it should find out # about source code changes. Here we point to the buildbot clone of pyflakes. from buildbot.changes.gitpoller import GitPoller c['change_source'] = [] c['change_source'].append(GitPoller( repo_url, workdir=home_dir+'/source.git', branch='master', pollinterval=300)) ####### SCHEDULERS # Configure the Schedulers, which decide how to react to incoming changes. In this # case, just kick off a 'basebuild' build from buildbot.schedulers.basic import SingleBranchScheduler from buildbot.schedulers.forcesched import ForceScheduler from buildbot.changes import filter c['schedulers'] = [] c['schedulers'].append(SingleBranchScheduler( name="all", change_filter=filter.ChangeFilter(branch='master'), treeStableTimer=60, builderNames=targets)) c['schedulers'].append(ForceScheduler( name="force", builderNames=targets)) ####### BUILDERS # The 'builders' list defines the Builders, which tell Buildbot how to perform a build: # what steps, and which slaves can execute them. Note that any particular build will # only take place on one slave. from buildbot.process.factory import BuildFactory from buildbot.steps.source import Git from buildbot.steps.shell import ShellCommand from buildbot.steps.transfer import FileDownload MakeTargetMap = { "^tools/": "tools/clean", "^toolchain/": "toolchain/clean", "^target/linux/": "target/linux/clean", "^(config|include)/": "dirclean" } def IsAffected(pattern): def CheckAffected(change): for request in change.build.requests: for source in request.sources: for change in source.changes: for file in change.files: if re.match(pattern, file): return True return False return CheckAffected def isPathBuiltin(path): incl = {} pkgs = {} conf = open(".config", "r") while True: line = conf.readline() if line == '': break m = re.match("^(CONFIG_PACKAGE_.+?)=y", line) if m: incl[m.group(1)] = True conf.close() deps = open("tmp/.packagedeps", "r") while True: line = deps.readline() if line == '': break m = re.match("^package-\$\((CONFIG_PACKAGE_.+?)\) \+= (\S+)", line) if m and incl.get(m.group(1)) == True: pkgs["package/%s" % m.group(2)] = True deps.close() while path != '': if pkgs.get(path) == True: return True path = os.path.dirname(path) return False def isChangeBuiltin(change): return True # for request in change.build.requests: # for source in request.sources: # for change in source.changes: # for file in change.files: # if isPathBuiltin(file): # return True # return False c['builders'] = [] dlLock = locks.SlaveLock("slave_dl") checkBuiltin = re.sub('[\t\n ]+', ' ', """ checkBuiltin() { local symbol op path file; for file in $CHANGED_FILES; do case "$file" in package/*/*) : ;; *) return 0 ;; esac; done; while read symbol op path; do case "$symbol" in package-*) symbol="${symbol##*(}"; symbol="${symbol%)}"; for file in $CHANGED_FILES; do case "$file" in "package/$path/"*) grep -qsx "$symbol=y" .config && return 0 ;; esac; done; esac; done < tmp/.packagedeps; return 1; } """).strip() class IfBuiltinShellCommand(ShellCommand): def _quote(self, str): if re.search("[^a-zA-Z0-9/_.-]", str): return "'%s'" %(re.sub("'", "'\"'\"'", str)) return str def setCommand(self, command): if not isinstance(command, (str, unicode)): command = ' '.join(map(self._quote, command)) self.command = [ '/bin/sh', '-c', '%s; if checkBuiltin; then %s; else exit 0; fi' %(checkBuiltin, command) ] def setupEnvironment(self, cmd): slaveEnv = self.slaveEnvironment if slaveEnv is None: slaveEnv = { } changedFiles = { } for request in self.build.requests: for source in request.sources: for change in source.changes: for file in change.files: changedFiles[file] = True fullSlaveEnv = slaveEnv.copy() fullSlaveEnv['CHANGED_FILES'] = ' '.join(changedFiles.keys()) cmd.args['env'] = fullSlaveEnv slaveNames = [ ] for slave in c['slaves']: slaveNames.append(slave.slavename) for target in targets: ts = target.split('/') factory = BuildFactory() # check out the source factory.addStep(Git(repourl=repo_url, mode='update')) factory.addStep(ShellCommand( name = "rmtmp", description = "Remove tmp folder", command=["rm", "-rf", "tmp/"])) # feed # factory.addStep(ShellCommand( # name = "feedsconf", # description = "Copy the feeds.conf", # command='''cp ~/feeds.conf ./feeds.conf''' )) # feed factory.addStep(ShellCommand( name = "updatefeeds", description = "Updating feeds", command=["./scripts/feeds", "update"])) # feed factory.addStep(ShellCommand( name = "installfeeds", description = "Installing feeds", command=["./scripts/feeds", "install", "-a"])) # configure factory.addStep(ShellCommand( name = "newconfig", description = "Seeding .config", command='''cat < .config CONFIG_TARGET_%s=y CONFIG_TARGET_%s_%s=y CONFIG_ALL_NONSHARED=y CONFIG_SDK=y CONFIG_IB=y # CONFIG_IB_STANDALONE is not set CONFIG_DEVEL=y CONFIG_CCACHE=y CONFIG_SIGNED_PACKAGES=y # CONFIG_PER_FEED_REPO_ADD_COMMENTED is not set CONFIG_KERNEL_KALLSYMS=y CONFIG_COLLECT_KERNEL_DEBUG=y EOT''' %(ts[0], ts[0], ts[1]) )) factory.addStep(ShellCommand( name = "delbin", description = "Removing output directory", command = ["rm", "-rf", "bin/"] )) factory.addStep(ShellCommand( name = "defconfig", description = "Populating .config", command = ["make", "defconfig"] )) # check arch / libc factory.addStep(ShellCommand( name = "checkarch", description = "Checking architecture", command = ["grep", "-sq", "CONFIG_TARGET_%s=y" %(ts[0]), ".config"], logEnviron = False, want_stdout = False, want_stderr = False, haltOnFailure = True )) factory.addStep(ShellCommand( name = "checklibc", description = "Checking libc flavor", command = ["grep", "-sq", 'CONFIG_LIBC="musl"', ".config"], logEnviron = False, want_stdout = False, want_stderr = False, haltOnFailure = True )) # install build key factory.addStep(FileDownload(mastersrc=home_dir+'/key-build', slavedest="key-build", mode=0600)) factory.addStep(FileDownload(mastersrc=home_dir+'/key-build.pub', slavedest="key-build.pub", mode=0600)) # prepare dl factory.addStep(ShellCommand( name = "dldir", description = "Preparing dl/", command = "mkdir -p $HOME/dl && ln -sf $HOME/dl ./dl", logEnviron = False, want_stdout = False )) # populate dl factory.addStep(ShellCommand( name = "dlrun", description = "Populating dl/", command = ["make", "-j4", "download", "V=s"], logEnviron = False, locks = [dlLock.access('exclusive')] )) factory.addStep(ShellCommand( name = "cleanbase", description = "Cleaning base-files", command=["make", "package/base-files/clean", "V=s"] )) # optional clean steps for pattern, maketarget in MakeTargetMap.items(): factory.addStep(ShellCommand( name = maketarget, description = maketarget, command=["make", maketarget, "V=s"], doStepIf=IsAffected(pattern) )) # build factory.addStep(ShellCommand( name = "tools", description = "Building tools", command = ["make", "-j4", "tools/install", "V=s"], haltOnFailure = True )) factory.addStep(ShellCommand( name = "toolchain", description = "Building toolchain", command=["make", "-j4", "toolchain/install", "V=s"], haltOnFailure = True )) factory.addStep(ShellCommand( name = "kmods", description = "Building kmods", command=["make", "-j4", "target/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"], #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])}, haltOnFailure = True )) factory.addStep(ShellCommand( name = "pkgbuild", description = "Building packages", command=["make", "-j4", "package/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"], #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])}, haltOnFailure = True )) # factory.addStep(IfBuiltinShellCommand( factory.addStep(ShellCommand( name = "pkginstall", description = "Installing packages", command=["make", "-j4", "package/install", "V=s"], doStepIf = isChangeBuiltin, haltOnFailure = True )) factory.addStep(ShellCommand( name = "pkgindex", description = "Indexing packages", command=["make", "-j4", "package/index", "V=s"], haltOnFailure = True )) #factory.addStep(IfBuiltinShellCommand( factory.addStep(ShellCommand( name = "images", description = "Building images", command=["make", "-j1", "target/install", "V=s"], doStepIf = isChangeBuiltin, haltOnFailure = True )) # upload factory.addStep(ShellCommand( name = "uploadprepare", description = "Preparing target directory", command=["rsync", "-av", "--include", "/%s/" %(ts[0]), "--include", "/%s/%s/" %(ts[0], ts[1]), "--exclude", "/*", "--exclude", "/*/*", "--exclude", "/%s/%s/*" %(ts[0], ts[1]), "bin/targets/", "%s/targets/" %(rsync_url)], env={'RSYNC_PASSWORD': rsync_key}, haltOnFailure = True, logEnviron = False )) factory.addStep(ShellCommand( name = "targetupload", description = "Uploading target files", command=["rsync", "--delete", "--delay-updates", "-avz", "bin/targets/%s/%s/" %(ts[0], ts[1]), "%s/targets/%s/%s/" %(rsync_url, ts[0], ts[1])], env={'RSYNC_PASSWORD': rsync_key}, haltOnFailure = True, logEnviron = False )) if False: factory.addStep(ShellCommand( name = "packageupload", description = "Uploading package files", command=["rsync", "--delete", "--delay-updates", "-avz", "bin/packages/", "%s/packages/" %(rsync_url)], env={'RSYNC_PASSWORD': rsync_key}, haltOnFailure = False, logEnviron = False )) # logs if False: factory.addStep(ShellCommand( name = "upload", description = "Uploading logs", command=["rsync", "--delete", "--delay-updates", "-avz", "logs/", "%s/logs/%s/%s/" %(rsync_url, ts[0], ts[1])], env={'RSYNC_PASSWORD': rsync_key}, haltOnFailure = False, alwaysRun = True, logEnviron = False )) from buildbot.config import BuilderConfig c['builders'].append(BuilderConfig(name=target, slavenames=slaveNames, factory=factory)) ####### STATUS TARGETS # 'status' is a list of Status Targets. The results of each build will be # pushed to these targets. buildbot/status/*.py has a variety to choose from, # including web pages, email senders, and IRC bots. c['status'] = [] from buildbot.status import html from buildbot.status.web import authz, auth if ini.has_option("status", "bind"): if ini.has_option("status", "user") and ini.has_option("status", "password"): authz_cfg=authz.Authz( # change any of these to True to enable; see the manual for more # options auth=auth.BasicAuth([(ini.get("status", "user"), ini.get("status", "password"))]), gracefulShutdown = False, forceBuild = 'auth', # use this to test your slave once it is set up forceAllBuilds = 'auth', pingBuilder = False, stopBuild = 'auth', stopAllBuilds = 'auth', cancelPendingBuild = 'auth', ) c['status'].append(html.WebStatus(http_port=ini.get("status", "bind"), authz=authz_cfg)) else: c['status'].append(html.WebStatus(http_port=ini.get("status", "bind"))) ####### PROJECT IDENTITY # the 'title' string will appear at the top of this buildbot # installation's html.WebStatus home page (linked to the # 'titleURL') and is embedded in the title of the waterfall HTML page. c['title'] = ini.get("general", "title") c['titleURL'] = ini.get("general", "title_url") # the 'buildbotURL' string should point to the location where the buildbot's # internal web server (usually the html.WebStatus page) is visible. This # typically uses the port number set in the Waterfall 'status' entry, but # with an externally-visible host name which the buildbot cannot figure out # without some help. c['buildbotURL'] = ini.get("general", "buildbot_url") ####### DB URL c['db'] = { # This specifies what database buildbot uses to store its state. You can leave # this at its default for all but the largest installations. 'db_url' : "sqlite:///state.sqlite", }