phase1: create version directories
[buildbot.git] / phase1 / master.cfg
1 # -*- python -*-
2 # ex: set syntax=python:
3
4 import os
5 import re
6 import subprocess
7 import ConfigParser
8
9 from buildbot import locks
10
11 # This is a sample buildmaster config file. It must be installed as
12 # 'master.cfg' in your buildmaster's base directory.
13
14 ini = ConfigParser.ConfigParser()
15 ini.read("./config.ini")
16
17 # This is the dictionary that the buildmaster pays attention to. We also use
18 # a shorter alias to save typing.
19 c = BuildmasterConfig = {}
20
21 ####### BUILDSLAVES
22
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
27
28 slave_port = 9989
29
30 if ini.has_option("general", "port"):
31 slave_port = ini.getint("general", "port")
32
33 c['slaves'] = []
34
35 for section in ini.sections():
36 if section.startswith("slave "):
37 if ini.has_option(section, "name") and ini.has_option(section, "password"):
38 name = ini.get(section, "name")
39 password = ini.get(section, "password")
40 max_builds = 1
41 if ini.has_option(section, "builds"):
42 max_builds = ini.getint(section, "builds")
43 c['slaves'].append(BuildSlave(name, password, max_builds = max_builds))
44
45 # 'slavePortnum' defines the TCP port to listen on for connections from slaves.
46 # This must match the value configured into the buildslaves (with their
47 # --master option)
48 c['slavePortnum'] = slave_port
49
50 # coalesce builds
51 c['mergeRequests'] = True
52
53 ####### CHANGESOURCES
54
55 home_dir = os.path.abspath(ini.get("general", "homedir"))
56 tree_expire = 0
57
58 if ini.has_option("general", "expire"):
59 tree_expire = ini.getint("general", "expire")
60
61 repo_url = ini.get("repo", "url")
62 repo_branch = "master"
63
64 if ini.has_option("repo", "branch"):
65 repo_branch = ini.get("repo", "branch")
66
67 rsync_bin_url = ini.get("rsync", "binary_url")
68 rsync_bin_key = ini.get("rsync", "binary_password")
69
70 rsync_src_url = None
71 rsync_src_key = None
72
73 if ini.has_option("rsync", "source_url"):
74 rsync_src_url = ini.get("rsync", "source_url")
75 rsync_src_key = ini.get("rsync", "source_password")
76
77 gpg_home = "~/.gnupg"
78 gpg_keyid = None
79 gpg_comment = "Unattended build signature"
80 gpg_passfile = "/dev/null"
81
82 if ini.has_option("gpg", "home"):
83 gpg_home = ini.get("gpg", "home")
84
85 if ini.has_option("gpg", "keyid"):
86 gpg_keyid = ini.get("gpg", "keyid")
87
88 if ini.has_option("gpg", "comment"):
89 gpg_comment = ini.get("gpg", "comment")
90
91 if ini.has_option("gpg", "passfile"):
92 gpg_passfile = ini.get("gpg", "passfile")
93
94
95 # find targets
96 targets = [ ]
97
98 if not os.path.isdir(home_dir+'/source.git'):
99 subprocess.call(["git", "clone", "--depth=1", "--branch="+repo_branch, repo_url, home_dir+'/source.git'])
100 else:
101 subprocess.call(["git", "pull"], cwd = home_dir+'/source.git')
102
103 findtargets = subprocess.Popen([home_dir+'/dumpinfo.pl', 'targets'],
104 stdout = subprocess.PIPE, cwd = home_dir+'/source.git')
105
106 while True:
107 line = findtargets.stdout.readline()
108 if not line:
109 break
110 ta = line.strip().split(' ')
111 targets.append(ta[0])
112
113
114 # the 'change_source' setting tells the buildmaster how it should find out
115 # about source code changes. Here we point to the buildbot clone of pyflakes.
116
117 from buildbot.changes.gitpoller import GitPoller
118 c['change_source'] = []
119 c['change_source'].append(GitPoller(
120 repo_url,
121 workdir=home_dir+'/work.git', branch='master',
122 pollinterval=300))
123
124 ####### SCHEDULERS
125
126 # Configure the Schedulers, which decide how to react to incoming changes. In this
127 # case, just kick off a 'basebuild' build
128
129 from buildbot.schedulers.basic import SingleBranchScheduler
130 from buildbot.schedulers.forcesched import ForceScheduler
131 from buildbot.changes import filter
132 c['schedulers'] = []
133 c['schedulers'].append(SingleBranchScheduler(
134 name="all",
135 change_filter=filter.ChangeFilter(branch='master'),
136 treeStableTimer=60,
137 builderNames=targets))
138
139 c['schedulers'].append(ForceScheduler(
140 name="force",
141 builderNames=targets))
142
143 ####### BUILDERS
144
145 # The 'builders' list defines the Builders, which tell Buildbot how to perform a build:
146 # what steps, and which slaves can execute them. Note that any particular build will
147 # only take place on one slave.
148
149 from buildbot.process.factory import BuildFactory
150 from buildbot.steps.source.git import Git
151 from buildbot.steps.shell import ShellCommand
152 from buildbot.steps.shell import SetProperty
153 from buildbot.steps.transfer import FileUpload
154 from buildbot.steps.transfer import FileDownload
155 from buildbot.steps.master import MasterShellCommand
156 from buildbot.process.properties import WithProperties
157
158
159 CleanTargetMap = [
160 [ "tools", "tools/clean" ],
161 [ "chain", "toolchain/clean" ],
162 [ "linux", "target/linux/clean" ],
163 [ "dir", "dirclean" ],
164 [ "dist", "distclean" ]
165 ]
166
167 def IsCleanRequested(pattern):
168 def CheckCleanProperty(step):
169 val = step.getProperty("clean")
170 if val and re.match(pattern, val):
171 return True
172 else:
173 return False
174
175 return CheckCleanProperty
176
177 def IsTaggingRequested(step):
178 val = step.getProperty("tag")
179 if val and re.match("^[0-9]+\.[0-9]+\.[0-9]+$", val):
180 return True
181 else:
182 return False
183
184 def IsNoTaggingRequested(step):
185 return not IsTaggingRequested(step)
186
187 def IsNoMasterBuild(step):
188 return repo_branch != "master"
189
190 def GetBaseVersion(props):
191 if re.match("^[^-]+-[0-9]+\.[0-9]+$", repo_branch):
192 return repo_branch.split('-')[1]
193 else:
194 return "master"
195
196 def GetVersionPrefix(props):
197 basever = GetBaseVersion(props)
198 if props.hasProperty("tag") and re.match("^[0-9]+\.[0-9]+\.[0-9]+$", props["tag"]):
199 return "%s/" % props["tag"]
200 elif basever != "master":
201 return "%s-HEAD/" % basever
202 else:
203 return ""
204
205
206 c['builders'] = []
207
208 dlLock = locks.SlaveLock("slave_dl")
209
210 checkBuiltin = re.sub('[\t\n ]+', ' ', """
211 checkBuiltin() {
212 local symbol op path file;
213 for file in $CHANGED_FILES; do
214 case "$file" in
215 package/*/*) : ;;
216 *) return 0 ;;
217 esac;
218 done;
219 while read symbol op path; do
220 case "$symbol" in package-*)
221 symbol="${symbol##*(}";
222 symbol="${symbol%)}";
223 for file in $CHANGED_FILES; do
224 case "$file" in "package/$path/"*)
225 grep -qsx "$symbol=y" .config && return 0
226 ;; esac;
227 done;
228 esac;
229 done < tmp/.packagedeps;
230 return 1;
231 }
232 """).strip()
233
234
235 class IfBuiltinShellCommand(ShellCommand):
236 def _quote(self, str):
237 if re.search("[^a-zA-Z0-9/_.-]", str):
238 return "'%s'" %(re.sub("'", "'\"'\"'", str))
239 return str
240
241 def setCommand(self, command):
242 if not isinstance(command, (str, unicode)):
243 command = ' '.join(map(self._quote, command))
244 self.command = [
245 '/bin/sh', '-c',
246 '%s; if checkBuiltin; then %s; else exit 0; fi' %(checkBuiltin, command)
247 ]
248
249 def setupEnvironment(self, cmd):
250 slaveEnv = self.slaveEnvironment
251 if slaveEnv is None:
252 slaveEnv = { }
253 changedFiles = { }
254 for request in self.build.requests:
255 for source in request.sources:
256 for change in source.changes:
257 for file in change.files:
258 changedFiles[file] = True
259 fullSlaveEnv = slaveEnv.copy()
260 fullSlaveEnv['CHANGED_FILES'] = ' '.join(changedFiles.keys())
261 cmd.args['env'] = fullSlaveEnv
262
263 slaveNames = [ ]
264
265 for slave in c['slaves']:
266 slaveNames.append(slave.slavename)
267
268 for target in targets:
269 ts = target.split('/')
270
271 factory = BuildFactory()
272
273 # find number of cores
274 factory.addStep(SetProperty(
275 name = "nproc",
276 property = "nproc",
277 description = "Finding number of CPUs",
278 command = ["nproc"]))
279
280 # expire tree if needed
281 if tree_expire > 0:
282 factory.addStep(FileDownload(
283 mastersrc = "expire.sh",
284 slavedest = "../expire.sh",
285 mode = 0755))
286
287 factory.addStep(ShellCommand(
288 name = "expire",
289 description = "Checking for build tree expiry",
290 command = ["./expire.sh", str(tree_expire)],
291 workdir = ".",
292 haltOnFailure = True,
293 timeout = 2400))
294
295 # user-requested clean targets
296 for tuple in CleanTargetMap:
297 factory.addStep(ShellCommand(
298 name = tuple[1],
299 description = 'User-requested "make %s"' % tuple[1],
300 command = ["make", tuple[1], "V=s"],
301 doStepIf = IsCleanRequested(tuple[0])
302 ))
303
304 factory.addStep(MasterShellCommand(
305 name = "maketag",
306 description = "Tagging Git repository",
307 command = [home_dir+'/maketag.sh', '-i', '-k', str(gpg_keyid or ''),
308 '-p', str(gpg_passfile or ''), '-v', WithProperties("%(tag:-)s")],
309 path = home_dir+'/source.git',
310 env = {'GNUPGHOME': gpg_home},
311 haltOnFailure = True,
312 doStepIf = IsTaggingRequested
313 ))
314
315 # switch to branch
316 factory.addStep(ShellCommand(
317 name = "switchbranch",
318 description = "Checking out Git branch",
319 command = ["git", "checkout", repo_branch],
320 haltOnFailure = True,
321 doStepIf = IsNoTaggingRequested
322 ))
323
324 # check out the source
325 factory.addStep(Git(
326 repourl = repo_url,
327 branch = repo_branch,
328 mode = 'incremental',
329 method = 'clean'))
330
331 # fetch tags
332 factory.addStep(ShellCommand(
333 name = "fetchtag",
334 description = "Fetching Git tags",
335 command = ["git", "fetch", "--tags", "--", repo_url],
336 haltOnFailure = True,
337 doStepIf = IsTaggingRequested
338 ))
339
340 # switch to tag
341 factory.addStep(ShellCommand(
342 name = "switchtag",
343 description = "Checking out Git tag",
344 command = ["git", "checkout", WithProperties("tags/v%(tag:-)s")],
345 haltOnFailure = True,
346 doStepIf = IsTaggingRequested
347 ))
348
349 factory.addStep(ShellCommand(
350 name = "rmtmp",
351 description = "Remove tmp folder",
352 command=["rm", "-rf", "tmp/"]))
353
354 # feed
355 # factory.addStep(ShellCommand(
356 # name = "feedsconf",
357 # description = "Copy the feeds.conf",
358 # command='''cp ~/feeds.conf ./feeds.conf''' ))
359
360 # feed
361 factory.addStep(ShellCommand(
362 name = "rmfeedlinks",
363 description = "Remove feed symlinks",
364 command=["rm", "-rf", "package/feeds/"]))
365
366 # feed
367 factory.addStep(ShellCommand(
368 name = "updatefeeds",
369 description = "Updating feeds",
370 command=["./scripts/feeds", "update"]))
371
372 # feed
373 factory.addStep(ShellCommand(
374 name = "installfeeds",
375 description = "Installing feeds",
376 command=["./scripts/feeds", "install", "-a"]))
377
378 # seed config
379 factory.addStep(FileDownload(
380 mastersrc = "config.seed",
381 slavedest = ".config",
382 mode = 0644
383 ))
384
385 # configure
386 factory.addStep(ShellCommand(
387 name = "newconfig",
388 description = "Seeding .config",
389 command = "printf 'CONFIG_TARGET_%s=y\\nCONFIG_TARGET_%s_%s=y\\n' >> .config" %(ts[0], ts[0], ts[1])
390 ))
391
392 factory.addStep(ShellCommand(
393 name = "delbin",
394 description = "Removing output directory",
395 command = ["rm", "-rf", "bin/"]
396 ))
397
398 factory.addStep(ShellCommand(
399 name = "defconfig",
400 description = "Populating .config",
401 command = ["make", "defconfig"]
402 ))
403
404 # check arch
405 factory.addStep(ShellCommand(
406 name = "checkarch",
407 description = "Checking architecture",
408 command = ["grep", "-sq", "CONFIG_TARGET_%s=y" %(ts[0]), ".config"],
409 logEnviron = False,
410 want_stdout = False,
411 want_stderr = False,
412 haltOnFailure = True
413 ))
414
415 # find libc suffix
416 factory.addStep(SetProperty(
417 name = "libc",
418 property = "libc",
419 description = "Finding libc suffix",
420 command = ["sed", "-ne", '/^CONFIG_LIBC=/ { s!^CONFIG_LIBC="\\(.*\\)"!\\1!; s!^musl$!!; s!.\\+!-&!p }', ".config"]))
421
422 # install build key
423 factory.addStep(FileDownload(mastersrc=home_dir+'/key-build', slavedest="key-build", mode=0600))
424 factory.addStep(FileDownload(mastersrc=home_dir+'/key-build.pub', slavedest="key-build.pub", mode=0600))
425
426 # prepare dl
427 factory.addStep(ShellCommand(
428 name = "dldir",
429 description = "Preparing dl/",
430 command = "mkdir -p $HOME/dl && rm -rf ./dl && ln -sf $HOME/dl ./dl",
431 logEnviron = False,
432 want_stdout = False
433 ))
434
435 # prepare tar
436 factory.addStep(ShellCommand(
437 name = "dltar",
438 description = "Building GNU tar",
439 command = ["make", WithProperties("-j%(nproc:~4)s"), "tools/tar/install", "V=s"],
440 haltOnFailure = True
441 ))
442
443 # populate dl
444 factory.addStep(ShellCommand(
445 name = "dlrun",
446 description = "Populating dl/",
447 command = ["make", WithProperties("-j%(nproc:~4)s"), "download", "V=s"],
448 logEnviron = False,
449 locks = [dlLock.access('exclusive')]
450 ))
451
452 factory.addStep(ShellCommand(
453 name = "cleanbase",
454 description = "Cleaning base-files",
455 command=["make", "package/base-files/clean", "V=s"]
456 ))
457
458 # build
459 factory.addStep(ShellCommand(
460 name = "tools",
461 description = "Building tools",
462 command = ["make", WithProperties("-j%(nproc:~4)s"), "tools/install", "V=s"],
463 haltOnFailure = True
464 ))
465
466 factory.addStep(ShellCommand(
467 name = "toolchain",
468 description = "Building toolchain",
469 command=["make", WithProperties("-j%(nproc:~4)s"), "toolchain/install", "V=s"],
470 haltOnFailure = True
471 ))
472
473 factory.addStep(ShellCommand(
474 name = "kmods",
475 description = "Building kmods",
476 command=["make", WithProperties("-j%(nproc:~4)s"), "target/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
477 #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])},
478 haltOnFailure = True
479 ))
480
481 factory.addStep(ShellCommand(
482 name = "pkgbuild",
483 description = "Building packages",
484 command=["make", WithProperties("-j%(nproc:~4)s"), "package/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
485 #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])},
486 haltOnFailure = True
487 ))
488
489 # factory.addStep(IfBuiltinShellCommand(
490 factory.addStep(ShellCommand(
491 name = "pkginstall",
492 description = "Installing packages",
493 command=["make", WithProperties("-j%(nproc:~4)s"), "package/install", "V=s"],
494 haltOnFailure = True
495 ))
496
497 factory.addStep(ShellCommand(
498 name = "pkgindex",
499 description = "Indexing packages",
500 command=["make", WithProperties("-j%(nproc:~4)s"), "package/index", "V=s"],
501 haltOnFailure = True
502 ))
503
504 #factory.addStep(IfBuiltinShellCommand(
505 factory.addStep(ShellCommand(
506 name = "images",
507 description = "Building images",
508 command=["make", WithProperties("-j%(nproc:~4)s"), "target/install", "V=s"],
509 haltOnFailure = True
510 ))
511
512 factory.addStep(ShellCommand(
513 name = "checksums",
514 description = "Calculating checksums",
515 command=["make", "-j1", "checksum", "V=s"],
516 haltOnFailure = True
517 ))
518
519 # sign
520 if gpg_keyid is not None:
521 factory.addStep(MasterShellCommand(
522 name = "signprepare",
523 description = "Preparing temporary signing directory",
524 command = ["mkdir", "-p", "%s/signing" %(home_dir)],
525 haltOnFailure = True
526 ))
527
528 factory.addStep(ShellCommand(
529 name = "signpack",
530 description = "Packing files to sign",
531 command = WithProperties("find bin/targets/%s/%s%%(libc)s/ -mindepth 1 -maxdepth 2 -type f -name sha256sums -print0 -or -name Packages -print0 | xargs -0 tar -czf sign.tar.gz" %(ts[0], ts[1])),
532 haltOnFailure = True
533 ))
534
535 factory.addStep(FileUpload(
536 slavesrc = "sign.tar.gz",
537 masterdest = "%s/signing/%s.%s.tar.gz" %(home_dir, ts[0], ts[1]),
538 haltOnFailure = True
539 ))
540
541 factory.addStep(MasterShellCommand(
542 name = "signfiles",
543 description = "Signing files",
544 command = ["%s/signall.sh" %(home_dir), "%s/signing/%s.%s.tar.gz" %(home_dir, ts[0], ts[1]), gpg_keyid, gpg_comment],
545 env = {'GNUPGHOME': gpg_home, 'PASSFILE': gpg_passfile},
546 haltOnFailure = True
547 ))
548
549 factory.addStep(FileDownload(
550 mastersrc = "%s/signing/%s.%s.tar.gz" %(home_dir, ts[0], ts[1]),
551 slavedest = "sign.tar.gz",
552 haltOnFailure = True
553 ))
554
555 factory.addStep(ShellCommand(
556 name = "signunpack",
557 description = "Unpacking signed files",
558 command = ["tar", "-xzf", "sign.tar.gz"],
559 haltOnFailure = True
560 ))
561
562 # upload
563 factory.addStep(ShellCommand(
564 name = "dirprepare",
565 description = "Preparing upload directory structure",
566 command = ["mkdir", "-p", WithProperties("tmp/upload/%%(prefix)stargets/%s/%s" %(ts[0], ts[1]), prefix=GetVersionPrefix)],
567 haltOnFailure = True
568 ))
569
570 factory.addStep(ShellCommand(
571 name = "linkprepare",
572 description = "Preparing repository symlink",
573 command = ["ln", "-s", "-f", WithProperties("../packages-%(basever)s", basever=GetBaseVersion), WithProperties("tmp/upload/%(prefix)spackages", prefix=GetVersionPrefix)],
574 doStepIf = IsNoMasterBuild,
575 haltOnFailure = True
576 ))
577
578 factory.addStep(ShellCommand(
579 name = "dirupload",
580 description = "Uploading directory structure",
581 command = ["rsync", "-avz", "tmp/upload/", "%s/" %(rsync_bin_url)],
582 env={'RSYNC_PASSWORD': rsync_bin_key},
583 haltOnFailure = True,
584 logEnviron = False
585 ))
586
587 factory.addStep(ShellCommand(
588 name = "targetupload",
589 description = "Uploading target files",
590 command=["rsync", "--delete", "--checksum", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1]),
591 "-avz", WithProperties("bin/targets/%s/%s%%(libc)s/" %(ts[0], ts[1])),
592 WithProperties("%s/%%(prefix)stargets/%s/%s/" %(rsync_bin_url, ts[0], ts[1]), prefix=GetVersionPrefix)],
593 env={'RSYNC_PASSWORD': rsync_bin_key},
594 haltOnFailure = True,
595 logEnviron = False
596 ))
597
598 if rsync_src_url is not None:
599 factory.addStep(ShellCommand(
600 name = "sourceupload",
601 description = "Uploading source archives",
602 command=["rsync", "--checksum", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1]), "-avz", "dl/", "%s/" %(rsync_src_url)],
603 env={'RSYNC_PASSWORD': rsync_src_key},
604 haltOnFailure = True,
605 logEnviron = False
606 ))
607
608 if False:
609 factory.addStep(ShellCommand(
610 name = "packageupload",
611 description = "Uploading package files",
612 command=["rsync", "--delete", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1]), "-avz", "bin/packages/", "%s/packages/" %(rsync_bin_url)],
613 env={'RSYNC_PASSWORD': rsync_bin_key},
614 haltOnFailure = False,
615 logEnviron = False
616 ))
617
618 # logs
619 if False:
620 factory.addStep(ShellCommand(
621 name = "upload",
622 description = "Uploading logs",
623 command=["rsync", "--delete", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1]), "-avz", "logs/", "%s/logs/%s/%s/" %(rsync_bin_url, ts[0], ts[1])],
624 env={'RSYNC_PASSWORD': rsync_bin_key},
625 haltOnFailure = False,
626 alwaysRun = True,
627 logEnviron = False
628 ))
629
630 from buildbot.config import BuilderConfig
631
632 c['builders'].append(BuilderConfig(name=target, slavenames=slaveNames, factory=factory))
633
634
635 ####### STATUS TARGETS
636
637 # 'status' is a list of Status Targets. The results of each build will be
638 # pushed to these targets. buildbot/status/*.py has a variety to choose from,
639 # including web pages, email senders, and IRC bots.
640
641 c['status'] = []
642
643 from buildbot.status import html
644 from buildbot.status.web import authz, auth
645
646 if ini.has_option("status", "bind"):
647 if ini.has_option("status", "user") and ini.has_option("status", "password"):
648 authz_cfg=authz.Authz(
649 # change any of these to True to enable; see the manual for more
650 # options
651 auth=auth.BasicAuth([(ini.get("status", "user"), ini.get("status", "password"))]),
652 gracefulShutdown = 'auth',
653 forceBuild = 'auth', # use this to test your slave once it is set up
654 forceAllBuilds = 'auth',
655 pingBuilder = False,
656 stopBuild = 'auth',
657 stopAllBuilds = 'auth',
658 cancelPendingBuild = 'auth',
659 )
660 c['status'].append(html.WebStatus(http_port=ini.get("status", "bind"), authz=authz_cfg))
661 else:
662 c['status'].append(html.WebStatus(http_port=ini.get("status", "bind")))
663
664
665 from buildbot.status import words
666
667 if ini.has_option("irc", "host") and ini.has_option("irc", "nickname") and ini.has_option("irc", "channel"):
668 irc_host = ini.get("irc", "host")
669 irc_port = 6667
670 irc_chan = ini.get("irc", "channel")
671 irc_nick = ini.get("irc", "nickname")
672 irc_pass = None
673
674 if ini.has_option("irc", "port"):
675 irc_port = ini.getint("irc", "port")
676
677 if ini.has_option("irc", "password"):
678 irc_pass = ini.get("irc", "password")
679
680 irc = words.IRC(irc_host, irc_nick, port = irc_port, password = irc_pass,
681 channels = [{ "channel": irc_chan }],
682 notify_events = {
683 'exception': 1,
684 'successToFailure': 1,
685 'failureToSuccess': 1
686 }
687 )
688
689 c['status'].append(irc)
690
691
692 ####### PROJECT IDENTITY
693
694 # the 'title' string will appear at the top of this buildbot
695 # installation's html.WebStatus home page (linked to the
696 # 'titleURL') and is embedded in the title of the waterfall HTML page.
697
698 c['title'] = ini.get("general", "title")
699 c['titleURL'] = ini.get("general", "title_url")
700
701 # the 'buildbotURL' string should point to the location where the buildbot's
702 # internal web server (usually the html.WebStatus page) is visible. This
703 # typically uses the port number set in the Waterfall 'status' entry, but
704 # with an externally-visible host name which the buildbot cannot figure out
705 # without some help.
706
707 c['buildbotURL'] = ini.get("general", "buildbot_url")
708
709 ####### DB URL
710
711 c['db'] = {
712 # This specifies what database buildbot uses to store its state. You can leave
713 # this at its default for all but the largest installations.
714 'db_url' : "sqlite:///state.sqlite",
715 }