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 = 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.transfer import FileDownload
113 "^tools/": "tools/clean",
114 "^toolchain/": "toolchain/clean",
115 "^target/linux/": "target/linux/clean",
116 "^(config|include)/": "dirclean"
119 def IsAffected(pattern):
120 def CheckAffected(change):
121 for request in change.build.requests:
122 for source in request.sources:
123 for change in source.changes:
124 for file in change.files:
125 if re.match(pattern, file):
130 def isPathBuiltin(path):
133 conf = open(".config", "r")
136 line = conf.readline()
139 m = re.match("^(CONFIG_PACKAGE_.+?)=y", line)
141 incl[m.group(1)] = True
145 deps = open("tmp/.packagedeps", "r")
148 line = deps.readline()
151 m = re.match("^package-\$\((CONFIG_PACKAGE_.+?)\) \+= (\S+)", line)
152 if m and incl.get(m.group(1)) == True:
153 pkgs["package/%s" % m.group(2)] = True
158 if pkgs.get(path) == True:
160 path = os.path.dirname(path)
164 def isChangeBuiltin(change):
166 # for request in change.build.requests:
167 # for source in request.sources:
168 # for change in source.changes:
169 # for file in change.files:
170 # if isPathBuiltin(file):
177 dlLock = locks.SlaveLock("slave_dl")
179 checkBuiltin = re.sub('[\t\n ]+', ' ', """
181 local symbol op path file;
182 for file in $CHANGED_FILES; do
188 while read symbol op path; do
189 case "$symbol" in package-*)
190 symbol="${symbol##*(}";
191 symbol="${symbol%)}";
192 for file in $CHANGED_FILES; do
193 case "$file" in "package/$path/"*)
194 grep -qsx "$symbol=y" .config && return 0
198 done < tmp/.packagedeps;
204 class IfBuiltinShellCommand(ShellCommand):
205 def _quote(self, str):
206 if re.search("[^a-zA-Z0-9/_.-]", str):
207 return "'%s'" %(re.sub("'", "'\"'\"'", str))
210 def setCommand(self, command):
211 if not isinstance(command, (str, unicode)):
212 command = ' '.join(map(self._quote, command))
215 '%s; if checkBuiltin; then %s; else exit 0; fi' %(checkBuiltin, command)
218 def setupEnvironment(self, cmd):
219 slaveEnv = self.slaveEnvironment
223 for request in self.build.requests:
224 for source in request.sources:
225 for change in source.changes:
226 for file in change.files:
227 changedFiles[file] = True
228 fullSlaveEnv = slaveEnv.copy()
229 fullSlaveEnv['CHANGED_FILES'] = ' '.join(changedFiles.keys())
230 cmd.args['env'] = fullSlaveEnv
234 for slave in c['slaves']:
235 slaveNames.append(slave.slavename)
237 for target in targets:
238 ts = target.split('/')
240 factory = BuildFactory()
242 # check out the source
243 factory.addStep(Git(repourl=repo_url, mode='update'))
245 factory.addStep(ShellCommand(
247 description = "Remove tmp folder",
248 command=["rm", "-rf", "tmp/"]))
251 # factory.addStep(ShellCommand(
252 # name = "feedsconf",
253 # description = "Copy the feeds.conf",
254 # command='''cp ~/feeds.conf ./feeds.conf''' ))
257 factory.addStep(ShellCommand(
258 name = "updatefeeds",
259 description = "Updating feeds",
260 command=["./scripts/feeds", "update"]))
263 factory.addStep(ShellCommand(
264 name = "installfeeds",
265 description = "Installing feeds",
266 command=["./scripts/feeds", "install", "-a"]))
269 factory.addStep(ShellCommand(
271 description = "Seeding .config",
272 command='''cat <<EOT > .config
274 CONFIG_TARGET_%s_%s=y
275 CONFIG_ALL_NONSHARED=y
278 # CONFIG_IB_STANDALONE is not set
281 CONFIG_SIGNED_PACKAGES=y
282 # CONFIG_PER_FEED_REPO_ADD_COMMENTED is not set
283 CONFIG_KERNEL_KALLSYMS=y
284 CONFIG_COLLECT_KERNEL_DEBUG=y
285 EOT''' %(ts[0], ts[0], ts[1]) ))
287 factory.addStep(ShellCommand(
289 description = "Removing output directory",
290 command = ["rm", "-rf", "bin/"]
293 factory.addStep(ShellCommand(
295 description = "Populating .config",
296 command = ["make", "defconfig"]
300 factory.addStep(ShellCommand(
302 description = "Checking architecture",
303 command = ["grep", "-sq", "CONFIG_TARGET_%s=y" %(ts[0]), ".config"],
311 factory.addStep(FileDownload(mastersrc=home_dir+'/key-build', slavedest="key-build", mode=0600))
314 factory.addStep(ShellCommand(
316 description = "Preparing dl/",
317 command = "mkdir -p $HOME/dl && ln -sf $HOME/dl ./dl",
323 factory.addStep(ShellCommand(
325 description = "Populating dl/",
326 command = ["make", "-j4", "download", "V=s"],
328 locks = [dlLock.access('exclusive')]
331 factory.addStep(ShellCommand(
333 description = "Cleaning base-files",
334 command=["make", "package/base-files/clean", "V=s"]
337 # optional clean steps
338 for pattern, maketarget in MakeTargetMap.items():
339 factory.addStep(ShellCommand(
341 description = maketarget,
342 command=["make", maketarget, "V=s"], doStepIf=IsAffected(pattern)
346 factory.addStep(ShellCommand(
348 description = "Building tools",
349 command = ["make", "-j4", "tools/install", "V=s"],
353 factory.addStep(ShellCommand(
355 description = "Building toolchain",
356 command=["make", "-j4", "toolchain/install", "V=s"],
360 factory.addStep(ShellCommand(
362 description = "Building kmods",
363 command=["make", "-j4", "target/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
364 #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])},
368 factory.addStep(ShellCommand(
370 description = "Building packages",
371 command=["make", "-j4", "package/compile", "V=s", "IGNORE_ERRORS=n m", "BUILD_LOG=1"],
372 #env={'BUILD_LOG_DIR': 'bin/%s' %(ts[0])},
376 # factory.addStep(IfBuiltinShellCommand(
377 factory.addStep(ShellCommand(
379 description = "Installing packages",
380 command=["make", "-j4", "package/install", "V=s"],
381 doStepIf = isChangeBuiltin,
385 factory.addStep(ShellCommand(
387 description = "Indexing packages",
388 command=["make", "-j4", "package/index", "V=s"],
392 #factory.addStep(IfBuiltinShellCommand(
393 factory.addStep(ShellCommand(
395 description = "Building images",
396 command=["make", "-j1", "target/install", "V=s"],
397 doStepIf = isChangeBuiltin,
402 factory.addStep(ShellCommand(
403 name = "uploadprepare",
404 description = "Preparing target directory",
405 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)],
406 env={'RSYNC_PASSWORD': rsync_key},
407 haltOnFailure = True,
411 factory.addStep(ShellCommand(
412 name = "targetupload",
413 description = "Uploading target files",
414 command=["rsync", "--delete", "-avz", "bin/targets/%s/%s/" %(ts[0], ts[1]), "%s/targets/%s/%s/" %(rsync_url, ts[0], ts[1])],
415 env={'RSYNC_PASSWORD': rsync_key},
416 haltOnFailure = True,
421 factory.addStep(ShellCommand(
422 name = "packageupload",
423 description = "Uploading package files",
424 command=["rsync", "--delete", "-avz", "bin/packages/", "%s/packages/" %(rsync_url)],
425 env={'RSYNC_PASSWORD': rsync_key},
426 haltOnFailure = False,
432 factory.addStep(ShellCommand(
434 description = "Uploading logs",
435 command=["rsync", "--delete", "-avz", "logs/", "%s/logs/%s/%s/" %(rsync_url, ts[0], ts[1])],
436 env={'RSYNC_PASSWORD': rsync_key},
437 haltOnFailure = False,
442 from buildbot.config import BuilderConfig
444 c['builders'].append(BuilderConfig(name=target, slavenames=slaveNames, factory=factory))
447 ####### STATUS TARGETS
449 # 'status' is a list of Status Targets. The results of each build will be
450 # pushed to these targets. buildbot/status/*.py has a variety to choose from,
451 # including web pages, email senders, and IRC bots.
455 from buildbot.status import html
456 from buildbot.status.web import authz, auth
458 if ini.has_option("status", "bind"):
459 if ini.has_option("status", "user") and ini.has_option("status", "password"):
460 authz_cfg=authz.Authz(
461 # change any of these to True to enable; see the manual for more
463 auth=auth.BasicAuth([(ini.get("status", "user"), ini.get("status", "password"))]),
464 gracefulShutdown = False,
465 forceBuild = 'auth', # use this to test your slave once it is set up
466 forceAllBuilds = 'auth',
469 stopAllBuilds = 'auth',
470 cancelPendingBuild = 'auth',
472 c['status'].append(html.WebStatus(http_port=ini.get("status", "bind"), authz=authz_cfg))
474 c['status'].append(html.WebStatus(http_port=ini.get("status", "bind")))
476 ####### PROJECT IDENTITY
478 # the 'title' string will appear at the top of this buildbot
479 # installation's html.WebStatus home page (linked to the
480 # 'titleURL') and is embedded in the title of the waterfall HTML page.
482 c['title'] = ini.get("general", "title")
483 c['titleURL'] = ini.get("general", "title_url")
485 # the 'buildbotURL' string should point to the location where the buildbot's
486 # internal web server (usually the html.WebStatus page) is visible. This
487 # typically uses the port number set in the Waterfall 'status' entry, but
488 # with an externally-visible host name which the buildbot cannot figure out
491 c['buildbotURL'] = ini.get("general", "buildbot_url")
496 # This specifies what database buildbot uses to store its state. You can leave
497 # this at its default for all but the largest installations.
498 'db_url' : "sqlite:///state.sqlite",