21da1a2e35eb24f4957b60ff6ade07498fe668ba
[buildbot.git] / phase1 / master.cfg
1 # -*- python -*-
2 # ex: set syntax=python:
3
4 import os
5 import re
6 import base64
7 import subprocess
8 import configparser
9
10 from dateutil.tz import tzutc
11 from datetime import datetime, timedelta
12
13 from twisted.internet import defer
14 from twisted.python import log
15
16 from buildbot import locks
17 from buildbot.data import resultspec
18 from buildbot.changes.gitpoller import GitPoller
19 from buildbot.config import BuilderConfig
20 from buildbot.plugins import reporters
21 from buildbot.plugins import schedulers
22 from buildbot.plugins import steps
23 from buildbot.plugins import util
24 from buildbot.process import properties
25 from buildbot.process import results
26 from buildbot.process.factory import BuildFactory
27 from buildbot.process.properties import Interpolate
28 from buildbot.process.properties import Property
29 from buildbot.schedulers.basic import AnyBranchScheduler
30 from buildbot.schedulers.forcesched import BaseParameter
31 from buildbot.schedulers.forcesched import ForceScheduler
32 from buildbot.schedulers.forcesched import ValidationError
33 from buildbot.steps.master import MasterShellCommand
34 from buildbot.steps.shell import SetPropertyFromCommand
35 from buildbot.steps.shell import ShellCommand
36 from buildbot.steps.source.git import Git
37 from buildbot.steps.transfer import FileDownload
38 from buildbot.steps.transfer import FileUpload
39 from buildbot.steps.transfer import StringDownload
40 from buildbot.worker import Worker
41 from buildbot.worker.local import LocalWorker
42
43
44 if not os.path.exists("twistd.pid"):
45 with open("twistd.pid", "w") as pidfile:
46 pidfile.write("{}".format(os.getpid()))
47
48 # This is a sample buildmaster config file. It must be installed as
49 # 'master.cfg' in your buildmaster's base directory.
50
51 ini = configparser.ConfigParser()
52 ini.read(os.getenv("BUILDMASTER_CONFIG", "./config.ini"))
53
54 if "general" not in ini or "phase1" not in ini:
55 raise ValueError("Fix your configuration")
56
57 inip1 = ini['phase1']
58
59 # Globals
60 work_dir = os.path.abspath(ini['general'].get("workdir", "."))
61 scripts_dir = os.path.abspath("../scripts")
62
63 repo_url = ini['repo'].get("url")
64
65 rsync_defopts = ["-v", "-4", "--timeout=120"]
66
67 #if rsync_bin_url.find("::") > 0 or rsync_bin_url.find("rsync://") == 0:
68 # rsync_bin_defopts += ["--contimeout=20"]
69
70 branches = {}
71
72 def ini_parse_branch(section):
73 b = {}
74 name = section.get("name")
75
76 if not name:
77 raise ValueError("missing 'name' in " + repr(section))
78 if name in branches:
79 raise ValueError("duplicate branch name in " + repr(section))
80
81 b["name"] = name
82 b["bin_url"] = section.get("binary_url")
83 b["bin_key"] = section.get("binary_password")
84
85 b["src_url"] = section.get("source_url")
86 b["src_key"] = section.get("source_password")
87
88 b["gpg_key"] = section.get("gpg_key")
89
90 b["usign_key"] = section.get("usign_key")
91 usign_comment = "untrusted comment: " + name.replace("-", " ").title() + " key"
92 b["usign_comment"] = section.get("usign_comment", usign_comment)
93
94 b["config_seed"] = section.get("config_seed")
95
96 b["kmod_archive"] = section.getboolean("kmod_archive", False)
97
98 branches[name] = b
99 log.msg("Configured branch: {}".format(name))
100
101 # PB port can be either a numeric port or a connection string
102 pb_port = inip1.get("port") or 9989
103
104 # This is the dictionary that the buildmaster pays attention to. We also use
105 # a shorter alias to save typing.
106 c = BuildmasterConfig = {}
107
108 ####### PROJECT IDENTITY
109
110 # the 'title' string will appear at the top of this buildbot
111 # installation's html.WebStatus home page (linked to the
112 # 'titleURL') and is embedded in the title of the waterfall HTML page.
113
114 c['title'] = ini['general'].get("title")
115 c['titleURL'] = ini['general'].get("title_url")
116
117 # the 'buildbotURL' string should point to the location where the buildbot's
118 # internal web server (usually the html.WebStatus page) is visible. This
119 # typically uses the port number set in the Waterfall 'status' entry, but
120 # with an externally-visible host name which the buildbot cannot figure out
121 # without some help.
122
123 c['buildbotURL'] = inip1.get("buildbot_url")
124
125 ####### BUILDWORKERS
126
127 # The 'workers' list defines the set of recognized buildworkers. Each element is
128 # a Worker object, specifying a unique worker name and password. The same
129 # worker name and password must be configured on the worker.
130
131 c['workers'] = []
132 NetLocks = dict()
133
134 def ini_parse_workers(section):
135 name = section.get("name")
136 password = section.get("password")
137 phase = section.getint("phase")
138 tagonly = section.getboolean("tag_only")
139
140 if not name or not password or not phase == 1:
141 log.msg("invalid worker configuration ignored: {}".format(repr(section)))
142 return
143
144 sl_props = { 'dl_lock':None, 'ul_lock':None, 'tag_only':tagonly }
145 if "dl_lock" in section:
146 lockname = section.get("dl_lock")
147 sl_props['dl_lock'] = lockname
148 if lockname not in NetLocks:
149 NetLocks[lockname] = locks.MasterLock(lockname)
150 if "ul_lock" in section:
151 lockname = section.get("ul_lock")
152 sl_props['ul_lock'] = lockname
153 if lockname not in NetLocks:
154 NetLocks[lockname] = locks.MasterLock(lockname)
155
156 log.msg("Configured worker: {}".format(name))
157 c['workers'].append(Worker(name, password, max_builds = 1, properties = sl_props))
158
159
160 for section in ini.sections():
161 if section.startswith("branch "):
162 ini_parse_branch(ini[section])
163
164 if section.startswith("worker "):
165 ini_parse_workers(ini[section])
166
167 branchNames = [branches[b]["name"] for b in branches]
168
169 c['protocols'] = {'pb': {'port': pb_port}}
170
171 # coalesce builds
172 c['collapseRequests'] = True
173
174 # Reduce amount of backlog data
175 c['configurators'] = [util.JanitorConfigurator(
176 logHorizon=timedelta(days=3),
177 hour=6,
178 )]
179
180 @defer.inlineCallbacks
181 def getNewestCompleteTime(bldr):
182 """Returns the complete_at of the latest completed and not SKIPPED
183 build request for this builder, or None if there are no such build
184 requests. We need to filter out SKIPPED requests because we're
185 using collapseRequests=True which is unfortunately marking all
186 previous requests as complete when new buildset is created.
187
188 @returns: datetime instance or None, via Deferred
189 """
190
191 bldrid = yield bldr.getBuilderId()
192 completed = yield bldr.master.data.get(
193 ('builders', bldrid, 'buildrequests'),
194 [
195 resultspec.Filter('complete', 'eq', [True]),
196 resultspec.Filter('results', 'ne', [results.SKIPPED]),
197 ],
198 order=['-complete_at'], limit=1)
199 if not completed:
200 return
201
202 complete_at = completed[0]['complete_at']
203
204 last_build = yield bldr.master.data.get(
205 ('builds', ),
206 [
207 resultspec.Filter('builderid', 'eq', [bldrid]),
208 ],
209 order=['-started_at'], limit=1)
210
211 if last_build and last_build[0]:
212 last_complete_at = last_build[0]['complete_at']
213 if last_complete_at and (last_complete_at > complete_at):
214 return last_complete_at
215
216 return complete_at
217
218 @defer.inlineCallbacks
219 def prioritizeBuilders(master, builders):
220 """Returns sorted list of builders by their last timestamp of completed and
221 not skipped build, ordered first by branch name.
222
223 @returns: list of sorted builders
224 """
225
226 bldrNamePrio = { "__Janitor": 0, "00_force_build": 0 }
227 i = 1
228 for bname in branchNames:
229 bldrNamePrio[bname] = i
230 i += 1
231
232 def is_building(bldr):
233 return bool(bldr.building) or bool(bldr.old_building)
234
235 def bldr_info(bldr):
236 d = defer.maybeDeferred(getNewestCompleteTime, bldr)
237 d.addCallback(lambda complete_at: (complete_at, bldr))
238 return d
239
240 def bldr_sort(item):
241 (complete_at, bldr) = item
242
243 pos = 99
244 for (name, prio) in bldrNamePrio.items():
245 if bldr.name.startswith(name):
246 pos = prio
247 break
248
249 if not complete_at:
250 date = datetime.min
251 complete_at = date.replace(tzinfo=tzutc())
252
253 if is_building(bldr):
254 date = datetime.max
255 complete_at = date.replace(tzinfo=tzutc())
256
257 return (pos, complete_at, bldr.name)
258
259 results = yield defer.gatherResults([bldr_info(bldr) for bldr in builders])
260 results.sort(key=bldr_sort)
261
262 #for r in results:
263 # log.msg("prioritizeBuilders: {:>20} complete_at: {}".format(r[1].name, r[0]))
264
265 return [r[1] for r in results]
266
267 c['prioritizeBuilders'] = prioritizeBuilders
268
269 ####### CHANGESOURCES
270
271 # find targets
272 targets = set()
273
274 def populateTargets():
275 log.msg("Populating targets, this will take time")
276 sourcegit = work_dir + '/source.git'
277 for branch in branchNames:
278 if os.path.isdir(sourcegit):
279 subprocess.call(["rm", "-rf", sourcegit])
280
281 subprocess.call(["git", "clone", "-q", "--depth=1", "--branch="+branch, repo_url, sourcegit])
282
283 os.makedirs(sourcegit + '/tmp', exist_ok=True)
284 findtargets = subprocess.Popen(['./scripts/dump-target-info.pl', 'targets'],
285 stdout = subprocess.PIPE, stderr = subprocess.DEVNULL, cwd = sourcegit)
286
287 while True:
288 line = findtargets.stdout.readline()
289 if not line:
290 break
291 ta = line.decode().strip().split(' ')
292 targets.add(ta[0])
293
294 subprocess.call(["rm", "-rf", sourcegit])
295
296 populateTargets()
297
298 # the 'change_source' setting tells the buildmaster how it should find out
299 # about source code changes. Here we point to the buildbot clone of pyflakes.
300
301 c['change_source'] = []
302 c['change_source'].append(GitPoller(
303 repo_url,
304 workdir=work_dir+'/work.git', branches=branchNames,
305 pollAtLaunch=True, pollinterval=300))
306
307 ####### SCHEDULERS
308
309 # Configure the Schedulers, which decide how to react to incoming changes. In this
310 # case, just kick off a 'basebuild' build
311
312 class TagChoiceParameter(BaseParameter):
313 spec_attributes = ["strict", "choices"]
314 type = "list"
315 strict = True
316
317 def __init__(self, name, label=None, **kw):
318 super().__init__(name, label, **kw)
319 self._choice_list = []
320
321 def getRevTags(self, findtag=None):
322 taglist = []
323 branchvers = []
324
325 for b in branchNames:
326 basever = re.search(r'-([0-9]+\.[0-9]+)$', b)
327 if basever:
328 branchvers.append(basever[1])
329
330 alltags = subprocess.Popen(
331 ['git', 'ls-remote', '--tags', repo_url],
332 stdout = subprocess.PIPE)
333
334 while True:
335 line = alltags.stdout.readline()
336
337 if not line:
338 break
339
340 (rev, tag) = line.split()
341
342 tagver = re.search(r'\brefs/tags/(v[0-9]+\.[0-9]+\.[0-9]+(?:-rc[0-9]+)?)$', tag.decode().strip())
343
344 # only list tags matching configured branches
345 if tagver and any(tagver[1][1:].startswith(b) for b in branchvers):
346 if findtag and findtag != tagver[1]:
347 continue
348 taglist.append({'rev': rev.decode().strip(), 'tag': tagver[1]})
349
350 return taglist
351
352 @property
353 def choices(self):
354 taglist = [rt['tag'] for rt in self.getRevTags()]
355 taglist.sort(reverse=True, key=lambda tag: tag if re.search(r'-rc[0-9]+$', tag) else tag + '-z')
356 taglist.insert(0, '')
357
358 self._choice_list = taglist
359
360 return self._choice_list
361
362 def updateFromKwargs(self, properties, kwargs, **unused):
363 tag = self.getFromKwargs(kwargs)
364 properties[self.name] = tag
365
366 # find the commit matching the tag
367 findtag = self.getRevTags(tag)
368
369 if not findtag:
370 raise ValidationError("Couldn't find tag")
371
372 properties['force_revision'] = findtag[0]['rev']
373
374 # find the branch matching the tag
375 branch = None
376 branchver = re.search(r'v([0-9]+\.[0-9]+)', tag)
377 for b in branchNames:
378 if b.endswith(branchver[1]):
379 branch = b
380
381 if not branch:
382 raise ValidationError("Couldn't find branch")
383
384 properties['force_branch'] = branch
385
386 def parse_from_arg(self, s):
387 if self.strict and s not in self._choice_list:
388 raise ValidationError("'%s' does not belong to list of available choices '%s'" % (s, self._choice_list))
389 return s
390
391 @util.renderer
392 @defer.inlineCallbacks
393 def builderNames(props):
394 """ since we have per branch and per target builders,
395 address the relevant builder for each new buildrequest
396 based on the request's desired branch and target.
397 """
398 branch = props.getProperty("branch")
399 target = props.getProperty("target", "")
400
401 if target == "all":
402 target = ""
403
404 # if that didn't work, try sourcestamp to find a branch
405 if not branch:
406 # match builders with target branch
407 ss = props.sourcestamps[0]
408 if ss:
409 branch = ss['branch']
410 else:
411 log.msg("couldn't find builder")
412 return [] # nothing works
413
414 bname = branch + "_" + target
415 builders = []
416
417 for b in (yield props.master.data.get(('builders',))):
418 if not b['name'].startswith(bname):
419 continue
420 builders.append(b['name'])
421
422 return builders
423
424 c['schedulers'] = []
425 c['schedulers'].append(AnyBranchScheduler(
426 name = "all",
427 change_filter = util.ChangeFilter(branch=branchNames),
428 treeStableTimer = 15*60,
429 builderNames = builderNames))
430
431 c['schedulers'].append(ForceScheduler(
432 name = "force",
433 buttonName = "Force builds",
434 label = "Force build details",
435 builderNames = [ "00_force_build" ],
436
437 codebases = [
438 util.CodebaseParameter(
439 "",
440 label = "Repository",
441 branch = util.FixedParameter(name = "branch", default = ""),
442 revision = util.FixedParameter(name = "revision", default = ""),
443 repository = util.FixedParameter(name = "repository", default = ""),
444 project = util.FixedParameter(name = "project", default = "")
445 )
446 ],
447
448 reason = util.StringParameter(
449 name = "reason",
450 label = "Reason",
451 default = "Trigger build",
452 required = True,
453 size = 80
454 ),
455
456 properties = [
457 util.ChoiceStringParameter(
458 name = "target",
459 label = "Build target",
460 default = "all",
461 choices = [ "all" ] + list(targets)
462 ),
463 TagChoiceParameter(
464 name = "tag",
465 label = "Build tag",
466 default = ""
467 )
468 ]
469 ))
470
471 c['schedulers'].append(schedulers.Triggerable(name="trigger", builderNames=builderNames))
472
473 ####### BUILDERS
474
475 # The 'builders' list defines the Builders, which tell Buildbot how to perform a build:
476 # what steps, and which workers can execute them. Note that any particular build will
477 # only take place on one worker.
478
479 def IsNoMasterBuild(step):
480 return step.getProperty("branch") != "master"
481
482 def IsUsignEnabled(step):
483 branch = step.getProperty("branch")
484 return branch and branches[branch].get("usign_key")
485
486 def IsSignEnabled(step):
487 branch = step.getProperty("branch")
488 return IsUsignEnabled(step) or branch and branches[branch].get("gpg_key")
489
490 def IsKmodArchiveEnabled(step):
491 branch = step.getProperty("branch")
492 return branch and branches[branch].get("kmod_archive")
493
494 def GetBaseVersion(branch):
495 if re.match(r"^[^-]+-[0-9]+\.[0-9]+$", branch):
496 return branch.split('-')[1]
497 else:
498 return "master"
499
500 @properties.renderer
501 def GetVersionPrefix(props):
502 branch = props.getProperty("branch")
503 basever = GetBaseVersion(branch)
504 if props.hasProperty("tag") and re.match(r"^v[0-9]+\.[0-9]+\.[0-9]+(?:-rc[0-9]+)?$", props["tag"]):
505 return "%s/" % props["tag"][1:]
506 elif basever != "master":
507 return "%s-SNAPSHOT/" % basever
508 else:
509 return ""
510
511 @util.renderer
512 def GetConfigSeed(props):
513 branch = props.getProperty("branch")
514 return branch and branches[branch].get("config_seed") or ""
515
516 @util.renderer
517 def GetRsyncParams(props, srcorbin, urlorkey):
518 # srcorbin: 'bin' or 'src'; urlorkey: 'url' or 'key'
519 branch = props.getProperty("branch")
520 opt = srcorbin + "_" + urlorkey
521 return branch and branches[branch].get(opt)
522
523 @util.renderer
524 def GetUsignKey(props):
525 branch = props.getProperty("branch")
526 return branch and branches[branch].get("usign_key")
527
528 def GetNextBuild(builder, requests):
529 for r in requests:
530 if r.properties:
531 # order tagged build first
532 if r.properties.hasProperty("tag"):
533 return r
534
535 r = requests[0]
536 #log.msg("GetNextBuild: {:>20} id: {} bsid: {}".format(builder.name, r.id, r.bsid))
537 return r
538
539 def MakeEnv(overrides=None, tryccache=False):
540 env = {
541 'CCC': Interpolate("%(prop:cc_command:-gcc)s"),
542 'CCXX': Interpolate("%(prop:cxx_command:-g++)s"),
543 }
544 if tryccache:
545 env['CC'] = Interpolate("%(prop:builddir)s/ccache_cc.sh")
546 env['CXX'] = Interpolate("%(prop:builddir)s/ccache_cxx.sh")
547 env['CCACHE'] = Interpolate("%(prop:ccache_command:-)s")
548 else:
549 env['CC'] = env['CCC']
550 env['CXX'] = env['CCXX']
551 env['CCACHE'] = ''
552 if overrides is not None:
553 env.update(overrides)
554 return env
555
556 @properties.renderer
557 def NetLockDl(props, extralock=None):
558 lock = None
559 if props.hasProperty("dl_lock"):
560 lock = NetLocks[props["dl_lock"]]
561 if lock is not None:
562 return [lock.access('exclusive')]
563 else:
564 return []
565
566 @properties.renderer
567 def NetLockUl(props):
568 lock = None
569 if props.hasProperty("ul_lock"):
570 lock = NetLocks[props["ul_lock"]]
571 if lock is not None:
572 return [lock.access('exclusive')]
573 else:
574 return []
575
576 def IsTargetSelected(target):
577 def CheckTargetProperty(step):
578 selected_target = step.getProperty("target", "all")
579 if selected_target != "all" and selected_target != target:
580 return False
581 return True
582
583 return CheckTargetProperty
584
585 @util.renderer
586 def UsignSec2Pub(props):
587 branch = props.getProperty("branch")
588 try:
589 comment = branches[branch].get("usign_comment") or "untrusted comment: secret key"
590 seckey = branches[branch].get("usign_key")
591 seckey = base64.b64decode(seckey)
592 except:
593 return None
594
595 return "{}\n{}".format(re.sub(r"\bsecret key$", "public key", comment),
596 base64.b64encode(seckey[0:2] + seckey[32:40] + seckey[72:]))
597
598
599 def canStartBuild(builder, wfb, request):
600 """ filter out non tag requests for tag_only workers. """
601 wtagonly = wfb.worker.properties.getProperty('tag_only')
602 tag = request.properties.getProperty('tag')
603
604 if wtagonly and not tag:
605 return False
606
607 return True
608
609 c['builders'] = []
610
611 workerNames = [ ]
612
613 for worker in c['workers']:
614 workerNames.append(worker.workername)
615
616 # add a single LocalWorker to handle the forcebuild builder
617 c['workers'].append(LocalWorker("__local_force_build", max_builds=1))
618
619 force_factory = BuildFactory()
620 force_factory.addStep(steps.Trigger(
621 name = "trigger_build",
622 schedulerNames = [ "trigger" ],
623 sourceStamps = [{ "codebase": "", "branch": Property("force_branch"), "revision": Property("force_revision"), "repository": repo_url, "project": "" }],
624 set_properties = { "reason": Property("reason"), "tag": Property("tag"), "target": Property("target") },
625 ))
626
627 c['builders'].append(BuilderConfig(
628 name = "00_force_build",
629 workername = "__local_force_build",
630 factory = force_factory))
631
632 for target in targets:
633 ts = target.split('/')
634
635 factory = BuildFactory()
636
637 # setup shared work directory if required
638 factory.addStep(ShellCommand(
639 name = "sharedwd",
640 descriptionDone = "Shared work directory set up",
641 command = 'test -L "$PWD" || (mkdir -p ../shared-workdir && rm -rf "$PWD" && ln -s shared-workdir "$PWD")',
642 workdir = ".",
643 haltOnFailure = True,
644 ))
645
646 # find number of cores
647 factory.addStep(SetPropertyFromCommand(
648 name = "nproc",
649 property = "nproc",
650 description = "Finding number of CPUs",
651 command = ["nproc"],
652 ))
653
654 # find gcc and g++ compilers
655 factory.addStep(FileDownload(
656 name = "dlfindbinpl",
657 mastersrc = scripts_dir + '/findbin.pl',
658 workerdest = "../findbin.pl",
659 mode = 0o755,
660 ))
661
662 factory.addStep(SetPropertyFromCommand(
663 name = "gcc",
664 property = "cc_command",
665 description = "Finding gcc command",
666 command = ["../findbin.pl", "gcc", "", ""],
667 haltOnFailure = True,
668 ))
669
670 factory.addStep(SetPropertyFromCommand(
671 name = "g++",
672 property = "cxx_command",
673 description = "Finding g++ command",
674 command = ["../findbin.pl", "g++", "", ""],
675 haltOnFailure = True,
676 ))
677
678 # see if ccache is available
679 factory.addStep(SetPropertyFromCommand(
680 name = "ccache",
681 property = "ccache_command",
682 description = "Testing for ccache command",
683 command = ["which", "ccache"],
684 haltOnFailure = False,
685 flunkOnFailure = False,
686 warnOnFailure = False,
687 hideStepIf = lambda r, s: r==results.FAILURE,
688 ))
689
690 # check out the source
691 # Git() runs:
692 # if repo doesn't exist: 'git clone repourl'
693 # method 'clean' runs 'git clean -d -f', method fresh runs 'git clean -f -f -d -x'. Only works with mode='full'
694 # git cat-file -e <commit>
695 # git checkout -f <commit>
696 # git checkout -B <branch>
697 # git rev-parse HEAD
698 factory.addStep(Git(
699 name = "git",
700 repourl = repo_url,
701 mode = 'full',
702 method = 'fresh',
703 locks = NetLockDl,
704 haltOnFailure = True,
705 ))
706
707 # update remote refs
708 factory.addStep(ShellCommand(
709 name = "fetchrefs",
710 description = "Fetching Git remote refs",
711 command = ["git", "fetch", "origin", Interpolate("+refs/heads/%(prop:branch)s:refs/remotes/origin/%(prop:branch)s")],
712 haltOnFailure = True,
713 ))
714
715 # Verify that Git HEAD points to a tag or branch
716 # Ref: https://web.archive.org/web/20190729224316/http://lists.infradead.org/pipermail/openwrt-devel/2019-June/017809.html
717 factory.addStep(ShellCommand(
718 name = "gitverify",
719 description = "Ensure that Git HEAD is pointing to a branch or tag",
720 command = 'git rev-parse --abbrev-ref HEAD | grep -vxqF HEAD || git show-ref --tags --dereference 2>/dev/null | sed -ne "/^$(git rev-parse HEAD) / { s|^.*/||; s|\\^.*||; p }" | grep -qE "^v[0-9][0-9]\\."',
721 haltOnFailure = True,
722 ))
723
724 factory.addStep(ShellCommand(
725 name = "rmtmp",
726 description = "Remove tmp folder",
727 command=["rm", "-rf", "tmp/"],
728 ))
729
730 # feed
731 factory.addStep(ShellCommand(
732 name = "rmfeedlinks",
733 description = "Remove feed symlinks",
734 command=["rm", "-rf", "package/feeds/"],
735 ))
736
737 factory.addStep(StringDownload(
738 name = "ccachecc",
739 s = '#!/bin/sh\nexec ${CCACHE} ${CCC} "$@"\n',
740 workerdest = "../ccache_cc.sh",
741 mode = 0o755,
742 ))
743
744 factory.addStep(StringDownload(
745 name = "ccachecxx",
746 s = '#!/bin/sh\nexec ${CCACHE} ${CCXX} "$@"\n',
747 workerdest = "../ccache_cxx.sh",
748 mode = 0o755,
749 ))
750
751 # feed
752 factory.addStep(ShellCommand(
753 name = "updatefeeds",
754 description = "Updating feeds",
755 command=["./scripts/feeds", "update"],
756 env = MakeEnv(tryccache=True),
757 haltOnFailure = True,
758 locks = NetLockDl,
759 ))
760
761 # feed
762 factory.addStep(ShellCommand(
763 name = "installfeeds",
764 description = "Installing feeds",
765 command=["./scripts/feeds", "install", "-a"],
766 env = MakeEnv(tryccache=True),
767 haltOnFailure = True,
768 ))
769
770 # seed config
771 factory.addStep(StringDownload(
772 name = "dlconfigseed",
773 s = Interpolate("%(kw:seed)s\n", seed=GetConfigSeed),
774 workerdest = ".config",
775 mode = 0o644,
776 ))
777
778 # configure
779 factory.addStep(ShellCommand(
780 name = "newconfig",
781 descriptionDone = ".config seeded",
782 command = Interpolate("printf 'CONFIG_TARGET_%(kw:target)s=y\\nCONFIG_TARGET_%(kw:target)s_%(kw:subtarget)s=y\\nCONFIG_SIGNED_PACKAGES=%(kw:usign:#?|y|n)s\\n' >> .config", target=ts[0], subtarget=ts[1], usign=GetUsignKey),
783 ))
784
785 factory.addStep(ShellCommand(
786 name = "delbin",
787 description = "Removing output directory",
788 command = ["rm", "-rf", "bin/"],
789 ))
790
791 factory.addStep(ShellCommand(
792 name = "defconfig",
793 description = "Populating .config",
794 command = ["make", "defconfig"],
795 env = MakeEnv(),
796 ))
797
798 # check arch - exit early if does not exist - NB: some targets do not define CONFIG_TARGET_target_subtarget
799 factory.addStep(ShellCommand(
800 name = "checkarch",
801 description = "Checking architecture",
802 descriptionDone = "Architecture validated",
803 command = 'grep -sq CONFIG_TARGET_%s=y .config && grep -sq CONFIG_TARGET_SUBTARGET=\\"%s\\" .config' %(ts[0], ts[1]),
804 logEnviron = False,
805 want_stdout = False,
806 want_stderr = False,
807 haltOnFailure = True,
808 flunkOnFailure = False, # this is not a build FAILURE
809 ))
810
811 # find libc suffix
812 factory.addStep(SetPropertyFromCommand(
813 name = "libc",
814 property = "libc",
815 description = "Finding libc suffix",
816 command = ["sed", "-ne", '/^CONFIG_LIBC=/ { s!^CONFIG_LIBC="\\(.*\\)"!\\1!; s!^musl$!!; s!.\\+!-&!p }', ".config"],
817 ))
818
819 # install build key
820 factory.addStep(StringDownload(
821 name = "dlkeybuildpub",
822 s = Interpolate("%(kw:sec2pub)s", sec2pub=UsignSec2Pub),
823 workerdest = "key-build.pub",
824 mode = 0o600,
825 doStepIf = IsUsignEnabled,
826 ))
827
828 factory.addStep(StringDownload(
829 name = "dlkeybuild",
830 s = "# fake private key",
831 workerdest = "key-build",
832 mode = 0o600,
833 doStepIf = IsUsignEnabled,
834 ))
835
836 factory.addStep(StringDownload(
837 name = "dlkeybuilducert",
838 s = "# fake certificate",
839 workerdest = "key-build.ucert",
840 mode = 0o600,
841 doStepIf = IsUsignEnabled,
842 ))
843
844 # prepare dl
845 factory.addStep(ShellCommand(
846 name = "dldir",
847 description = "Preparing dl/",
848 descriptionDone = "dl/ prepared",
849 command = 'mkdir -p ../dl && rm -rf "build/dl" && ln -s ../../dl "build/dl"',
850 workdir = Property("builddir"),
851 logEnviron = False,
852 want_stdout = False,
853 ))
854
855 # cleanup dl
856 factory.addStep(ShellCommand(
857 name = "dlprune",
858 description = "Pruning dl/",
859 descriptionDone = "dl/ pruned",
860 command = 'find dl/ -atime +15 -delete -print',
861 logEnviron = False,
862 ))
863
864 # prepare tar
865 factory.addStep(ShellCommand(
866 name = "dltar",
867 description = "Building and installing GNU tar",
868 descriptionDone = "GNU tar built and installed",
869 command = ["make", Interpolate("-j%(prop:nproc:-1)s"), "tools/tar/compile", "V=s"],
870 env = MakeEnv(tryccache=True),
871 haltOnFailure = True,
872 ))
873
874 # populate dl
875 factory.addStep(ShellCommand(
876 name = "dlrun",
877 description = "Populating dl/",
878 descriptionDone = "dl/ populated",
879 command = ["make", Interpolate("-j%(prop:nproc:-1)s"), "download", "V=s"],
880 env = MakeEnv(),
881 logEnviron = False,
882 locks = NetLockDl,
883 ))
884
885 factory.addStep(ShellCommand(
886 name = "cleanbase",
887 description = "Cleaning base-files",
888 command=["make", "package/base-files/clean", "V=s"],
889 ))
890
891 # build
892 factory.addStep(ShellCommand(
893 name = "tools",
894 description = "Building and installing tools",
895 descriptionDone = "Tools built and installed",
896 command = ["make", Interpolate("-j%(prop:nproc:-1)s"), "tools/install", "V=s"],
897 env = MakeEnv(tryccache=True),
898 haltOnFailure = True,
899 ))
900
901 factory.addStep(ShellCommand(
902 name = "toolchain",
903 description = "Building and installing toolchain",
904 descriptionDone = "Toolchain built and installed",
905 command=["make", Interpolate("-j%(prop:nproc:-1)s"), "toolchain/install", "V=s"],
906 env = MakeEnv(),
907 haltOnFailure = True,
908 ))
909
910 factory.addStep(ShellCommand(
911 name = "kmods",
912 description = "Building kmods",
913 descriptionDone = "Kmods built",
914 command=["make", Interpolate("-j%(prop:nproc:-1)s"), "target/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
915 env = MakeEnv(),
916 haltOnFailure = True,
917 ))
918
919 # find kernel version
920 factory.addStep(SetPropertyFromCommand(
921 name = "kernelversion",
922 property = "kernelversion",
923 description = "Finding the effective Kernel version",
924 command = "make --no-print-directory -C target/linux/ val.LINUX_VERSION val.LINUX_RELEASE val.LINUX_VERMAGIC | xargs printf '%s-%s-%s\\n'",
925 env = { 'TOPDIR': Interpolate("%(prop:builddir)s/build") },
926 ))
927
928 factory.addStep(ShellCommand(
929 name = "pkgclean",
930 description = "Cleaning up package build",
931 descriptionDone = "Package build cleaned up",
932 command=["make", "package/cleanup", "V=s"],
933 ))
934
935 factory.addStep(ShellCommand(
936 name = "pkgbuild",
937 description = "Building packages",
938 descriptionDone = "Packages built",
939 command=["make", Interpolate("-j%(prop:nproc:-1)s"), "package/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
940 env = MakeEnv(),
941 haltOnFailure = True,
942 ))
943
944 factory.addStep(ShellCommand(
945 name = "pkginstall",
946 description = "Installing packages",
947 descriptionDone = "Packages installed",
948 command=["make", Interpolate("-j%(prop:nproc:-1)s"), "package/install", "V=s"],
949 env = MakeEnv(),
950 haltOnFailure = True,
951 ))
952
953 factory.addStep(ShellCommand(
954 name = "pkgindex",
955 description = "Indexing packages",
956 descriptionDone = "Packages indexed",
957 command=["make", Interpolate("-j%(prop:nproc:-1)s"), "package/index", "V=s", "CONFIG_SIGNED_PACKAGES="],
958 env = MakeEnv(),
959 haltOnFailure = True,
960 ))
961
962 factory.addStep(ShellCommand(
963 name = "images",
964 description = "Building and installing images",
965 descriptionDone = "Images built and installed",
966 command=["make", Interpolate("-j%(prop:nproc:-1)s"), "target/install", "V=s"],
967 env = MakeEnv(),
968 haltOnFailure = True,
969 ))
970
971 factory.addStep(ShellCommand(
972 name = "buildinfo",
973 description = "Generating config.buildinfo, version.buildinfo and feeds.buildinfo",
974 command = "make -j1 buildinfo V=s || true",
975 env = MakeEnv(),
976 haltOnFailure = True,
977 ))
978
979 factory.addStep(ShellCommand(
980 name = "json_overview_image_info",
981 description = "Generating profiles.json in target folder",
982 command = "make -j1 json_overview_image_info V=s || true",
983 env = MakeEnv(),
984 haltOnFailure = True,
985 ))
986
987 factory.addStep(ShellCommand(
988 name = "checksums",
989 description = "Calculating checksums",
990 descriptionDone = "Checksums calculated",
991 command=["make", "-j1", "checksum", "V=s"],
992 env = MakeEnv(),
993 haltOnFailure = True,
994 ))
995
996 factory.addStep(ShellCommand(
997 name = "kmoddir",
998 descriptionDone = "Kmod directory created",
999 command=["mkdir", "-p", Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/kmods/%(prop:kernelversion)s", target=ts[0], subtarget=ts[1])],
1000 haltOnFailure = True,
1001 doStepIf = IsKmodArchiveEnabled,
1002 ))
1003
1004 factory.addStep(ShellCommand(
1005 name = "kmodprepare",
1006 description = "Preparing kmod archive",
1007 descriptionDone = "Kmod archive prepared",
1008 command=["rsync", "--include=/kmod-*.ipk", "--exclude=*", "-va",
1009 Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/packages/", target=ts[0], subtarget=ts[1]),
1010 Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/kmods/%(prop:kernelversion)s/", target=ts[0], subtarget=ts[1])],
1011 haltOnFailure = True,
1012 doStepIf = IsKmodArchiveEnabled,
1013 ))
1014
1015 factory.addStep(ShellCommand(
1016 name = "kmodindex",
1017 description = "Indexing kmod archive",
1018 descriptionDone = "Kmod archive indexed",
1019 command=["make", Interpolate("-j%(prop:nproc:-1)s"), "package/index", "V=s", "CONFIG_SIGNED_PACKAGES=",
1020 Interpolate("PACKAGE_SUBDIRS=bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/kmods/%(prop:kernelversion)s/", target=ts[0], subtarget=ts[1])],
1021 env = MakeEnv(),
1022 haltOnFailure = True,
1023 doStepIf = IsKmodArchiveEnabled,
1024 ))
1025
1026 # sign
1027 factory.addStep(MasterShellCommand(
1028 name = "signprepare",
1029 descriptionDone = "Temporary signing directory prepared",
1030 command = ["mkdir", "-p", "%s/signing" %(work_dir)],
1031 haltOnFailure = True,
1032 doStepIf = IsSignEnabled,
1033
1034 ))
1035
1036 factory.addStep(ShellCommand(
1037 name = "signpack",
1038 description = "Packing files to sign",
1039 descriptionDone = "Files to sign packed",
1040 command = Interpolate("find bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/ bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/kmods/ -mindepth 1 -maxdepth 2 -type f -name sha256sums -print0 -or -name Packages -print0 | xargs -0 tar -czf sign.tar.gz", target=ts[0], subtarget=ts[1]),
1041 haltOnFailure = True,
1042 doStepIf = IsSignEnabled,
1043 ))
1044
1045 factory.addStep(FileUpload(
1046 workersrc = "sign.tar.gz",
1047 masterdest = "%s/signing/%s.%s.tar.gz" %(work_dir, ts[0], ts[1]),
1048 haltOnFailure = True,
1049 doStepIf = IsSignEnabled,
1050 ))
1051
1052 factory.addStep(MasterShellCommand(
1053 name = "signfiles",
1054 description = "Signing files",
1055 descriptionDone = "Files signed",
1056 command = ["%s/signall.sh" %(scripts_dir), "%s/signing/%s.%s.tar.gz" %(work_dir, ts[0], ts[1]), Interpolate("%(prop:branch)s")],
1057 env = { 'CONFIG_INI': os.getenv("BUILDMASTER_CONFIG", "./config.ini") },
1058 haltOnFailure = True,
1059 doStepIf = IsSignEnabled,
1060 ))
1061
1062 factory.addStep(FileDownload(
1063 name = "dlsigntargz",
1064 mastersrc = "%s/signing/%s.%s.tar.gz" %(work_dir, ts[0], ts[1]),
1065 workerdest = "sign.tar.gz",
1066 haltOnFailure = True,
1067 doStepIf = IsSignEnabled,
1068 ))
1069
1070 factory.addStep(ShellCommand(
1071 name = "signunpack",
1072 description = "Unpacking signed files",
1073 descriptionDone = "Signed files unpacked",
1074 command = ["tar", "-xzf", "sign.tar.gz"],
1075 haltOnFailure = True,
1076 doStepIf = IsSignEnabled,
1077 ))
1078
1079 # upload
1080 factory.addStep(ShellCommand(
1081 name = "dirprepare",
1082 descriptionDone = "Upload directory structure prepared",
1083 command = ["mkdir", "-p", Interpolate("tmp/upload/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s", target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix)],
1084 haltOnFailure = True,
1085 ))
1086
1087 factory.addStep(ShellCommand(
1088 name = "linkprepare",
1089 descriptionDone = "Repository symlink prepared",
1090 command = ["ln", "-s", "-f", Interpolate("../packages-%(kw:basever)s", basever=util.Transform(GetBaseVersion, Property("branch"))), Interpolate("tmp/upload/%(kw:prefix)spackages", prefix=GetVersionPrefix)],
1091 doStepIf = IsNoMasterBuild,
1092 haltOnFailure = True,
1093 ))
1094
1095 factory.addStep(ShellCommand(
1096 name = "kmoddirprepare",
1097 descriptionDone = "Kmod archive upload directory prepared",
1098 command = ["mkdir", "-p", Interpolate("tmp/upload/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s/kmods/%(prop:kernelversion)s", target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix)],
1099 haltOnFailure = True,
1100 doStepIf = IsKmodArchiveEnabled,
1101 ))
1102
1103 factory.addStep(ShellCommand(
1104 name = "dirupload",
1105 description = "Uploading directory structure",
1106 descriptionDone = "Directory structure uploaded",
1107 command = ["rsync", "-az"] + rsync_defopts + ["tmp/upload/", Interpolate("%(kw:url)s/", url=GetRsyncParams.withArgs("bin", "url"))],
1108 env={ 'RSYNC_PASSWORD': Interpolate("%(kw:key)s", key=GetRsyncParams.withArgs("bin", "key")) },
1109 haltOnFailure = True,
1110 logEnviron = False,
1111 locks = NetLockUl,
1112 doStepIf = util.Transform(bool, GetRsyncParams.withArgs("bin", "url")),
1113 ))
1114
1115 # download remote sha256sums to 'target-sha256sums'
1116 factory.addStep(ShellCommand(
1117 name = "target-sha256sums",
1118 description = "Fetching remote sha256sums for target",
1119 descriptionDone = "Remote sha256sums for target fetched",
1120 command = ["rsync", "-z"] + rsync_defopts + [Interpolate("%(kw:url)s/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s/sha256sums", url=GetRsyncParams.withArgs("bin", "url"), target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix), "target-sha256sums"],
1121 env={ 'RSYNC_PASSWORD': Interpolate("%(kw:key)s", key=GetRsyncParams.withArgs("bin", "key")) },
1122 logEnviron = False,
1123 haltOnFailure = False,
1124 flunkOnFailure = False,
1125 warnOnFailure = False,
1126 doStepIf = util.Transform(bool, GetRsyncParams.withArgs("bin", "url")),
1127 ))
1128
1129 # build list of files to upload
1130 factory.addStep(FileDownload(
1131 name = "dlsha2rsyncpl",
1132 mastersrc = scripts_dir + '/sha2rsync.pl',
1133 workerdest = "../sha2rsync.pl",
1134 mode = 0o755,
1135 ))
1136
1137 factory.addStep(ShellCommand(
1138 name = "buildlist",
1139 description = "Building list of files to upload",
1140 descriptionDone = "List of files to upload built",
1141 command = ["../sha2rsync.pl", "target-sha256sums", Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/sha256sums", target=ts[0], subtarget=ts[1]), "rsynclist"],
1142 haltOnFailure = True,
1143 ))
1144
1145 factory.addStep(FileDownload(
1146 name = "dlrsync.sh",
1147 mastersrc = scripts_dir + '/rsync.sh',
1148 workerdest = "../rsync.sh",
1149 mode = 0o755,
1150 ))
1151
1152 # upload new files and update existing ones
1153 factory.addStep(ShellCommand(
1154 name = "targetupload",
1155 description = "Uploading target files",
1156 descriptionDone = "Target files uploaded",
1157 command=["../rsync.sh", "--exclude=/kmods/", "--files-from=rsynclist", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1])] + rsync_defopts +
1158 ["-a", Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/", target=ts[0], subtarget=ts[1]),
1159 Interpolate("%(kw:url)s/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s/", url=GetRsyncParams.withArgs("bin", "url"), target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix)],
1160 env={ 'RSYNC_PASSWORD': Interpolate("%(kw:key)s", key=GetRsyncParams.withArgs("bin", "key")) },
1161 haltOnFailure = True,
1162 logEnviron = False,
1163 doStepIf = util.Transform(bool, GetRsyncParams.withArgs("bin", "url")),
1164 ))
1165
1166 # delete files which don't exist locally
1167 factory.addStep(ShellCommand(
1168 name = "targetprune",
1169 description = "Pruning target files",
1170 descriptionDone = "Target files pruned",
1171 command=["../rsync.sh", "--exclude=/kmods/", "--delete", "--existing", "--ignore-existing", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1])] + rsync_defopts +
1172 ["-a", Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/", target=ts[0], subtarget=ts[1]),
1173 Interpolate("%(kw:url)s/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s/", url=GetRsyncParams.withArgs("bin", "url"), target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix)],
1174 env={ 'RSYNC_PASSWORD': Interpolate("%(kw:key)s", key=GetRsyncParams.withArgs("bin", "key")) },
1175 haltOnFailure = True,
1176 logEnviron = False,
1177 locks = NetLockUl,
1178 doStepIf = util.Transform(bool, GetRsyncParams.withArgs("bin", "url")),
1179 ))
1180
1181 factory.addStep(ShellCommand(
1182 name = "kmodupload",
1183 description = "Uploading kmod archive",
1184 descriptionDone = "Kmod archive uploaded",
1185 command=["../rsync.sh", "--delete", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1])] + rsync_defopts +
1186 ["-a", Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/kmods/%(prop:kernelversion)s/", target=ts[0], subtarget=ts[1]),
1187 Interpolate("%(kw:url)s/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s/kmods/%(prop:kernelversion)s/", url=GetRsyncParams.withArgs("bin", "url"), target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix)],
1188 env={ 'RSYNC_PASSWORD': Interpolate("%(kw:key)s", key=GetRsyncParams.withArgs("bin", "key")) },
1189 haltOnFailure = True,
1190 logEnviron = False,
1191 locks = NetLockUl,
1192 doStepIf = util.Transform(lambda a, b: bool(a and b), IsKmodArchiveEnabled, GetRsyncParams.withArgs("bin", "url")),
1193 ))
1194
1195 factory.addStep(ShellCommand(
1196 name = "sourcelist",
1197 description = "Finding source archives to upload",
1198 descriptionDone = "Source archives to upload found",
1199 command = "find dl/ -maxdepth 1 -type f -not -size 0 -not -name '.*' -not -name '*.hash' -not -name '*.dl' -newer .config -printf '%f\\n' > sourcelist",
1200 haltOnFailure = True,
1201 ))
1202
1203 factory.addStep(ShellCommand(
1204 name = "sourceupload",
1205 description = "Uploading source archives",
1206 descriptionDone = "Source archives uploaded",
1207 command=["../rsync.sh", "--files-from=sourcelist", "--size-only", "--delay-updates"] + rsync_defopts +
1208 [Interpolate("--partial-dir=.~tmp~%(kw:target)s~%(kw:subtarget)s~%(prop:workername)s", target=ts[0], subtarget=ts[1]), "-a", "dl/", Interpolate("%(kw:url)s/", url=GetRsyncParams.withArgs("src", "url"))],
1209 env={ 'RSYNC_PASSWORD': Interpolate("%(kw:key)s", key=GetRsyncParams.withArgs("src", "key")) },
1210 haltOnFailure = True,
1211 logEnviron = False,
1212 locks = NetLockUl,
1213 doStepIf = util.Transform(bool, GetRsyncParams.withArgs("src", "url")),
1214 ))
1215
1216 factory.addStep(ShellCommand(
1217 name = "df",
1218 description = "Reporting disk usage",
1219 command=["df", "-h", "."],
1220 env={'LC_ALL': 'C'},
1221 logEnviron = False,
1222 haltOnFailure = False,
1223 flunkOnFailure = False,
1224 warnOnFailure = False,
1225 alwaysRun = True,
1226 ))
1227
1228 factory.addStep(ShellCommand(
1229 name = "du",
1230 description = "Reporting estimated file space usage",
1231 command=["du", "-sh", "."],
1232 env={'LC_ALL': 'C'},
1233 logEnviron = False,
1234 haltOnFailure = False,
1235 flunkOnFailure = False,
1236 warnOnFailure = False,
1237 alwaysRun = True,
1238 ))
1239
1240 factory.addStep(ShellCommand(
1241 name = "ccachestat",
1242 description = "Reporting ccache stats",
1243 command=["ccache", "-s"],
1244 env = MakeEnv(overrides={ 'PATH': ["${PATH}", "./staging_dir/host/bin"] }),
1245 logEnviron = False,
1246 want_stderr = False,
1247 haltOnFailure = False,
1248 flunkOnFailure = False,
1249 warnOnFailure = False,
1250 hideStepIf = lambda r, s: r==results.FAILURE,
1251 ))
1252
1253 for brname in branchNames:
1254 bldrname = brname + "_" + target
1255 c['builders'].append(BuilderConfig(name=bldrname, workernames=workerNames, factory=factory, nextBuild=GetNextBuild, canStartBuild=canStartBuild))
1256
1257
1258 ####### STATUS TARGETS
1259
1260 # 'status' is a list of Status Targets. The results of each build will be
1261 # pushed to these targets. buildbot/status/*.py has a variety to choose from,
1262 # including web pages, email senders, and IRC bots.
1263
1264 if "status_bind" in inip1:
1265 c['www'] = {
1266 'port': inip1.get("status_bind"),
1267 'plugins': {
1268 'waterfall_view': True,
1269 'console_view': True,
1270 'grid_view': True
1271 }
1272 }
1273
1274 if "status_user" in inip1 and "status_password" in inip1:
1275 c['www']['auth'] = util.UserPasswordAuth([
1276 (inip1.get("status_user"), inip1.get("status_password"))
1277 ])
1278 c['www']['authz'] = util.Authz(
1279 allowRules=[ util.AnyControlEndpointMatcher(role="admins") ],
1280 roleMatchers=[ util.RolesFromUsername(roles=["admins"], usernames=[inip1.get("status_user")]) ]
1281 )
1282
1283 c['services'] = []
1284 if ini.has_section("irc"):
1285 iniirc = ini['irc']
1286 irc_host = iniirc.get("host", None)
1287 irc_port = iniirc.getint("port", 6667)
1288 irc_chan = iniirc.get("channel", None)
1289 irc_nick = iniirc.get("nickname", None)
1290 irc_pass = iniirc.get("password", None)
1291
1292 if irc_host and irc_nick and irc_chan:
1293 irc = reporters.IRC(irc_host, irc_nick,
1294 port = irc_port,
1295 password = irc_pass,
1296 channels = [ irc_chan ],
1297 notify_events = [ 'exception', 'problem', 'recovery' ]
1298 )
1299
1300 c['services'].append(irc)
1301
1302 c['revlink'] = util.RevlinkMatch([
1303 r'https://git.openwrt.org/openwrt/(.*).git'
1304 ],
1305 r'https://git.openwrt.org/?p=openwrt/\1.git;a=commit;h=%s')
1306
1307 ####### DB URL
1308
1309 c['db'] = {
1310 # This specifies what database buildbot uses to store its state. You can leave
1311 # this at its default for all but the largest installations.
1312 'db_url' : "sqlite:///state.sqlite",
1313 }
1314
1315 c['buildbotNetUsageData'] = None