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