2 # ex: set syntax=python:
10 from buildbot import locks
12 # This is a sample buildmaster config file. It must be installed as
13 # 'master.cfg' in your buildmaster's base directory.
15 ini = ConfigParser.ConfigParser()
16 ini.read("./config.ini")
18 # This is the dictionary that the buildmaster pays attention to. We also use
19 # a shorter alias to save typing.
20 c = BuildmasterConfig = {}
22 ####### PROJECT IDENTITY
24 # the 'title' string will appear at the top of this buildbot
25 # installation's html.WebStatus home page (linked to the
26 # 'titleURL') and is embedded in the title of the waterfall HTML page.
28 c['title'] = ini.get("general", "title")
29 c['titleURL'] = ini.get("general", "title_url")
31 # the 'buildbotURL' string should point to the location where the buildbot's
32 # internal web server (usually the html.WebStatus page) is visible. This
33 # typically uses the port number set in the Waterfall 'status' entry, but
34 # with an externally-visible host name which the buildbot cannot figure out
37 c['buildbotURL'] = ini.get("general", "buildbot_url")
41 # The 'slaves' list defines the set of recognized buildslaves. Each element is
42 # a BuildSlave object, specifying a unique slave name and password. The same
43 # slave name and password must be configured on the slave.
44 from buildbot.buildslave import BuildSlave
48 if ini.has_option("general", "port"):
49 slave_port = ini.getint("general", "port")
54 for section in ini.sections():
55 if section.startswith("slave "):
56 if ini.has_option(section, "name") and ini.has_option(section, "password"):
57 sl_props = { 'dl_lock':None, 'ul_lock':None, 'do_cleanup':False, 'max_builds':1, 'shared_wd':False }
58 name = ini.get(section, "name")
59 password = ini.get(section, "password")
61 if ini.has_option(section, "builds"):
62 max_builds = ini.getint(section, "builds")
63 sl_props['max_builds'] = max_builds
64 if ini.has_option(section, "cleanup"):
65 sl_props['do_cleanup'] = ini.getboolean(section, "cleanup")
66 if ini.has_option(section, "dl_lock"):
67 lockname = ini.get(section, "dl_lock")
68 sl_props['dl_lock'] = lockname
69 if lockname not in NetLocks:
70 NetLocks[lockname] = locks.MasterLock(lockname)
71 if ini.has_option(section, "ul_lock"):
72 lockname = ini.get(section, "dl_lock")
73 sl_props['ul_lock'] = lockname
74 if lockname not in NetLocks:
75 NetLocks[lockname] = locks.MasterLock(lockname)
76 if ini.has_option(section, "shared_wd"):
77 shared_wd = ini.getboolean(section, "shared_wd")
78 sl_props['shared_wd'] = shared_wd
79 if shared_wd and (max_builds != 1):
80 raise ValueError('max_builds must be 1 with shared workdir!')
81 c['slaves'].append(BuildSlave(name, password, max_builds = max_builds, properties = sl_props))
83 # 'slavePortnum' defines the TCP port to listen on for connections from slaves.
84 # This must match the value configured into the buildslaves (with their
86 c['slavePortnum'] = slave_port
89 c['mergeRequests'] = True
91 # Reduce amount of backlog data
92 c['buildHorizon'] = 30
97 work_dir = os.path.abspath(ini.get("general", "workdir") or ".")
98 scripts_dir = os.path.abspath("../scripts")
111 if ini.has_option("general", "expire"):
112 tree_expire = ini.getint("general", "expire")
114 if ini.has_option("general", "other_builds"):
115 other_builds = ini.getint("general", "other_builds")
117 if ini.has_option("general", "cc_version"):
118 cc_version = ini.get("general", "cc_version").split()
119 if len(cc_version) == 1:
120 cc_version = ["eq", cc_version[0]]
122 if ini.has_option("general", "git_ssh"):
123 git_ssh = ini.getboolean("general", "git_ssh")
125 if ini.has_option("general", "git_ssh_key"):
126 git_ssh_key = ini.get("general", "git_ssh_key")
130 if ini.has_option("general", "config_seed"):
131 config_seed = ini.get("general", "config_seed")
133 repo_url = ini.get("repo", "url")
134 repo_branch = "master"
136 if ini.has_option("repo", "branch"):
137 repo_branch = ini.get("repo", "branch")
139 rsync_bin_url = ini.get("rsync", "binary_url")
140 rsync_bin_key = ini.get("rsync", "binary_password")
145 if ini.has_option("rsync", "source_url"):
146 rsync_src_url = ini.get("rsync", "source_url")
147 rsync_src_key = ini.get("rsync", "source_password")
149 rsync_defopts = ["-4", "-v", "--timeout=120", "--contimeout=20"]
152 gpg_passphrase = None
153 gpg_comment = repo_branch.replace("-", " ").title() + " key"
155 if ini.has_option("gpg", "key"):
156 gpg_key = ini.get("gpg", "key")
158 if ini.has_option("gpg", "passphrase"):
159 gpg_passphrase = ini.get("gpg", "passphrase")
161 if ini.has_option("gpg", "comment"):
162 gpg_comment = ini.get("gpg", "comment")
165 usign_comment = "untrusted comment: " + repo_branch.replace("-", " ").title() + " key"
167 if ini.has_option("usign", "key"):
168 usign_key = ini.get("usign", "key")
170 if ini.has_option("usign", "comment"):
171 usign_comment = ini.get("usign", "comment")
173 enable_kmod_archive = True
179 if not os.path.isdir(work_dir+'/source.git'):
180 subprocess.call(["git", "clone", "--depth=1", "--branch="+repo_branch, repo_url, work_dir+'/source.git'])
182 subprocess.call(["git", "pull"], cwd = work_dir+'/source.git')
184 findtargets = subprocess.Popen([scripts_dir + '/dumpinfo.pl', 'targets'],
185 stdout = subprocess.PIPE, cwd = work_dir+'/source.git')
188 line = findtargets.stdout.readline()
191 ta = line.strip().split(' ')
192 targets.append(ta[0])
195 # the 'change_source' setting tells the buildmaster how it should find out
196 # about source code changes. Here we point to the buildbot clone of pyflakes.
198 from buildbot.changes.gitpoller import GitPoller
199 c['change_source'] = []
200 c['change_source'].append(GitPoller(
202 workdir=work_dir+'/work.git', branch=repo_branch,
207 # Configure the Schedulers, which decide how to react to incoming changes. In this
208 # case, just kick off a 'basebuild' build
210 from buildbot.schedulers.basic import SingleBranchScheduler
211 from buildbot.schedulers.forcesched import ForceScheduler
212 from buildbot.changes import filter
214 c['schedulers'].append(SingleBranchScheduler(
216 change_filter=filter.ChangeFilter(branch=repo_branch),
218 builderNames=targets))
220 c['schedulers'].append(ForceScheduler(
222 builderNames=targets))
226 # The 'builders' list defines the Builders, which tell Buildbot how to perform a build:
227 # what steps, and which slaves can execute them. Note that any particular build will
228 # only take place on one slave.
230 from buildbot.process.factory import BuildFactory
231 from buildbot.steps.source.git import Git
232 from buildbot.steps.shell import ShellCommand
233 from buildbot.steps.shell import SetPropertyFromCommand
234 from buildbot.steps.transfer import FileUpload
235 from buildbot.steps.transfer import FileDownload
236 from buildbot.steps.transfer import StringDownload
237 from buildbot.steps.master import MasterShellCommand
238 from buildbot.process.properties import Interpolate
239 from buildbot.process import properties
243 [ "tools", "tools/clean" ],
244 [ "chain", "toolchain/clean" ],
245 [ "linux", "target/linux/clean" ],
246 [ "dir", "dirclean" ],
247 [ "dist", "distclean" ]
250 def IsMakeCleanRequested(pattern):
251 def CheckCleanProperty(step):
252 val = step.getProperty("clean")
253 if val and re.match(pattern, val):
258 return CheckCleanProperty
260 def IsCleanupRequested(step):
261 shared_wd = step.getProperty("shared_wd")
264 do_cleanup = step.getProperty("do_cleanup")
270 def IsExpireRequested(step):
271 shared_wd = step.getProperty("shared_wd")
275 return not IsCleanupRequested(step)
277 def IsGitFreshRequested(step):
278 do_cleanup = step.getProperty("do_cleanup")
284 def IsGitCleanRequested(step):
285 return not IsGitFreshRequested(step)
287 def IsTaggingRequested(step):
288 val = step.getProperty("tag")
289 if val and re.match("^[0-9]+\.[0-9]+\.[0-9]+(?:-rc[0-9]+)?$", val):
294 def IsNoTaggingRequested(step):
295 return not IsTaggingRequested(step)
297 def IsNoMasterBuild(step):
298 return repo_branch != "master"
300 def GetBaseVersion():
301 if re.match("^[^-]+-[0-9]+\.[0-9]+$", repo_branch):
302 return repo_branch.split('-')[1]
307 def GetVersionPrefix(props):
308 basever = GetBaseVersion()
309 if props.hasProperty("tag") and re.match("^[0-9]+\.[0-9]+\.[0-9]+(?:-rc[0-9]+)?$", props["tag"]):
310 return "%s/" % props["tag"]
311 elif basever != "master":
312 return "%s-SNAPSHOT/" % basever
317 def GetNumJobs(props):
318 if props.hasProperty("max_builds") and props.hasProperty("nproc"):
319 return str(int(props["nproc"]) / (props["max_builds"] + other_builds))
325 if props.hasProperty("cc_command"):
326 return props["cc_command"]
332 if props.hasProperty("cxx_command"):
333 return props["cxx_command"]
339 if props.hasProperty("builddir"):
340 return props["builddir"]
341 elif props.hasProperty("workdir"):
342 return props["workdir"]
347 def GetCCache(props):
348 if props.hasProperty("ccache_command") and "ccache" in props["ccache_command"]:
349 return props["ccache_command"]
353 def GetNextBuild(builder, requests):
355 if r.properties and r.properties.hasProperty("tag"):
359 def MakeEnv(overrides=None, tryccache=False):
361 'CCC': Interpolate("%(kw:cc)s", cc=GetCC),
362 'CCXX': Interpolate("%(kw:cxx)s", cxx=GetCXX),
365 env['CC'] = Interpolate("%(kw:cwd)s/ccache_cc.sh", cwd=GetCwd)
366 env['CXX'] = Interpolate("%(kw:cwd)s/ccache_cxx.sh", cwd=GetCwd)
367 env['CCACHE'] = Interpolate("%(kw:ccache)s", ccache=GetCCache)
369 env['CC'] = env['CCC']
370 env['CXX'] = env['CCXX']
372 if overrides is not None:
373 env.update(overrides)
377 def NetLockDl(props):
379 if props.hasProperty("dl_lock"):
380 lock = NetLocks[props["dl_lock"]]
382 return [lock.access('exclusive')]
387 def NetLockUl(props):
389 if props.hasProperty("ul_lock"):
390 lock = NetLocks[props["ul_lock"]]
392 return [lock.access('exclusive')]
396 def UsignSec2Pub(seckey, comment="untrusted comment: secret key"):
398 seckey = base64.b64decode(seckey)
402 return "{}\n{}".format(re.sub(r"\bsecret key$", "public key", comment),
403 base64.b64encode(seckey[0:2] + seckey[32:40] + seckey[72:]))
408 dlLock = locks.SlaveLock("slave_dl")
410 checkBuiltin = re.sub('[\t\n ]+', ' ', """
412 local symbol op path file;
413 for file in $CHANGED_FILES; do
419 while read symbol op path; do
420 case "$symbol" in package-*)
421 symbol="${symbol##*(}";
422 symbol="${symbol%)}";
423 for file in $CHANGED_FILES; do
424 case "$file" in "package/$path/"*)
425 grep -qsx "$symbol=y" .config && return 0
429 done < tmp/.packagedeps;
435 class IfBuiltinShellCommand(ShellCommand):
436 def _quote(self, str):
437 if re.search("[^a-zA-Z0-9/_.-]", str):
438 return "'%s'" %(re.sub("'", "'\"'\"'", str))
441 def setCommand(self, command):
442 if not isinstance(command, (str, unicode)):
443 command = ' '.join(map(self._quote, command))
446 '%s; if checkBuiltin; then %s; else exit 0; fi' %(checkBuiltin, command)
449 def setupEnvironment(self, cmd):
450 slaveEnv = self.slaveEnvironment
454 for request in self.build.requests:
455 for source in request.sources:
456 for change in source.changes:
457 for file in change.files:
458 changedFiles[file] = True
459 fullSlaveEnv = slaveEnv.copy()
460 fullSlaveEnv['CHANGED_FILES'] = ' '.join(changedFiles.keys())
461 cmd.args['env'] = fullSlaveEnv
465 for slave in c['slaves']:
466 slaveNames.append(slave.slavename)
468 for target in targets:
469 ts = target.split('/')
471 factory = BuildFactory()
473 # find number of cores
474 factory.addStep(SetPropertyFromCommand(
477 description = "Finding number of CPUs",
478 command = ["nproc"]))
480 # find gcc and g++ compilers
481 if cc_version is not None:
482 factory.addStep(FileDownload(
483 name = "dlfindbinpl",
484 mastersrc = scripts_dir + '/findbin.pl',
485 slavedest = "../findbin.pl",
488 factory.addStep(SetPropertyFromCommand(
490 property = "cc_command",
491 description = "Finding gcc command",
492 command = ["../findbin.pl", "gcc", cc_version[0], cc_version[1]],
493 haltOnFailure = True))
495 factory.addStep(SetPropertyFromCommand(
497 property = "cxx_command",
498 description = "Finding g++ command",
499 command = ["../findbin.pl", "g++", cc_version[0], cc_version[1]],
500 haltOnFailure = True))
502 # see if ccache is available
503 factory.addStep(SetPropertyFromCommand(
504 property = "ccache_command",
505 command = ["which", "ccache"],
506 description = "Testing for ccache command",
507 haltOnFailure = False,
508 flunkOnFailure = False,
509 warnOnFailure = False,
512 # expire tree if needed
514 factory.addStep(FileDownload(
516 doStepIf = IsExpireRequested,
517 mastersrc = scripts_dir + '/expire.sh',
518 slavedest = "../expire.sh",
521 factory.addStep(ShellCommand(
523 description = "Checking for build tree expiry",
524 command = ["./expire.sh", str(tree_expire)],
526 haltOnFailure = True,
527 doStepIf = IsExpireRequested,
530 # cleanup.sh if needed
531 factory.addStep(FileDownload(
532 name = "dlcleanupsh",
533 mastersrc = scripts_dir + '/cleanup-phase1.sh',
534 slavedest = "../cleanup.sh",
536 doStepIf = IsCleanupRequested))
538 factory.addStep(ShellCommand(
540 description = "Cleaning previous builds",
541 command = ["./cleanup.sh", c['buildbotURL'], Interpolate("%(prop:slavename)s"), Interpolate("%(prop:buildername)s"), "full"],
543 haltOnFailure = True,
544 doStepIf = IsCleanupRequested,
547 factory.addStep(ShellCommand(
549 description = "Cleaning work area",
550 command = ["./cleanup.sh", c['buildbotURL'], Interpolate("%(prop:slavename)s"), Interpolate("%(prop:buildername)s"), "single"],
552 haltOnFailure = True,
553 doStepIf = IsCleanupRequested,
556 # user-requested clean targets
557 for tuple in CleanTargetMap:
558 factory.addStep(ShellCommand(
560 description = 'User-requested "make %s"' % tuple[1],
561 command = ["make", tuple[1], "V=s"],
563 doStepIf = IsMakeCleanRequested(tuple[0])
566 # Workaround bug when switching from a checked out tag back to a branch
567 # Ref: http://lists.infradead.org/pipermail/openwrt-devel/2019-June/017809.html
568 factory.addStep(ShellCommand(
569 name = "gitcheckout",
570 description = "Ensure that Git HEAD is sane",
571 command = "if [ -d .git ]; then git checkout master; else exit 0; fi",
572 haltOnFailure = True))
574 # check out the source
576 # if repo doesn't exist: 'git clone repourl'
577 # method 'clean' runs 'git clean -d -f', method fresh runs 'git clean -d -f x'. Only works with mode='full'
578 # 'git fetch -t repourl branch; git reset --hard revision'
579 # Git() parameters can't take a renderer until buildbot 0.8.10, so we have to split the fresh and clean cases
580 # if buildbot is updated, one can use: method = Interpolate('%(prop:do_cleanup:#?|fresh|clean)s')
584 branch = repo_branch,
587 haltOnFailure = True,
588 doStepIf = IsGitCleanRequested,
594 branch = repo_branch,
597 haltOnFailure = True,
598 doStepIf = IsGitFreshRequested,
602 factory.addStep(ShellCommand(
604 description = "Fetching Git remote refs",
605 command = ["git", "fetch", "origin", "+refs/heads/%s:refs/remotes/origin/%s" %(repo_branch, repo_branch)],
610 factory.addStep(ShellCommand(
612 description = "Checking out Git tag",
613 command = ["git", "checkout", Interpolate("tags/v%(prop:tag:-)s")],
614 haltOnFailure = True,
615 doStepIf = IsTaggingRequested
618 # Verify that Git HEAD points to a tag or branch
619 # Ref: http://lists.infradead.org/pipermail/openwrt-devel/2019-June/017809.html
620 factory.addStep(ShellCommand(
622 description = "Ensure that Git HEAD is pointing to a branch or tag",
623 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]\\."',
624 haltOnFailure = True))
626 factory.addStep(ShellCommand(
628 description = "Remove tmp folder",
629 command=["rm", "-rf", "tmp/"]))
632 # factory.addStep(ShellCommand(
633 # name = "feedsconf",
634 # description = "Copy the feeds.conf",
635 # command='''cp ~/feeds.conf ./feeds.conf''' ))
638 factory.addStep(ShellCommand(
639 name = "rmfeedlinks",
640 description = "Remove feed symlinks",
641 command=["rm", "-rf", "package/feeds/"]))
643 factory.addStep(StringDownload(
645 s = '#!/bin/sh\nexec ${CCACHE} ${CCC} "$@"\n',
646 slavedest = "../ccache_cc.sh",
650 factory.addStep(StringDownload(
652 s = '#!/bin/sh\nexec ${CCACHE} ${CCXX} "$@"\n',
653 slavedest = "../ccache_cxx.sh",
659 factory.addStep(StringDownload(
660 name = "dlgitclonekey",
662 slavedest = "../git-clone.key",
666 factory.addStep(ShellCommand(
667 name = "patchfeedsconf",
668 description = "Patching feeds.conf",
669 command="sed -e 's#https://#ssh://git@#g' feeds.conf.default > feeds.conf",
674 factory.addStep(ShellCommand(
675 name = "updatefeeds",
676 description = "Updating feeds",
677 command=["./scripts/feeds", "update"],
678 env = MakeEnv(tryccache=True, overrides={'GIT_SSH_COMMAND': Interpolate("ssh -o IdentitiesOnly=yes -o IdentityFile=%(kw:cwd)s/git-clone.key -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no", cwd=GetCwd)} if git_ssh else {}),
684 factory.addStep(ShellCommand(
685 name = "rmfeedsconf",
686 description = "Removing feeds.conf",
687 command=["rm", "feeds.conf"],
692 factory.addStep(ShellCommand(
693 name = "installfeeds",
694 description = "Installing feeds",
695 command=["./scripts/feeds", "install", "-a"],
696 env = MakeEnv(tryccache=True),
701 if config_seed is not None:
702 factory.addStep(StringDownload(
703 name = "dlconfigseed",
704 s = config_seed + '\n',
705 slavedest = ".config",
710 factory.addStep(ShellCommand(
712 description = "Seeding .config",
713 command = "printf 'CONFIG_TARGET_%s=y\\nCONFIG_TARGET_%s_%s=y\\nCONFIG_SIGNED_PACKAGES=%s\\n' >> .config" %(ts[0], ts[0], ts[1], 'y' if usign_key is not None else 'n')
716 factory.addStep(ShellCommand(
718 description = "Removing output directory",
719 command = ["rm", "-rf", "bin/"]
722 factory.addStep(ShellCommand(
724 description = "Populating .config",
725 command = ["make", "defconfig"],
730 factory.addStep(ShellCommand(
732 description = "Checking architecture",
733 command = ["grep", "-sq", "CONFIG_TARGET_%s=y" %(ts[0]), ".config"],
741 factory.addStep(SetPropertyFromCommand(
744 description = "Finding libc suffix",
745 command = ["sed", "-ne", '/^CONFIG_LIBC=/ { s!^CONFIG_LIBC="\\(.*\\)"!\\1!; s!^musl$!!; s!.\\+!-&!p }', ".config"]))
748 if usign_key is not None:
749 factory.addStep(StringDownload(
750 name = "dlkeybuildpub",
751 s = UsignSec2Pub(usign_key, usign_comment),
752 slavedest = "key-build.pub",
756 factory.addStep(StringDownload(
758 s = "# fake private key",
759 slavedest = "key-build",
763 factory.addStep(StringDownload(
764 name = "dlkeybuilducert",
765 s = "# fake certificate",
766 slavedest = "key-build.ucert",
771 factory.addStep(ShellCommand(
773 description = "Preparing dl/",
774 command = "mkdir -p $HOME/dl && rm -rf ./dl && ln -sf $HOME/dl ./dl",
780 factory.addStep(ShellCommand(
782 description = "Building and installing GNU tar",
783 command = ["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "tools/tar/compile", "V=s"],
784 env = MakeEnv(tryccache=True),
789 factory.addStep(ShellCommand(
791 description = "Populating dl/",
792 command = ["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "download", "V=s"],
795 locks = [dlLock.access('exclusive')],
798 factory.addStep(ShellCommand(
800 description = "Cleaning base-files",
801 command=["make", "package/base-files/clean", "V=s"]
805 factory.addStep(ShellCommand(
807 description = "Building and installing tools",
808 command = ["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "tools/install", "V=s"],
809 env = MakeEnv(tryccache=True),
813 factory.addStep(ShellCommand(
815 description = "Building and installing toolchain",
816 command=["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "toolchain/install", "V=s"],
821 factory.addStep(ShellCommand(
823 description = "Building kmods",
824 command=["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "target/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
826 #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])},
830 # find kernel version
831 factory.addStep(SetPropertyFromCommand(
832 name = "kernelversion",
833 property = "kernelversion",
834 description = "Finding the effective Kernel version",
835 command = "make --no-print-directory -C target/linux/ val.LINUX_VERSION val.LINUX_RELEASE val.LINUX_VERMAGIC | xargs printf '%s-%s-%s\\n'",
836 env = { 'TOPDIR': Interpolate("%(kw:cwd)s/build", cwd=GetCwd) }
839 factory.addStep(ShellCommand(
841 description = "Cleaning up package build",
842 command=["make", "package/cleanup", "V=s"]
845 factory.addStep(ShellCommand(
847 description = "Building packages",
848 command=["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "package/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
850 #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])},
854 # factory.addStep(IfBuiltinShellCommand(
855 factory.addStep(ShellCommand(
857 description = "Installing packages",
858 command=["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "package/install", "V=s"],
863 factory.addStep(ShellCommand(
865 description = "Indexing packages",
866 command=["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "package/index", "V=s", "CONFIG_SIGNED_PACKAGES="],
871 if enable_kmod_archive:
872 # embed kmod repository. Must happen before 'images'
874 # find rootfs staging directory
875 factory.addStep(SetPropertyFromCommand(
877 property = "stageroot",
878 description = "Finding the rootfs staging directory",
879 command=["make", "--no-print-directory", "val.STAGING_DIR_ROOT"],
880 env = { 'TOPDIR': Interpolate("%(kw:cwd)s/build", cwd=GetCwd) }
883 factory.addStep(ShellCommand(
885 description = "Creating file overlay directory",
886 command=["mkdir", "-p", "files/etc/opkg"],
890 factory.addStep(ShellCommand(
892 description = "Embedding kmod repository configuration",
893 command=Interpolate("sed -e 's#^\\(src/gz .*\\)_core \\(.*\\)/packages$#&\\n\\1_kmods \\2/kmods/%(prop:kernelversion)s#' " +
894 "%(prop:stageroot)s/etc/opkg/distfeeds.conf > files/etc/opkg/distfeeds.conf"),
898 #factory.addStep(IfBuiltinShellCommand(
899 factory.addStep(ShellCommand(
901 description = "Building and installing images",
902 command=["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "target/install", "V=s"],
907 factory.addStep(ShellCommand(
909 description = "Generating config.seed",
910 command=["make", "-j1", "diffconfig", "V=s"],
915 factory.addStep(ShellCommand(
917 description = "Calculating checksums",
918 command=["make", "-j1", "checksum", "V=s"],
923 if enable_kmod_archive:
924 factory.addStep(ShellCommand(
926 description = "Creating kmod directory",
927 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])],
931 factory.addStep(ShellCommand(
932 name = "kmodprepare",
933 description = "Preparing kmod archive",
934 command=["rsync", "--include=/kmod-*.ipk", "--exclude=*", "-va",
935 Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/packages/", target=ts[0], subtarget=ts[1]),
936 Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/kmods/%(prop:kernelversion)s/", target=ts[0], subtarget=ts[1])],
940 factory.addStep(ShellCommand(
942 description = "Indexing kmod archive",
943 command=["make", Interpolate("-j%(kw:jobs)s", jobs=GetNumJobs), "package/index", "V=s", "CONFIG_SIGNED_PACKAGES=",
944 Interpolate("PACKAGE_SUBDIRS=bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/kmods/%(prop:kernelversion)s/", target=ts[0], subtarget=ts[1])],
950 if gpg_key is not None or usign_key is not None:
951 factory.addStep(MasterShellCommand(
952 name = "signprepare",
953 description = "Preparing temporary signing directory",
954 command = ["mkdir", "-p", "%s/signing" %(work_dir)],
958 factory.addStep(ShellCommand(
960 description = "Packing files to sign",
961 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]),
965 factory.addStep(FileUpload(
966 slavesrc = "sign.tar.gz",
967 masterdest = "%s/signing/%s.%s.tar.gz" %(work_dir, ts[0], ts[1]),
971 factory.addStep(MasterShellCommand(
973 description = "Signing files",
974 command = ["%s/signall.sh" %(scripts_dir), "%s/signing/%s.%s.tar.gz" %(work_dir, ts[0], ts[1])],
977 'GPGPASS': gpg_passphrase,
978 'GPGCOMMENT': gpg_comment,
979 'USIGNKEY': usign_key,
980 'USIGNCOMMENT': usign_comment
985 factory.addStep(FileDownload(
986 name = "dlsigntargz",
987 mastersrc = "%s/signing/%s.%s.tar.gz" %(work_dir, ts[0], ts[1]),
988 slavedest = "sign.tar.gz",
992 factory.addStep(ShellCommand(
994 description = "Unpacking signed files",
995 command = ["tar", "-xzf", "sign.tar.gz"],
1000 factory.addStep(ShellCommand(
1001 name = "dirprepare",
1002 description = "Preparing upload directory structure",
1003 command = ["mkdir", "-p", Interpolate("tmp/upload/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s", target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix)],
1004 haltOnFailure = True
1007 factory.addStep(ShellCommand(
1008 name = "linkprepare",
1009 description = "Preparing repository symlink",
1010 command = ["ln", "-s", "-f", Interpolate("../packages-%(kw:basever)s", basever=GetBaseVersion()), Interpolate("tmp/upload/%(kw:prefix)spackages", prefix=GetVersionPrefix)],
1011 doStepIf = IsNoMasterBuild,
1012 haltOnFailure = True
1015 if enable_kmod_archive:
1016 factory.addStep(ShellCommand(
1017 name = "kmoddirprepare",
1018 description = "Preparing kmod archive upload directory",
1019 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)],
1020 haltOnFailure = True
1023 factory.addStep(ShellCommand(
1025 description = "Uploading directory structure",
1026 command = ["rsync", "-az"] + rsync_defopts + ["tmp/upload/", "%s/" %(rsync_bin_url)],
1027 env={'RSYNC_PASSWORD': rsync_bin_key},
1028 haltOnFailure = True,
1032 # download remote sha256sums to 'target-sha256sums'
1033 factory.addStep(ShellCommand(
1034 name = "target-sha256sums",
1035 description = "Fetching remote sha256sums for target",
1036 command = ["rsync", "-z"] + rsync_defopts + [Interpolate("%(kw:rsyncbinurl)s/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s/sha256sums", rsyncbinurl=rsync_bin_url, target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix), "target-sha256sums"],
1037 env={'RSYNC_PASSWORD': rsync_bin_key},
1039 haltOnFailure = False,
1040 flunkOnFailure = False,
1041 warnOnFailure = False,
1044 # build list of files to upload
1045 factory.addStep(FileDownload(
1046 name = "dlsha2rsyncpl",
1047 mastersrc = scripts_dir + '/sha2rsync.pl',
1048 slavedest = "../sha2rsync.pl",
1052 factory.addStep(ShellCommand(
1054 description = "Building list of files to upload",
1055 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"],
1056 haltOnFailure = True,
1059 factory.addStep(FileDownload(
1060 name = "dlrsync.sh",
1061 mastersrc = scripts_dir + '/rsync.sh',
1062 slavedest = "../rsync.sh",
1066 # upload new files and update existing ones
1067 factory.addStep(ShellCommand(
1068 name = "targetupload",
1069 description = "Uploading target files",
1070 command=["../rsync.sh", "--exclude=/kmods/", "--files-from=rsynclist", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1])] + rsync_defopts +
1071 ["-a", Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/", target=ts[0], subtarget=ts[1]),
1072 Interpolate("%(kw:rsyncbinurl)s/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s/", rsyncbinurl=rsync_bin_url, target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix)],
1073 env={'RSYNC_PASSWORD': rsync_bin_key},
1074 haltOnFailure = True,
1078 # delete files which don't exist locally
1079 factory.addStep(ShellCommand(
1080 name = "targetprune",
1081 description = "Pruning target files",
1082 command=["../rsync.sh", "--exclude=/kmods/", "--delete", "--existing", "--ignore-existing", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1])] + rsync_defopts +
1083 ["-a", Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/", target=ts[0], subtarget=ts[1]),
1084 Interpolate("%(kw:rsyncbinurl)s/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s/", rsyncbinurl=rsync_bin_url, target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix)],
1085 env={'RSYNC_PASSWORD': rsync_bin_key},
1086 haltOnFailure = True,
1090 if enable_kmod_archive:
1091 factory.addStep(ShellCommand(
1092 name = "kmodupload",
1093 description = "Uploading kmod archive",
1094 command=["../rsync.sh", "--delete", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1])] + rsync_defopts +
1095 ["-a", Interpolate("bin/targets/%(kw:target)s/%(kw:subtarget)s%(prop:libc)s/kmods/%(prop:kernelversion)s/", target=ts[0], subtarget=ts[1]),
1096 Interpolate("%(kw:rsyncbinurl)s/%(kw:prefix)stargets/%(kw:target)s/%(kw:subtarget)s/kmods/%(prop:kernelversion)s/", rsyncbinurl=rsync_bin_url, target=ts[0], subtarget=ts[1], prefix=GetVersionPrefix)],
1097 env={'RSYNC_PASSWORD': rsync_bin_key},
1098 haltOnFailure = True,
1102 if rsync_src_url is not None:
1103 factory.addStep(ShellCommand(
1104 name = "sourcelist",
1105 description = "Finding source archives to upload",
1106 command = "find dl/ -maxdepth 1 -type f -not -size 0 -not -name '.*' -newer .config -printf '%f\\n' > sourcelist",
1107 haltOnFailure = True
1110 factory.addStep(ShellCommand(
1111 name = "sourceupload",
1112 description = "Uploading source archives",
1113 command=["../rsync.sh", "--files-from=sourcelist", "--size-only", "--delay-updates"] + rsync_defopts +
1114 [Interpolate("--partial-dir=.~tmp~%(kw:target)s~%(kw:subtarget)s~%(prop:slavename)s", target=ts[0], subtarget=ts[1]), "-a", "dl/", "%s/" %(rsync_src_url)],
1115 env={'RSYNC_PASSWORD': rsync_src_key},
1116 haltOnFailure = True,
1121 factory.addStep(ShellCommand(
1122 name = "packageupload",
1123 description = "Uploading package files",
1124 command=["../rsync.sh", "--delete", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1]), "-a"] + rsync_defopts + ["bin/packages/", "%s/packages/" %(rsync_bin_url)],
1125 env={'RSYNC_PASSWORD': rsync_bin_key},
1126 haltOnFailure = False,
1132 factory.addStep(ShellCommand(
1134 description = "Uploading logs",
1135 command=["../rsync.sh", "--delete", "--delay-updates", "--partial-dir=.~tmp~%s~%s" %(ts[0], ts[1]), "-az"] + rsync_defopts + ["logs/", "%s/logs/%s/%s/" %(rsync_bin_url, ts[0], ts[1])],
1136 env={'RSYNC_PASSWORD': rsync_bin_key},
1137 haltOnFailure = False,
1142 factory.addStep(ShellCommand(
1144 description = "Reporting disk usage",
1145 command=["df", "-h", "."],
1146 env={'LC_ALL': 'C'},
1147 haltOnFailure = False,
1151 factory.addStep(ShellCommand(
1152 name = "ccachestat",
1153 description = "Reporting ccache stats",
1154 command=["ccache", "-s"],
1155 env = MakeEnv(overrides={ 'PATH': ["${PATH}", "./staging_dir/host/bin"] }),
1156 want_stderr = False,
1157 haltOnFailure = False,
1158 flunkOnFailure = False,
1159 warnOnFailure = False,
1163 from buildbot.config import BuilderConfig
1165 c['builders'].append(BuilderConfig(name=target, slavenames=slaveNames, factory=factory, nextBuild=GetNextBuild))
1168 ####### STATUS TARGETS
1170 # 'status' is a list of Status Targets. The results of each build will be
1171 # pushed to these targets. buildbot/status/*.py has a variety to choose from,
1172 # including web pages, email senders, and IRC bots.
1176 from buildbot.status import html
1177 from buildbot.status.web import authz, auth
1179 if ini.has_option("status", "bind"):
1180 if ini.has_option("status", "user") and ini.has_option("status", "password"):
1181 authz_cfg=authz.Authz(
1182 # change any of these to True to enable; see the manual for more
1184 auth=auth.BasicAuth([(ini.get("status", "user"), ini.get("status", "password"))]),
1185 gracefulShutdown = 'auth',
1186 forceBuild = 'auth', # use this to test your slave once it is set up
1187 forceAllBuilds = 'auth',
1188 pingBuilder = False,
1190 stopAllBuilds = 'auth',
1191 cancelPendingBuild = 'auth',
1193 c['status'].append(html.WebStatus(http_port=ini.get("status", "bind"), authz=authz_cfg))
1195 c['status'].append(html.WebStatus(http_port=ini.get("status", "bind")))
1198 from buildbot.status import words
1200 if ini.has_option("irc", "host") and ini.has_option("irc", "nickname") and ini.has_option("irc", "channel"):
1201 irc_host = ini.get("irc", "host")
1203 irc_chan = ini.get("irc", "channel")
1204 irc_nick = ini.get("irc", "nickname")
1207 if ini.has_option("irc", "port"):
1208 irc_port = ini.getint("irc", "port")
1210 if ini.has_option("irc", "password"):
1211 irc_pass = ini.get("irc", "password")
1213 irc = words.IRC(irc_host, irc_nick, port = irc_port, password = irc_pass,
1214 channels = [{ "channel": irc_chan }],
1217 'successToFailure': 1,
1218 'failureToSuccess': 1
1222 c['status'].append(irc)
1227 # This specifies what database buildbot uses to store its state. You can leave
1228 # this at its default for all but the largest installations.
1229 'db_url' : "sqlite:///state.sqlite",