|
| 1 | +# vim: set ft=python: |
| 2 | + |
| 3 | +# {{ $allocID := env "NOMAD_ALLOC_ID" }} |
| 4 | + |
| 5 | +import configparser |
| 6 | +import json |
| 7 | +import shlex |
| 8 | +from pathlib import Path |
| 9 | + |
| 10 | +from twisted.internet import defer |
| 11 | + |
| 12 | +from buildbot.process.results import SUCCESS, SKIPPED |
| 13 | +from buildbot.plugins import util, secrets, reporters, worker, schedulers |
| 14 | +from buildbot.plugins import steps |
| 15 | + |
| 16 | +ini = configparser.ConfigParser() |
| 17 | +ini.read('/local/config.ini') |
| 18 | + |
| 19 | +with open(ini['buildbot'].get('workers', '/local/workers.json')) as f: |
| 20 | + js = json.load(f) |
| 21 | + workers = js.get("workers", []) |
| 22 | + builders = js.get("builders", []) |
| 23 | + |
| 24 | +netauth = util.BuildbotNetAuth(conf=Path("/etc/netauth/config.toml")) |
| 25 | + |
| 26 | +authz = util.Authz( |
| 27 | + allowRules=[ |
| 28 | + util.AnyEndpointMatcher(role="ops", defaultDeny=False), |
| 29 | + util.AnyControlEndpointMatcher(role="ops"), |
| 30 | + ], |
| 31 | + roleMatchers=[ |
| 32 | + util.RolesFromGroups(groupPrefix="build-"), |
| 33 | + ] |
| 34 | +) |
| 35 | + |
| 36 | +c = BuildmasterConfig = { |
| 37 | + 'buildbotNetUsageData': None, |
| 38 | + 'protocols': {'pb': {'port': ini['buildbot'].getint('worker-port', 9989)}}, |
| 39 | + 'secretsProviders': [secrets.SecretInAFile(dirname="/secrets/buildbot")], |
| 40 | + 'workers': [], |
| 41 | + 'change_source': [], |
| 42 | + 'collapseRequests': True, |
| 43 | + 'schedulers': [], |
| 44 | + 'builders': [], |
| 45 | + 'services': [reporters.Prometheus(port=9100)], |
| 46 | + 'title': ini['buildbot'].get('title', 'Void Linux'), |
| 47 | + 'titleURL': ini['buildbot'].get('title-url', 'https://voidlinux.org/'), |
| 48 | + 'buildbotURL': ini['buildbot'].get('url', 'http://localhost:8010/'), |
| 49 | + 'www': { |
| 50 | + 'port': ini['buildbot'].getint('www-port', 8010), |
| 51 | + 'plugins': {'waterfall_view': {}, 'console_view': {}, 'grid_view': {}, 'void_view': {}}, |
| 52 | + 'change_hook_dialects': { |
| 53 | + 'github': { |
| 54 | + 'secret': util.Secret('github-webhook'), |
| 55 | + 'strict': True, |
| 56 | + }, |
| 57 | + }, |
| 58 | + 'avatar_methods': [ |
| 59 | + netauth, util.AvatarGitHub(), util.AvatarGravatar(), |
| 60 | + ], |
| 61 | + 'authz': authz, |
| 62 | + 'auth': netauth, |
| 63 | + 'ui_default_config': { |
| 64 | + 'Links.build_link_template': "%(build_number)", |
| 65 | + 'Waterfall.number_background_waterfall': True, |
| 66 | + 'Waterfall.show_builders_without_builds': True, |
| 67 | + 'Builders.show_workers_name': True, |
| 68 | + 'Grid.fullChanges': True, |
| 69 | + }, |
| 70 | + }, |
| 71 | + 'db': { |
| 72 | + 'db_url': ini['buildbot'].get('db-url', 'sqlite:////db/state.sqlite'), |
| 73 | + }, |
| 74 | +} |
| 75 | + |
| 76 | +if 'irc' in ini: |
| 77 | + c['services'].append(reporters.IRC( |
| 78 | + host=ini['irc']['host'], |
| 79 | + port=ini['irc'].getint('port', 6697), |
| 80 | + nick=ini['irc']['nick'], |
| 81 | + password=util.Secret('irc-password'), |
| 82 | + channels=[ini['irc']['channel']], |
| 83 | + authz={'!': ini['irc'].get('authz-users', '').split(' ')}, |
| 84 | + notify_events=ini['irc'].get( |
| 85 | + 'notify-events', 'failure exception cancelled worker' |
| 86 | + ).split(), |
| 87 | + noticeOnChannel=ini['irc'].getboolean('notice', True), |
| 88 | + # useRevisions and showBlameList are not implemented and will cause |
| 89 | + # the irc notifier to error out, do NOT enable them |
| 90 | + useRevisions=ini['irc'].getboolean('use-revisions', False), |
| 91 | + showBlameList=ini['irc'].getboolean('show-blame', False), |
| 92 | + useSSL=ini['irc'].getboolean('use-ssl', True), |
| 93 | + useColors=ini['irc'].getboolean('use-colors', True), |
| 94 | + )) |
| 95 | + |
| 96 | +# ###### WORKERS |
| 97 | + |
| 98 | +for w in workers: |
| 99 | + name = 'worker-' + w['name'] |
| 100 | + passwd = util.Secret('worker-password') |
| 101 | + max_builds = w.get('max-builds', 1) |
| 102 | + c['workers'].append(worker.Worker(name, passwd, max_builds=max_builds)) |
| 103 | + |
| 104 | + |
| 105 | +# ###### SCHEDULERS |
| 106 | + |
| 107 | +builder_names = [] |
| 108 | +for b in builders: |
| 109 | + builder_names.append(b['name']) |
| 110 | + |
| 111 | +c['schedulers'].append(schedulers.SingleBranchScheduler( |
| 112 | + name="all", |
| 113 | + change_filter=util.ChangeFilter(branch='master'), |
| 114 | + treeStableTimer=None, |
| 115 | + builderNames=builder_names)) |
| 116 | + |
| 117 | +c['schedulers'].append(schedulers.ForceScheduler( |
| 118 | + name="force", |
| 119 | + builderNames=builder_names)) |
| 120 | + |
| 121 | + |
| 122 | +# ###### BUILDERS |
| 123 | + |
| 124 | +distdir = 'void-packages' |
| 125 | +bulkdir = 'xbps-bulk' |
| 126 | +hostdir = '/hostdir' |
| 127 | +buildroot = 'buildroot' |
| 128 | +builddir = lambda: util.Interpolate('builddir-%(prop:buildnumber)s') |
| 129 | +do_sync = lambda: util.Interpolate('%(prop:sync)s') == "True" |
| 130 | +hide_skipped = lambda results, _: results == SKIPPED |
| 131 | + |
| 132 | + |
| 133 | +factory = util.BuildFactory() |
| 134 | + |
| 135 | + |
| 136 | +@util.renderer |
| 137 | +def make_xbps_src_cmd(props, cmd): |
| 138 | + command = [ |
| 139 | + f'{distdir}/xbps-src', |
| 140 | + '-H', hostdir, |
| 141 | + '-m', buildroot, |
| 142 | + '-A', props.getProperty('host'), |
| 143 | + ] |
| 144 | + |
| 145 | + if cmd == 'binary-bootstrap': |
| 146 | + command += shlex.split(str(props.getProperty('bootstrap_args'))) |
| 147 | + elif props.getProperty('cross') == 'True': |
| 148 | + command += ['-a', props.getProperty('target')] |
| 149 | + |
| 150 | + command += [cmd] |
| 151 | + |
| 152 | + return command |
| 153 | + |
| 154 | + |
| 155 | +@util.renderer |
| 156 | +def make_xbps_bulk_cmd(props): |
| 157 | + command = [ |
| 158 | + f'../{bulkdir}/configure', |
| 159 | + '-h', hostdir, |
| 160 | + '-d', f'../{distdir}', |
| 161 | + '-m', f'../{buildroot}', |
| 162 | + '-t', |
| 163 | + ] |
| 164 | + if props.getProperty('cross') == 'True': |
| 165 | + command += ['-a', props.getProperty('target')] |
| 166 | + else: |
| 167 | + command += ['-a', 'native-', props.getProperty('host')] |
| 168 | + |
| 169 | + return command |
| 170 | + |
| 171 | + |
| 172 | +class ShellCommandWithChanges(steps.ShellCommand): |
| 173 | + @defer.inlineCallbacks |
| 174 | + def run(self): |
| 175 | + cmd = yield self.makeRemoteShellCommand() |
| 176 | + pkgs = [f.split("/")[-2] for f in self.build.allFiles() |
| 177 | + if f.startswith("srcpkgs/") and f.endswith("/template")] |
| 178 | + cmd.command += pkgs |
| 179 | + yield self.runCommand(cmd) |
| 180 | + return cmd.results() |
| 181 | + |
| 182 | + |
| 183 | +@util.renderer |
| 184 | +def build_packages(props): |
| 185 | + # if a better solver is written |
| 186 | + # cmds = [] |
| 187 | + # for p in str(props.getProperty('packages')).strip().split(): |
| 188 | + # cmds.append(util.ShellArg( |
| 189 | + # command=['make', f'built/{p}'], |
| 190 | + # logname=f'pkg:{p}', |
| 191 | + # haltOnFailure=True, |
| 192 | + # )) |
| 193 | + cmds = [util.ShellArg( |
| 194 | + command=['make', 'all'], |
| 195 | + logname='build', |
| 196 | + haltOnFailure=True, |
| 197 | + )] |
| 198 | + if cmds: |
| 199 | + cmds.append(util.ShellArg( |
| 200 | + command=['make', 'clean'], |
| 201 | + logname='cleanup', |
| 202 | + haltOnFailure=True, |
| 203 | + )) |
| 204 | + return cmds |
| 205 | + |
| 206 | + |
| 207 | +@util.renderer |
| 208 | +def make_prune_cmd(props): |
| 209 | + return ['bash', '-c', |
| 210 | + util.Interpolate(f""" |
| 211 | +export XBPS_TARGET_ARCH="%(prop:target)s" |
| 212 | +for repo in / /debug /nonfree /bootstrap; do |
| 213 | + xbps-rindex -r "{hostdir}/binpkgs/$repo" |
| 214 | +done |
| 215 | +if [ "$XBPS_TARGET_ARCH" = i686 ]; then |
| 216 | + for repo in /multilib /multilib/nonfree /multilib/bootstrap; do |
| 217 | + XBPS_TARGET_ARCH=x86_64 xbps-rindex -r "{hostdir}/binpkgs/$repo" |
| 218 | + done |
| 219 | +fi |
| 220 | +""")] |
| 221 | + |
| 222 | +@util.renderer |
| 223 | +def make_rsync_cmd(props): |
| 224 | + return ['bash', '-c', |
| 225 | + util.Interpolate(""" |
| 226 | +rsync -vurk --delete-after --delay-updates \ |
| 227 | +--filter='+ */ + %(prop:target)s-repodata + %(prop:target)s-stagedata + *.%(prop:target)s.xbps + otime - .* - *' \ |
| 228 | +--password-file=/secrets/rsync/password /hostdir/binpkgs/ \ |
| 229 | +{{ range nomadService 1 $allocID "build-rsyncd" -}} |
| 230 | +rsync://buildsync-%(prop:worker)s@{{ .Address }}:{{ .Port }}/%(prop:worker)s |
| 231 | +{{ end -}}""")] |
| 232 | + |
| 233 | + |
| 234 | +factory.addStep(steps.Git( |
| 235 | + repourl='https://github.com/void-linux/void-packages.git', |
| 236 | + mode='incremental', |
| 237 | + workdir=distdir, |
| 238 | + progress=True, |
| 239 | + alwaysUseLatest=True, |
| 240 | + name='update_void_packages', |
| 241 | + description='updating void-packages from git', |
| 242 | + descriptionDone='void-packages updated', |
| 243 | + haltOnFailure=True, |
| 244 | + logEnviron=False, |
| 245 | +)) |
| 246 | + |
| 247 | +factory.addStep(steps.Git( |
| 248 | + repourl='https://github.com/void-linux/xbps-bulk.git', |
| 249 | + mode='incremental', |
| 250 | + workdir=bulkdir, |
| 251 | + progress=True, |
| 252 | + alwaysUseLatest=True, |
| 253 | + name='update_xbps_bulk', |
| 254 | + description='updating xbps-bulk from git', |
| 255 | + descriptionDone='xbps-bulk updated', |
| 256 | + haltOnFailure=True, |
| 257 | + logEnviron=False, |
| 258 | +)) |
| 259 | + |
| 260 | +factory.addStep(steps.ShellCommand( |
| 261 | + command=make_xbps_src_cmd.withArgs('binary-bootstrap'), |
| 262 | + name='bootstrap', |
| 263 | + description='running xbps-src binary-bootstrap', |
| 264 | + descriptionDone='xbps-src binary-bootstrap done', |
| 265 | + haltOnFailure=True, |
| 266 | + logEnviron=False, |
| 267 | + usePTY=True, |
| 268 | + workdir='.', |
| 269 | +)) |
| 270 | + |
| 271 | +factory.addStep(steps.ShellCommand( |
| 272 | + command=make_xbps_src_cmd.withArgs('bootstrap-update'), |
| 273 | + name='bootstrap_update', |
| 274 | + description='updating xbps-src bootstrap packages', |
| 275 | + descriptionDone='xbps-src bootstrap-update done', |
| 276 | + haltOnFailure=True, |
| 277 | + logEnviron=False, |
| 278 | + usePTY=True, |
| 279 | + workdir='.', |
| 280 | +)) |
| 281 | + |
| 282 | +factory.addStep(ShellCommandWithChanges( |
| 283 | + command=make_xbps_bulk_cmd, |
| 284 | + name='find_packages', |
| 285 | + description='finding packages to build', |
| 286 | + descriptionDone='found packages', |
| 287 | + haltOnFailure=True, |
| 288 | + logEnviron=False, |
| 289 | + usePTY=True, |
| 290 | + workdir=builddir(), |
| 291 | +)) |
| 292 | + |
| 293 | +factory.addStep(steps.SetPropertyFromCommand( |
| 294 | + command=['make', 'print_pkgs'], |
| 295 | + property='packages', |
| 296 | + name='get_packages', |
| 297 | + description='collecting packages to build', |
| 298 | + descriptionDone='collected packages', |
| 299 | + haltOnFailure=True, |
| 300 | + logEnviron=False, |
| 301 | + workdir=builddir(), |
| 302 | +)) |
| 303 | + |
| 304 | +factory.addStep(steps.ShellSequence( |
| 305 | + commands=build_packages, |
| 306 | + name='build_packages', |
| 307 | + description='building packages', |
| 308 | + descriptionDone='built packages', |
| 309 | + haltOnFailure=True, |
| 310 | + logEnviron=False, |
| 311 | + usePTY=True, |
| 312 | + workdir=builddir(), |
| 313 | + timeout=14400, |
| 314 | +)) |
| 315 | + |
| 316 | +factory.addStep(steps.ShellCommand( |
| 317 | + command=make_prune_cmd, |
| 318 | + name='prune_packages', |
| 319 | + description='removing obsolete packages', |
| 320 | + descriptionDone='removed obsolete packages', |
| 321 | + haltOnFailure=True, |
| 322 | + logEnviron=False, |
| 323 | + usePTY=True, |
| 324 | + workdir='.', |
| 325 | + timeout=14400, |
| 326 | +)) |
| 327 | + |
| 328 | +factory.addStep(steps.ShellCommand( |
| 329 | + command=make_rsync_cmd, |
| 330 | + name='sync_packages', |
| 331 | + description='syncing packages to the shadow repository', |
| 332 | + descriptionDone='synced packages to the shadow repository', |
| 333 | + alwaysRun=True, |
| 334 | + logEnviron=False, |
| 335 | + usePTY=True, |
| 336 | + workdir='.', |
| 337 | + doStepIf=do_sync(), |
| 338 | + hideStepIf=hide_skipped, |
| 339 | + timeout=14400, |
| 340 | + decodeRC={ |
| 341 | + 0: SUCCESS, |
| 342 | + 23: SUCCESS, |
| 343 | + 24: SUCCESS, |
| 344 | + }, |
| 345 | +)) |
| 346 | + |
| 347 | +for b in builders: |
| 348 | + workernames = ["worker-" + b['worker']] |
| 349 | + |
| 350 | + name = b['name'] |
| 351 | + hostarch = b['host'] |
| 352 | + targetarch = b.get('target', hostarch) |
| 353 | + props = { |
| 354 | + 'name': name, |
| 355 | + 'host': hostarch, |
| 356 | + 'target': targetarch, |
| 357 | + 'cross': str(hostarch != targetarch), |
| 358 | + 'worker': b['worker'], |
| 359 | + 'sync': str(b['sync']), |
| 360 | + 'bootstrap_args': b.get('bootstrap_args', '-N'), |
| 361 | + } |
| 362 | + |
| 363 | + c['builders'].append(util.BuilderConfig( |
| 364 | + name=name, |
| 365 | + workernames=workernames, |
| 366 | + factory=factory, |
| 367 | + properties=props, |
| 368 | + )) |
0 commit comments