2 # ex: set syntax=python:
9 from buildbot import locks
11 # This is a sample buildmaster config file. It must be installed as
12 # 'master.cfg' in your buildmaster's base directory.
14 ini = ConfigParser.ConfigParser()
15 ini.read("./config.ini")
17 # This is the dictionary that the buildmaster pays attention to. We also use
18 # a shorter alias to save typing.
19 c = BuildmasterConfig = {}
23 # The 'slaves' list defines the set of recognized buildslaves. Each element is
24 # a BuildSlave object, specifying a unique slave name and password. The same
25 # slave name and password must be configured on the slave.
26 from buildbot.buildslave import BuildSlave
30 for section in ini.sections():
31 if section.startswith("slave "):
32 if ini.has_option(section, "name") and ini.has_option(section, "password"):
33 name = ini.get(section, "name")
34 password = ini.get(section, "password")
36 if ini.has_option(section, "builds"):
37 max_builds = ini.getint(section, "builds")
38 c['slaves'].append(BuildSlave(name, password, max_builds = max_builds))
40 # 'slavePortnum' defines the TCP port to listen on for connections from slaves.
41 # This must match the value configured into the buildslaves (with their
43 c['slavePortnum'] = 9989
46 c['mergeRequests'] = True
50 home_dir = os.path.abspath(ini.get("general", "homedir"))
52 repo_url = ini.get("repo", "url")
54 rsync_url = ini.get("rsync", "url")
55 rsync_key = ini.get("rsync", "password")
60 findtargets = subprocess.Popen([home_dir+'/dumpinfo.pl', 'targets'],
61 stdout = subprocess.PIPE, cwd = home_dir+'/source.git')
64 line = findtargets.stdout.readline()
67 ta = line.strip().split(' ')
71 # the 'change_source' setting tells the buildmaster how it should find out
72 # about source code changes. Here we point to the buildbot clone of pyflakes.
74 from buildbot.changes.gitpoller import GitPoller
75 c['change_source'] = []
76 c['change_source'].append(GitPoller(
78 workdir=home_dir+'/source.git', branch='master',
83 # Configure the Schedulers, which decide how to react to incoming changes. In this
84 # case, just kick off a 'basebuild' build
86 from buildbot.schedulers.basic import SingleBranchScheduler
87 from buildbot.schedulers.forcesched import ForceScheduler
88 from buildbot.changes import filter
90 c['schedulers'].append(SingleBranchScheduler(
92 change_filter=filter.ChangeFilter(branch='master'),
94 builderNames=targets))
96 c['schedulers'].append(ForceScheduler(
98 builderNames=targets))
102 # The 'builders' list defines the Builders, which tell Buildbot how to perform a build:
103 # what steps, and which slaves can execute them. Note that any particular build will
104 # only take place on one slave.
106 from buildbot.process.factory import BuildFactory
107 from buildbot.steps.source import Git
108 from buildbot.steps.shell import ShellCommand
109 from buildbot.steps.shell import SetProperty
110 from buildbot.steps.transfer import FileDownload
111 from buildbot.process.properties import WithProperties
115 "^tools/": "tools/clean",
116 "^toolchain/": "toolchain/clean",
117 "^target/linux/": "target/linux/clean",
118 "^(config|include)/": "dirclean"
121 def IsAffected(pattern):
122 def CheckAffected(change):
123 for request in change.build.requests:
124 for source in request.sources:
125 for change in source.changes:
126 for file in change.files:
127 if re.match(pattern, file):
132 def isPathBuiltin(path):
135 conf = open(".config", "r")
138 line = conf.readline()
141 m = re.match("^(CONFIG_PACKAGE_.+?)=y", line)
143 incl[m.group(1)] = True
147 deps = open("tmp/.packagedeps", "r")
150 line = deps.readline()
153 m = re.match("^package-\$\((CONFIG_PACKAGE_.+?)\) \+= (\S+)", line)
154 if m and incl.get(m.group(1)) == True:
155 pkgs["package/%s" % m.group(2)] = True
160 if pkgs.get(path) == True:
162 path = os.path.dirname(path)
166 def isChangeBuiltin(change):
168 # for request in change.build.requests:
169 # for source in request.sources:
170 # for change in source.changes:
171 # for file in change.files:
172 # if isPathBuiltin(file):
179 dlLock = locks.SlaveLock("slave_dl")
181 checkBuiltin = re.sub('[\t\n ]+', ' ', """
183 local symbol op path file;
184 for file in $CHANGED_FILES; do
190 while read symbol op path; do
191 case "$symbol" in package-*)
192 symbol="${symbol##*(}";
193 symbol="${symbol%)}";
194 for file in $CHANGED_FILES; do
195 case "$file" in "package/$path/"*)
196 grep -qsx "$symbol=y" .config && return 0
200 done < tmp/.packagedeps;
206 class IfBuiltinShellCommand(ShellCommand):
207 def _quote(self, str):
208 if re.search("[^a-zA-Z0-9/_.-]", str):
209 return "'%s'" %(re.sub("'", "'\"'\"'", str))
212 def setCommand(self, command):
213 if not isinstance(command, (str, unicode)):
214 command = ' '.join(map(self._quote, command))
217 '%s; if checkBuiltin; then %s; else exit 0; fi' %(checkBuiltin, command)
220 def setupEnvironment(self, cmd):
221 slaveEnv = self.slaveEnvironment
225 for request in self.build.requests:
226 for source in request.sources:
227 for change in source.changes:
228 for file in change.files:
229 changedFiles[file] = True
230 fullSlaveEnv = slaveEnv.copy()
231 fullSlaveEnv['CHANGED_FILES'] = ' '.join(changedFiles.keys())
232 cmd.args['env'] = fullSlaveEnv
236 for slave in c['slaves']:
237 slaveNames.append(slave.slavename)
239 for target in targets:
240 ts = target.split('/')
242 factory = BuildFactory()
244 # find number of cores
245 factory.addStep(SetProperty(
247 description = "Finding number of CPUs",
248 command = ["nproc"]))
250 # check out the source
251 factory.addStep(Git(repourl=repo_url, mode='update'))
253 factory.addStep(ShellCommand(
255 description = "Remove tmp folder",
256 command=["rm", "-rf", "tmp/"]))
259 # factory.addStep(ShellCommand(
260 # name = "feedsconf",
261 # description = "Copy the feeds.conf",
262 # command='''cp ~/feeds.conf ./feeds.conf''' ))
265 factory.addStep(ShellCommand(
266 name = "updatefeeds",
267 description = "Updating feeds",
268 command=["./scripts/feeds", "update"]))
271 factory.addStep(ShellCommand(
272 name = "installfeeds",
273 description = "Installing feeds",
274 command=["./scripts/feeds", "install", "-a"]))
277 factory.addStep(ShellCommand(
279 description = "Seeding .config",
280 command='''cat <<EOT > .config
282 CONFIG_TARGET_%s_%s=y
283 CONFIG_ALL_NONSHARED=y
286 # CONFIG_IB_STANDALONE is not set
289 CONFIG_SIGNED_PACKAGES=y
290 # CONFIG_PER_FEED_REPO_ADD_COMMENTED is not set
291 CONFIG_KERNEL_KALLSYMS=y
292 CONFIG_COLLECT_KERNEL_DEBUG=y
293 EOT''' %(ts[0], ts[0], ts[1]) ))
295 factory.addStep(ShellCommand(
297 description = "Removing output directory",
298 command = ["rm", "-rf", "bin/"]
301 factory.addStep(ShellCommand(
303 description = "Populating .config",
304 command = ["make", "defconfig"]
308 factory.addStep(ShellCommand(
310 description = "Checking architecture",
311 command = ["grep", "-sq", "CONFIG_TARGET_%s=y" %(ts[0]), ".config"],
318 factory.addStep(ShellCommand(
320 description = "Checking libc flavor",
321 command = ["grep", "-sq", 'CONFIG_LIBC="musl"', ".config"],
329 factory.addStep(FileDownload(mastersrc=home_dir+'/key-build', slavedest="key-build", mode=0600))
330 factory.addStep(FileDownload(mastersrc=home_dir+'/key-build.pub', slavedest="key-build.pub", mode=0600))
333 factory.addStep(ShellCommand(
335 description = "Preparing dl/",
336 command = "mkdir -p $HOME/dl && ln -sf $HOME/dl ./dl",
342 factory.addStep(ShellCommand(
344 description = "Populating dl/",
345 command = ["make", WithProperties("-j%(nproc:~4)s"), "download", "V=s"],
347 locks = [dlLock.access('exclusive')]
350 factory.addStep(ShellCommand(
352 description = "Cleaning base-files",
353 command=["make", "package/base-files/clean", "V=s"]
356 # optional clean steps
357 for pattern, maketarget in MakeTargetMap.items():
358 factory.addStep(ShellCommand(
360 description = maketarget,
361 command=["make", maketarget, "V=s"], doStepIf=IsAffected(pattern)
365 factory.addStep(ShellCommand(
367 description = "Building tools",
368 command = ["make", WithProperties("-j%(nproc:~4)s"), "tools/install", "V=s"],
372 factory.addStep(ShellCommand(
374 description = "Building toolchain",
375 command=["make", WithProperties("-j%(nproc:~4)s"), "toolchain/install", "V=s"],
379 factory.addStep(ShellCommand(
381 description = "Building kmods",
382 command=["make", WithProperties("-j%(nproc:~4)s"), "target/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
383 #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])},
387 factory.addStep(ShellCommand(
389 description = "Building packages",
390 command=["make", WithProperties("-j%(nproc:~4)s"), "package/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
391 #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])},
395 # factory.addStep(IfBuiltinShellCommand(
396 factory.addStep(ShellCommand(
398 description = "Installing packages",
399 command=["make", WithProperties("-j%(nproc:~4)s"), "package/install", "V=s"],
400 doStepIf = isChangeBuiltin,
404 factory.addStep(ShellCommand(
406 description = "Indexing packages",
407 command=["make", WithProperties("-j%(nproc:~4)s"), "package/index", "V=s"],
411 #factory.addStep(IfBuiltinShellCommand(
412 factory.addStep(ShellCommand(
414 description = "Building images",
415 command=["make", "-j1", "target/install", "V=s"],
416 doStepIf = isChangeBuiltin,
421 factory.addStep(ShellCommand(
422 name = "uploadprepare",
423 description = "Preparing target directory",
424 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)],
425 env={'RSYNC_PASSWORD': rsync_key},
426 haltOnFailure = True,
430 factory.addStep(ShellCommand(
431 name = "targetupload",
432 description = "Uploading target files",
433 command=["rsync", "--delete", "--delay-updates", "-avz", "bin/targets/%s/%s/" %(ts[0], ts[1]), "%s/targets/%s/%s/" %(rsync_url, ts[0], ts[1])],
434 env={'RSYNC_PASSWORD': rsync_key},
435 haltOnFailure = True,
440 factory.addStep(ShellCommand(
441 name = "packageupload",
442 description = "Uploading package files",
443 command=["rsync", "--delete", "--delay-updates", "-avz", "bin/packages/", "%s/packages/" %(rsync_url)],
444 env={'RSYNC_PASSWORD': rsync_key},
445 haltOnFailure = False,
451 factory.addStep(ShellCommand(
453 description = "Uploading logs",
454 command=["rsync", "--delete", "--delay-updates", "-avz", "logs/", "%s/logs/%s/%s/" %(rsync_url, ts[0], ts[1])],
455 env={'RSYNC_PASSWORD': rsync_key},
456 haltOnFailure = False,
461 from buildbot.config import BuilderConfig
463 c['builders'].append(BuilderConfig(name=target, slavenames=slaveNames, factory=factory))
466 ####### STATUS TARGETS
468 # 'status' is a list of Status Targets. The results of each build will be
469 # pushed to these targets. buildbot/status/*.py has a variety to choose from,
470 # including web pages, email senders, and IRC bots.
474 from buildbot.status import html
475 from buildbot.status.web import authz, auth
477 if ini.has_option("status", "bind"):
478 if ini.has_option("status", "user") and ini.has_option("status", "password"):
479 authz_cfg=authz.Authz(
480 # change any of these to True to enable; see the manual for more
482 auth=auth.BasicAuth([(ini.get("status", "user"), ini.get("status", "password"))]),
483 gracefulShutdown = False,
484 forceBuild = 'auth', # use this to test your slave once it is set up
485 forceAllBuilds = 'auth',
488 stopAllBuilds = 'auth',
489 cancelPendingBuild = 'auth',
491 c['status'].append(html.WebStatus(http_port=ini.get("status", "bind"), authz=authz_cfg))
493 c['status'].append(html.WebStatus(http_port=ini.get("status", "bind")))
495 ####### PROJECT IDENTITY
497 # the 'title' string will appear at the top of this buildbot
498 # installation's html.WebStatus home page (linked to the
499 # 'titleURL') and is embedded in the title of the waterfall HTML page.
501 c['title'] = ini.get("general", "title")
502 c['titleURL'] = ini.get("general", "title_url")
504 # the 'buildbotURL' string should point to the location where the buildbot's
505 # internal web server (usually the html.WebStatus page) is visible. This
506 # typically uses the port number set in the Waterfall 'status' entry, but
507 # with an externally-visible host name which the buildbot cannot figure out
510 c['buildbotURL'] = ini.get("general", "buildbot_url")
515 # This specifies what database buildbot uses to store its state. You can leave
516 # this at its default for all but the largest installations.
517 'db_url' : "sqlite:///state.sqlite",