blob: 1f652f85331b48a5b7fee52e2b988955e9ac34cb [file] [log] [blame]
borenetdb182c72016-09-30 12:53:12 -07001// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package main
6
7/*
8 Generate the tasks.json file.
9*/
10
11import (
borenetdb182c72016-09-30 12:53:12 -070012 "encoding/json"
Eric Boren27225492017-02-01 15:56:55 -050013 "flag"
borenetdb182c72016-09-30 12:53:12 -070014 "fmt"
Eric Boren27225492017-02-01 15:56:55 -050015 "io/ioutil"
borenetdb182c72016-09-30 12:53:12 -070016 "os"
17 "path"
Eric Boren27225492017-02-01 15:56:55 -050018 "regexp"
borenetdb182c72016-09-30 12:53:12 -070019 "sort"
20 "strings"
Eric Boren4b254b92016-11-08 12:55:32 -050021 "time"
borenetdb182c72016-09-30 12:53:12 -070022
23 "github.com/skia-dev/glog"
borenetdb182c72016-09-30 12:53:12 -070024 "go.skia.org/infra/go/util"
25 "go.skia.org/infra/task_scheduler/go/specs"
26)
27
28const (
Eric Boren8b3f9e62017-04-04 09:06:16 -040029 BUNDLE_RECIPES_NAME = "Housekeeper-PerCommit-BundleRecipes"
30
Kevin Lubick797ef162016-12-15 10:45:08 -050031 DEFAULT_OS = DEFAULT_OS_LINUX
32 DEFAULT_OS_LINUX = "Ubuntu-14.04"
borenetdb182c72016-09-30 12:53:12 -070033
borenetdb182c72016-09-30 12:53:12 -070034 // Name prefix for upload jobs.
35 PREFIX_UPLOAD = "Upload"
36)
37
38var (
39 // "Constants"
40
Eric Boren27225492017-02-01 15:56:55 -050041 // Top-level list of all jobs to run at each commit; loaded from
42 // jobs.json.
43 JOBS []string
44
45 // Mapping of human-friendly Android device names to a pair of {device_type, device_os}.
46 ANDROID_MAPPING map[string][]string
47
48 // General configuration information.
49 CONFIG struct {
Eric Boren965861b2017-02-06 15:38:41 -050050 GsBucketGm string `json:"gs_bucket_gm"`
51 GsBucketNano string `json:"gs_bucket_nano"`
52 NoUpload []string `json:"no_upload"`
53 Pool string `json:"pool"`
borenetdb182c72016-09-30 12:53:12 -070054 }
55
Eric Boren27225492017-02-01 15:56:55 -050056 // Mapping of human-friendly GPU names to PCI IDs.
57 GPU_MAPPING map[string]string
borenetdb182c72016-09-30 12:53:12 -070058
59 // Defines the structure of job names.
60 jobNameSchema *JobNameSchema
Eric Boren27225492017-02-01 15:56:55 -050061
62 // Flags.
Eric Boren1f8be682017-02-07 09:16:30 -050063 androidMapFile = flag.String("android_map", "", "JSON file containing a mapping of human-friendly Android device names to a pair of {device_type, device_os}.")
64 builderNameSchemaFile = flag.String("builder_name_schema", "", "Path to the builder_name_schema.json file. If not specified, uses infra/bots/recipe_modules/builder_name_schema/builder_name_schema.json from this repo.")
65 assetsDir = flag.String("assets_dir", "", "Directory containing assets.")
66 cfgFile = flag.String("cfg_file", "", "JSON file containing general configuration information.")
67 gpuMapFile = flag.String("gpu_map", "", "JSON file containing a mapping of human-friendly GPU names to PCI IDs.")
68 jobsFile = flag.String("jobs", "", "JSON file containing jobs to run.")
borenetdb182c72016-09-30 12:53:12 -070069)
70
Eric Boren27225492017-02-01 15:56:55 -050071// linuxGceDimensions are the Swarming dimensions for Linux GCE
72// instances.
73func linuxGceDimensions() []string {
74 return []string{
75 "cpu:x86-64-avx2",
76 "gpu:none",
77 fmt.Sprintf("os:%s", DEFAULT_OS_LINUX),
78 fmt.Sprintf("pool:%s", CONFIG.Pool),
79 }
80}
81
borenetdb182c72016-09-30 12:53:12 -070082// deriveCompileTaskName returns the name of a compile task based on the given
83// job name.
84func deriveCompileTaskName(jobName string, parts map[string]string) string {
85 if parts["role"] == "Housekeeper" {
86 return "Build-Ubuntu-GCC-x86_64-Release-Shared"
87 } else if parts["role"] == "Test" || parts["role"] == "Perf" {
88 task_os := parts["os"]
89 ec := parts["extra_config"]
Kevin Lubickb03b5ac2016-11-14 13:42:27 -050090 ec = strings.TrimSuffix(ec, "_Skpbench")
Ben Wagner46df2a12017-02-21 19:10:24 -050091 ec = strings.TrimSuffix(ec, "_AbandonGpuContext")
92 ec = strings.TrimSuffix(ec, "_PreAbandonGpuContext")
Ben Wagneradfeaf12017-02-21 19:27:07 -050093 if ec == "Valgrind" {
94 // skia:6267
95 ec = ""
96 }
borenetdb182c72016-09-30 12:53:12 -070097 if task_os == "Android" {
98 if ec == "Vulkan" {
99 ec = "Android_Vulkan"
borenetdb182c72016-09-30 12:53:12 -0700100 }
borenet52383432016-10-17 10:17:53 -0700101 task_os = "Ubuntu"
Kevin Lubickdcd2a902017-03-08 14:01:01 -0500102 } else if task_os == "Chromecast" {
103 task_os = "Ubuntu"
104 ec = "Chromecast"
Kevin Lubickcb6f3982017-04-07 10:04:08 -0400105 } else if strings.Contains(task_os, "ChromeOS") {
Kevin Lubick671cd722017-04-12 10:50:18 -0400106 ec = "Chromebook_ARM_GLES"
Kevin Lubick261ea192017-04-05 07:32:45 -0400107 task_os = "Ubuntu"
borenetdb182c72016-09-30 12:53:12 -0700108 } else if task_os == "iOS" {
109 ec = task_os
110 task_os = "Mac"
111 } else if strings.Contains(task_os, "Win") {
112 task_os = "Win"
Kevin Lubick893c49e2017-01-17 15:15:40 -0500113 } else if strings.Contains(task_os, "Ubuntu") {
114 task_os = "Ubuntu"
borenetdb182c72016-09-30 12:53:12 -0700115 }
Eric Boren50831302016-11-18 13:10:51 -0500116 jobNameMap := map[string]string{
borenetdb182c72016-09-30 12:53:12 -0700117 "role": "Build",
118 "os": task_os,
119 "compiler": parts["compiler"],
120 "target_arch": parts["arch"],
121 "configuration": parts["configuration"],
Eric Boren50831302016-11-18 13:10:51 -0500122 }
123 if ec != "" {
124 jobNameMap["extra_config"] = ec
125 }
126 name, err := jobNameSchema.MakeJobName(jobNameMap)
borenetdb182c72016-09-30 12:53:12 -0700127 if err != nil {
128 glog.Fatal(err)
129 }
130 return name
131 } else {
132 return jobName
133 }
134}
135
136// swarmDimensions generates swarming bot dimensions for the given task.
137func swarmDimensions(parts map[string]string) []string {
borenetdb182c72016-09-30 12:53:12 -0700138 d := map[string]string{
Eric Boren27225492017-02-01 15:56:55 -0500139 "pool": CONFIG.Pool,
borenetdb182c72016-09-30 12:53:12 -0700140 }
141 if os, ok := parts["os"]; ok {
Eric Boren54ff2fc2016-12-02 12:09:10 -0500142 d["os"] = map[string]string{
Kevin Lubick291547d2017-03-21 09:25:34 -0400143 "Android": "Android",
144 "Chromecast": "Android",
Kevin Lubickcb6f3982017-04-07 10:04:08 -0400145 "ChromeOS": "ChromeOS",
Kevin Lubick291547d2017-03-21 09:25:34 -0400146 "Mac": "Mac-10.11",
147 "Ubuntu": DEFAULT_OS_LINUX,
148 "Ubuntu16": "Ubuntu-16.10",
149 "Win": "Windows-2008ServerR2-SP1",
150 "Win10": "Windows-10-14393",
151 "Win2k8": "Windows-2008ServerR2-SP1",
152 "Win8": "Windows-8.1-SP0",
153 "iOS": "iOS-9.3.1",
Eric Boren54ff2fc2016-12-02 12:09:10 -0500154 }[os]
Ben Wagner73557372016-12-29 16:27:03 -0500155 // Chrome Golo has a different Windows image.
156 if parts["model"] == "Golo" && os == "Win10" {
157 d["os"] = "Windows-10-10586"
Ben Wagner17f811b2016-12-22 08:40:14 -0500158 }
borenetdb182c72016-09-30 12:53:12 -0700159 } else {
160 d["os"] = DEFAULT_OS
161 }
borenetdb182c72016-09-30 12:53:12 -0700162 if parts["role"] == "Test" || parts["role"] == "Perf" {
Kevin Lubick291547d2017-03-21 09:25:34 -0400163 if strings.Contains(parts["os"], "Android") || strings.Contains(parts["os"], "Chromecast") {
borenetdb182c72016-09-30 12:53:12 -0700164 // For Android, the device type is a better dimension
165 // than CPU or GPU.
Eric Boren27225492017-02-01 15:56:55 -0500166 deviceInfo, ok := ANDROID_MAPPING[parts["model"]]
167 if !ok {
168 glog.Fatalf("Entry %q not found in Android mapping: %v", parts["model"], ANDROID_MAPPING)
169 }
Eric Boren4b254b92016-11-08 12:55:32 -0500170 d["device_type"] = deviceInfo[0]
171 d["device_os"] = deviceInfo[1]
borenetdb182c72016-09-30 12:53:12 -0700172 } else if strings.Contains(parts["os"], "iOS") {
173 d["device"] = map[string]string{
Eric Boren792079cf2016-11-09 14:03:20 -0500174 "iPadMini4": "iPad5,1",
borenetdb182c72016-09-30 12:53:12 -0700175 }[parts["model"]]
borenetdb182c72016-09-30 12:53:12 -0700176 } else if parts["cpu_or_gpu"] == "CPU" {
177 d["gpu"] = "none"
178 d["cpu"] = map[string]string{
179 "AVX": "x86-64",
180 "AVX2": "x86-64-avx2",
181 "SSE4": "x86-64",
182 }[parts["cpu_or_gpu_value"]]
183 if strings.Contains(parts["os"], "Win") && parts["cpu_or_gpu_value"] == "AVX2" {
184 // AVX2 is not correctly detected on Windows. Fall back on other
185 // dimensions to ensure that we correctly target machines which we know
186 // have AVX2 support.
Eric Boren085bf7c2017-04-06 17:32:44 +0000187 d["cpu"] = "x86-64"
borenetdb182c72016-09-30 12:53:12 -0700188 d["os"] = "Windows-2008ServerR2-SP1"
189 }
190 } else {
Eric Boren27225492017-02-01 15:56:55 -0500191 gpu, ok := GPU_MAPPING[parts["cpu_or_gpu_value"]]
192 if !ok {
193 glog.Fatalf("Entry %q not found in GPU mapping: %v", parts["cpu_or_gpu_value"], GPU_MAPPING)
194 }
195 d["gpu"] = gpu
Ben Wagner08435892017-02-18 23:28:26 -0500196
197 // Hack: Specify machine_type dimension for NUCs and ShuttleCs. We
198 // temporarily have two types of machines with a GTX960. The only way to
199 // distinguish these bots is by machine_type.
200 machine_type, ok := map[string]string{
201 "NUC6i7KYK": "n1-highcpu-8",
202 "ShuttleC": "n1-standard-8",
203 }[parts["model"]]
204 if ok {
205 d["machine_type"] = machine_type
206 }
borenetdb182c72016-09-30 12:53:12 -0700207 }
208 } else {
209 d["gpu"] = "none"
Kevin Lubick4610a9b2017-03-22 15:54:54 -0400210 if d["os"] == DEFAULT_OS_LINUX {
211 return linuxGceDimensions()
212 }
borenetdb182c72016-09-30 12:53:12 -0700213 }
Kevin Lubick4610a9b2017-03-22 15:54:54 -0400214
borenetdb182c72016-09-30 12:53:12 -0700215 rv := make([]string, 0, len(d))
216 for k, v := range d {
217 rv = append(rv, fmt.Sprintf("%s:%s", k, v))
218 }
219 sort.Strings(rv)
220 return rv
221}
222
Eric Boren8b3f9e62017-04-04 09:06:16 -0400223// bundleRecipes generates the task to bundle and isolate the recipes.
224func bundleRecipes(b *specs.TasksCfgBuilder) string {
225 b.MustAddTask(BUNDLE_RECIPES_NAME, &specs.TaskSpec{
226 CipdPackages: []*specs.CipdPackage{},
227 Dimensions: linuxGceDimensions(),
228 ExtraArgs: []string{
229 "--workdir", "../../..", "bundle_recipes",
230 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
231 fmt.Sprintf("buildername=%s", BUNDLE_RECIPES_NAME),
Eric Boren8b3f9e62017-04-04 09:06:16 -0400232 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
233 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
234 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
235 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
236 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
237 },
238 Isolate: "bundle_recipes.isolate",
239 Priority: 0.95,
240 })
241 return BUNDLE_RECIPES_NAME
242}
243
Eric Boren23a6ec62017-04-07 08:31:22 -0400244// useBundledRecipes returns true iff the given bot should use bundled recipes
245// instead of syncing recipe DEPS itself.
246func useBundledRecipes(parts map[string]string) bool {
247 // Use bundled recipes for all test/perf tasks.
248 return true
249}
250
borenetdb182c72016-09-30 12:53:12 -0700251// compile generates a compile task. Returns the name of the last task in the
252// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700253func compile(b *specs.TasksCfgBuilder, name string, parts map[string]string) string {
borenetdb182c72016-09-30 12:53:12 -0700254 // Collect the necessary CIPD packages.
255 pkgs := []*specs.CipdPackage{}
256
257 // Android bots require a toolchain.
258 if strings.Contains(name, "Android") {
borenetdb182c72016-09-30 12:53:12 -0700259 if strings.Contains(name, "Mac") {
boreneted20a702016-10-20 11:04:31 -0700260 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("android_ndk_darwin"))
Mike Klein86c2c0f2016-11-02 13:13:16 -0400261 } else if strings.Contains(name, "Win") {
Mike Kleine9215f02016-11-02 15:44:26 -0400262 pkg := b.MustGetCipdPackageFromAsset("android_ndk_windows")
263 pkg.Path = "n"
264 pkgs = append(pkgs, pkg)
borenetdb182c72016-09-30 12:53:12 -0700265 } else {
boreneted20a702016-10-20 11:04:31 -0700266 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("android_ndk_linux"))
borenetdb182c72016-09-30 12:53:12 -0700267 }
Kevin Lubickdcd2a902017-03-08 14:01:01 -0500268 } else if strings.Contains(name, "Chromecast") {
269 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("cast_toolchain"))
Kevin Lubick261ea192017-04-05 07:32:45 -0400270 } else if strings.Contains(name, "Chromebook") {
271 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("clang_linux"))
272 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("armhf_sysroot"))
Kevin Lubick671cd722017-04-12 10:50:18 -0400273 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("chromebook_arm_gles"))
Kevin Lubick9c7dcac2017-01-18 09:24:56 -0500274 } else if strings.Contains(name, "Ubuntu") {
275 if strings.Contains(name, "Clang") {
276 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("clang_linux"))
277 }
278 if strings.Contains(name, "Vulkan") {
279 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("linux_vulkan_sdk"))
280 }
Mike Klein27dcee12016-11-09 16:31:42 -0500281 } else if strings.Contains(name, "Win") {
boreneted20a702016-10-20 11:04:31 -0700282 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("win_toolchain"))
borenetdb182c72016-09-30 12:53:12 -0700283 if strings.Contains(name, "Vulkan") {
boreneted20a702016-10-20 11:04:31 -0700284 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("win_vulkan_sdk"))
borenetdb182c72016-09-30 12:53:12 -0700285 }
286 }
287
Stephan Altmueller5f3b9402017-03-20 13:38:45 -0400288 // TODO(stephana): Remove this once all Mac machines are on the same
289 // OS version again. Move the call to swarmDimensions back to the
290 // creation of the TaskSpec struct below.
291 dimensions := swarmDimensions(parts)
292 if strings.Contains(name, "Mac") {
293 for idx, dim := range dimensions {
294 if strings.HasPrefix(dim, "os") {
295 dimensions[idx] = "os:Mac-10.12"
296 break
297 }
298 }
299 }
300
borenetdb182c72016-09-30 12:53:12 -0700301 // Add the task.
boreneted20a702016-10-20 11:04:31 -0700302 b.MustAddTask(name, &specs.TaskSpec{
borenetdb182c72016-09-30 12:53:12 -0700303 CipdPackages: pkgs,
Stephan Altmueller5f3b9402017-03-20 13:38:45 -0400304 Dimensions: dimensions,
borenetdb182c72016-09-30 12:53:12 -0700305 ExtraArgs: []string{
Eric Boren768f52f2017-04-10 08:14:33 -0400306 "--workdir", "../../..", "compile",
skia.buildbots2478c732016-11-04 14:37:26 -0400307 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700308 fmt.Sprintf("buildername=%s", name),
borenetdb182c72016-09-30 12:53:12 -0700309 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
310 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700311 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400312 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
313 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
borenetdb182c72016-09-30 12:53:12 -0700314 },
315 Isolate: "compile_skia.isolate",
316 Priority: 0.8,
boreneted20a702016-10-20 11:04:31 -0700317 })
Eric Boren8615fe52016-12-12 14:30:12 -0500318 // All compile tasks are runnable as their own Job. Assert that the Job
319 // is listed in JOBS.
320 if !util.In(name, JOBS) {
321 glog.Fatalf("Job %q is missing from the JOBS list!", name)
322 }
borenetdb182c72016-09-30 12:53:12 -0700323 return name
324}
325
326// recreateSKPs generates a RecreateSKPs task. Returns the name of the last
327// task in the generated chain of tasks, which the Job should add as a
328// dependency.
boreneted20a702016-10-20 11:04:31 -0700329func recreateSKPs(b *specs.TasksCfgBuilder, name string) string {
Eric Boren4b254b92016-11-08 12:55:32 -0500330 b.MustAddTask(name, &specs.TaskSpec{
Eric Borenf5a90e82016-11-15 15:18:20 -0500331 CipdPackages: []*specs.CipdPackage{},
Eric Boren27225492017-02-01 15:56:55 -0500332 Dimensions: linuxGceDimensions(),
Eric Borenf5a90e82016-11-15 15:18:20 -0500333 ExecutionTimeout: 4 * time.Hour,
Eric Boren4b254b92016-11-08 12:55:32 -0500334 ExtraArgs: []string{
Eric Boren768f52f2017-04-10 08:14:33 -0400335 "--workdir", "../../..", "recreate_skps",
Eric Boren4b254b92016-11-08 12:55:32 -0500336 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
337 fmt.Sprintf("buildername=%s", name),
Eric Boren4b254b92016-11-08 12:55:32 -0500338 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
339 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
340 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
341 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
342 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
343 },
Eric Borenf5a90e82016-11-15 15:18:20 -0500344 IoTimeout: 40 * time.Minute,
345 Isolate: "compile_skia.isolate",
346 Priority: 0.8,
Eric Boren4b254b92016-11-08 12:55:32 -0500347 })
borenetdb182c72016-09-30 12:53:12 -0700348 return name
349}
350
351// ctSKPs generates a CT SKPs task. Returns the name of the last task in the
352// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700353func ctSKPs(b *specs.TasksCfgBuilder, name string) string {
Eric Boren4b254b92016-11-08 12:55:32 -0500354 b.MustAddTask(name, &specs.TaskSpec{
355 CipdPackages: []*specs.CipdPackage{},
356 Dimensions: []string{"pool:SkiaCT"},
357 ExecutionTimeout: 24 * time.Hour,
358 ExtraArgs: []string{
Eric Boren768f52f2017-04-10 08:14:33 -0400359 "--workdir", "../../..", "ct_skps",
Eric Boren4b254b92016-11-08 12:55:32 -0500360 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
361 fmt.Sprintf("buildername=%s", name),
Eric Boren4b254b92016-11-08 12:55:32 -0500362 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
363 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
364 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
365 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
366 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
367 },
368 IoTimeout: time.Hour,
369 Isolate: "ct_skps_skia.isolate",
370 Priority: 0.8,
371 })
borenetdb182c72016-09-30 12:53:12 -0700372 return name
373}
374
375// housekeeper generates a Housekeeper task. Returns the name of the last task
376// in the generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700377func housekeeper(b *specs.TasksCfgBuilder, name, compileTaskName string) string {
Eric Boren4b254b92016-11-08 12:55:32 -0500378 b.MustAddTask(name, &specs.TaskSpec{
Eric Boren22f5ef72016-12-02 11:01:33 -0500379 CipdPackages: []*specs.CipdPackage{b.MustGetCipdPackageFromAsset("go")},
Eric Boren4b254b92016-11-08 12:55:32 -0500380 Dependencies: []string{compileTaskName},
Eric Boren27225492017-02-01 15:56:55 -0500381 Dimensions: linuxGceDimensions(),
Eric Boren4b254b92016-11-08 12:55:32 -0500382 ExtraArgs: []string{
Eric Boren768f52f2017-04-10 08:14:33 -0400383 "--workdir", "../../..", "housekeeper",
Eric Boren4b254b92016-11-08 12:55:32 -0500384 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
385 fmt.Sprintf("buildername=%s", name),
Eric Boren4b254b92016-11-08 12:55:32 -0500386 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
387 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
388 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
389 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
390 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
391 },
392 Isolate: "housekeeper_skia.isolate",
393 Priority: 0.8,
394 })
borenetdb182c72016-09-30 12:53:12 -0700395 return name
396}
397
borenet2dbbfa52016-10-14 06:32:09 -0700398// infra generates an infra_tests task. Returns the name of the last task in the
399// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700400func infra(b *specs.TasksCfgBuilder, name string) string {
401 b.MustAddTask(name, &specs.TaskSpec{
borenet2dbbfa52016-10-14 06:32:09 -0700402 CipdPackages: []*specs.CipdPackage{},
Eric Boren27225492017-02-01 15:56:55 -0500403 Dimensions: linuxGceDimensions(),
borenet2dbbfa52016-10-14 06:32:09 -0700404 ExtraArgs: []string{
Eric Boren768f52f2017-04-10 08:14:33 -0400405 "--workdir", "../../..", "infra",
skia.buildbots2478c732016-11-04 14:37:26 -0400406 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenet2dbbfa52016-10-14 06:32:09 -0700407 fmt.Sprintf("buildername=%s", name),
borenet2dbbfa52016-10-14 06:32:09 -0700408 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
409 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
410 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400411 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
412 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
borenet2dbbfa52016-10-14 06:32:09 -0700413 },
414 Isolate: "infra_skia.isolate",
415 Priority: 0.8,
boreneted20a702016-10-20 11:04:31 -0700416 })
borenet2dbbfa52016-10-14 06:32:09 -0700417 return name
418}
419
borenetdb182c72016-09-30 12:53:12 -0700420// doUpload indicates whether the given Job should upload its results.
421func doUpload(name string) bool {
Eric Boren27225492017-02-01 15:56:55 -0500422 for _, s := range CONFIG.NoUpload {
423 m, err := regexp.MatchString(s, name)
424 if err != nil {
425 glog.Fatal(err)
426 }
427 if m {
borenetdb182c72016-09-30 12:53:12 -0700428 return false
429 }
430 }
431 return true
432}
433
434// test generates a Test task. Returns the name of the last task in the
435// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700436func test(b *specs.TasksCfgBuilder, name string, parts map[string]string, compileTaskName string, pkgs []*specs.CipdPackage) string {
Eric Boren4b254b92016-11-08 12:55:32 -0500437 s := &specs.TaskSpec{
Eric Boren1f2f64b2016-11-09 18:35:15 -0500438 CipdPackages: pkgs,
439 Dependencies: []string{compileTaskName},
440 Dimensions: swarmDimensions(parts),
441 ExecutionTimeout: 4 * time.Hour,
442 Expiration: 20 * time.Hour,
borenetdb182c72016-09-30 12:53:12 -0700443 ExtraArgs: []string{
Eric Boren768f52f2017-04-10 08:14:33 -0400444 "--workdir", "../../..", "test",
skia.buildbots2478c732016-11-04 14:37:26 -0400445 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700446 fmt.Sprintf("buildername=%s", name),
borenetdb182c72016-09-30 12:53:12 -0700447 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
448 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700449 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400450 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
451 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
borenetdb182c72016-09-30 12:53:12 -0700452 },
Eric Boren5d9f3bf2017-02-22 08:36:03 -0500453 IoTimeout: 40 * time.Minute,
454 Isolate: "test_skia.isolate",
455 MaxAttempts: 1,
456 Priority: 0.8,
Eric Boren4b254b92016-11-08 12:55:32 -0500457 }
Eric Boren23a6ec62017-04-07 08:31:22 -0400458 if useBundledRecipes(parts) {
Eric Boren8b3f9e62017-04-04 09:06:16 -0400459 s.Dependencies = append(s.Dependencies, BUNDLE_RECIPES_NAME)
Eric Boren23a6ec62017-04-07 08:31:22 -0400460 if strings.Contains(parts["os"], "Win") {
461 s.Isolate = "test_skia_bundled_win.isolate"
462 } else {
463 s.Isolate = "test_skia_bundled_unix.isolate"
464 }
Eric Boren8b3f9e62017-04-04 09:06:16 -0400465 }
Eric Boren4b254b92016-11-08 12:55:32 -0500466 if strings.Contains(parts["extra_config"], "Valgrind") {
467 s.ExecutionTimeout = 9 * time.Hour
468 s.Expiration = 48 * time.Hour
469 s.IoTimeout = time.Hour
470 } else if strings.Contains(parts["extra_config"], "MSAN") {
471 s.ExecutionTimeout = 9 * time.Hour
472 }
473 b.MustAddTask(name, s)
474
borenetdb182c72016-09-30 12:53:12 -0700475 // Upload results if necessary.
476 if doUpload(name) {
477 uploadName := fmt.Sprintf("%s%s%s", PREFIX_UPLOAD, jobNameSchema.Sep, name)
boreneted20a702016-10-20 11:04:31 -0700478 b.MustAddTask(uploadName, &specs.TaskSpec{
borenetdb182c72016-09-30 12:53:12 -0700479 Dependencies: []string{name},
Eric Boren27225492017-02-01 15:56:55 -0500480 Dimensions: linuxGceDimensions(),
borenetdb182c72016-09-30 12:53:12 -0700481 ExtraArgs: []string{
482 "--workdir", "../../..", "upload_dm_results",
skia.buildbots2478c732016-11-04 14:37:26 -0400483 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700484 fmt.Sprintf("buildername=%s", name),
borenetdb182c72016-09-30 12:53:12 -0700485 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
486 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700487 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400488 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
489 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
Eric Boren965861b2017-02-06 15:38:41 -0500490 fmt.Sprintf("gs_bucket=%s", CONFIG.GsBucketGm),
borenetdb182c72016-09-30 12:53:12 -0700491 },
492 Isolate: "upload_dm_results.isolate",
493 Priority: 0.8,
boreneted20a702016-10-20 11:04:31 -0700494 })
borenetdb182c72016-09-30 12:53:12 -0700495 return uploadName
496 }
497 return name
498}
499
500// perf generates a Perf task. Returns the name of the last task in the
501// generated chain of tasks, which the Job should add as a dependency.
boreneted20a702016-10-20 11:04:31 -0700502func perf(b *specs.TasksCfgBuilder, name string, parts map[string]string, compileTaskName string, pkgs []*specs.CipdPackage) string {
Eric Boren768f52f2017-04-10 08:14:33 -0400503 recipe := "perf"
Kevin Lubickb03b5ac2016-11-14 13:42:27 -0500504 isolate := "perf_skia.isolate"
505 if strings.Contains(parts["extra_config"], "Skpbench") {
Eric Boren768f52f2017-04-10 08:14:33 -0400506 recipe = "skpbench"
Kevin Lubickb03b5ac2016-11-14 13:42:27 -0500507 isolate = "skpbench_skia.isolate"
Eric Boren23a6ec62017-04-07 08:31:22 -0400508 if useBundledRecipes(parts) {
509 if strings.Contains(parts["os"], "Win") {
510 isolate = "skpbench_skia_bundled_win.isolate"
511 } else {
512 isolate = "skpbench_skia_bundled_unix.isolate"
513 }
Eric Boren8b3f9e62017-04-04 09:06:16 -0400514 }
Eric Boren23a6ec62017-04-07 08:31:22 -0400515 } else if useBundledRecipes(parts) {
516 if strings.Contains(parts["os"], "Win") {
517 isolate = "perf_skia_bundled_win.isolate"
518 } else {
519 isolate = "perf_skia_bundled_unix.isolate"
520 }
Kevin Lubickb03b5ac2016-11-14 13:42:27 -0500521 }
Eric Boren4b254b92016-11-08 12:55:32 -0500522 s := &specs.TaskSpec{
Eric Boren1f2f64b2016-11-09 18:35:15 -0500523 CipdPackages: pkgs,
524 Dependencies: []string{compileTaskName},
525 Dimensions: swarmDimensions(parts),
526 ExecutionTimeout: 4 * time.Hour,
527 Expiration: 20 * time.Hour,
borenetdb182c72016-09-30 12:53:12 -0700528 ExtraArgs: []string{
Kevin Lubickb03b5ac2016-11-14 13:42:27 -0500529 "--workdir", "../../..", recipe,
skia.buildbots2478c732016-11-04 14:37:26 -0400530 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700531 fmt.Sprintf("buildername=%s", name),
borenetdb182c72016-09-30 12:53:12 -0700532 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
533 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700534 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400535 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
536 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
borenetdb182c72016-09-30 12:53:12 -0700537 },
Eric Boren5d9f3bf2017-02-22 08:36:03 -0500538 IoTimeout: 40 * time.Minute,
539 Isolate: isolate,
540 MaxAttempts: 1,
541 Priority: 0.8,
Eric Boren4b254b92016-11-08 12:55:32 -0500542 }
Eric Boren23a6ec62017-04-07 08:31:22 -0400543 if useBundledRecipes(parts) {
Eric Boren8b3f9e62017-04-04 09:06:16 -0400544 s.Dependencies = append(s.Dependencies, BUNDLE_RECIPES_NAME)
545 }
Eric Boren4b254b92016-11-08 12:55:32 -0500546 if strings.Contains(parts["extra_config"], "Valgrind") {
547 s.ExecutionTimeout = 9 * time.Hour
548 s.Expiration = 48 * time.Hour
549 s.IoTimeout = time.Hour
550 } else if strings.Contains(parts["extra_config"], "MSAN") {
551 s.ExecutionTimeout = 9 * time.Hour
552 }
553 b.MustAddTask(name, s)
554
borenetdb182c72016-09-30 12:53:12 -0700555 // Upload results if necessary.
556 if strings.Contains(name, "Release") && doUpload(name) {
557 uploadName := fmt.Sprintf("%s%s%s", PREFIX_UPLOAD, jobNameSchema.Sep, name)
boreneted20a702016-10-20 11:04:31 -0700558 b.MustAddTask(uploadName, &specs.TaskSpec{
borenetdb182c72016-09-30 12:53:12 -0700559 Dependencies: []string{name},
Eric Boren27225492017-02-01 15:56:55 -0500560 Dimensions: linuxGceDimensions(),
borenetdb182c72016-09-30 12:53:12 -0700561 ExtraArgs: []string{
562 "--workdir", "../../..", "upload_nano_results",
skia.buildbots2478c732016-11-04 14:37:26 -0400563 fmt.Sprintf("repository=%s", specs.PLACEHOLDER_REPO),
borenetdb182c72016-09-30 12:53:12 -0700564 fmt.Sprintf("buildername=%s", name),
borenetdb182c72016-09-30 12:53:12 -0700565 fmt.Sprintf("swarm_out_dir=%s", specs.PLACEHOLDER_ISOLATED_OUTDIR),
566 fmt.Sprintf("revision=%s", specs.PLACEHOLDER_REVISION),
borenet98b2e7a2016-10-13 06:23:45 -0700567 fmt.Sprintf("patch_storage=%s", specs.PLACEHOLDER_PATCH_STORAGE),
skia.buildbots2478c732016-11-04 14:37:26 -0400568 fmt.Sprintf("patch_issue=%s", specs.PLACEHOLDER_ISSUE),
569 fmt.Sprintf("patch_set=%s", specs.PLACEHOLDER_PATCHSET),
Eric Boren965861b2017-02-06 15:38:41 -0500570 fmt.Sprintf("gs_bucket=%s", CONFIG.GsBucketNano),
borenetdb182c72016-09-30 12:53:12 -0700571 },
572 Isolate: "upload_nano_results.isolate",
573 Priority: 0.8,
boreneted20a702016-10-20 11:04:31 -0700574 })
borenetdb182c72016-09-30 12:53:12 -0700575 return uploadName
576 }
577 return name
578}
579
580// process generates tasks and jobs for the given job name.
boreneted20a702016-10-20 11:04:31 -0700581func process(b *specs.TasksCfgBuilder, name string) {
borenetdb182c72016-09-30 12:53:12 -0700582 deps := []string{}
583
Eric Boren8b3f9e62017-04-04 09:06:16 -0400584 // Bundle Recipes.
585 if name == BUNDLE_RECIPES_NAME {
586 deps = append(deps, bundleRecipes(b))
587 }
588
borenetdb182c72016-09-30 12:53:12 -0700589 parts, err := jobNameSchema.ParseJobName(name)
590 if err != nil {
591 glog.Fatal(err)
592 }
593
594 // RecreateSKPs.
595 if strings.Contains(name, "RecreateSKPs") {
boreneted20a702016-10-20 11:04:31 -0700596 deps = append(deps, recreateSKPs(b, name))
borenetdb182c72016-09-30 12:53:12 -0700597 }
598
599 // CT bots.
600 if strings.Contains(name, "-CT_") {
boreneted20a702016-10-20 11:04:31 -0700601 deps = append(deps, ctSKPs(b, name))
borenetdb182c72016-09-30 12:53:12 -0700602 }
603
borenet2dbbfa52016-10-14 06:32:09 -0700604 // Infra tests.
605 if name == "Housekeeper-PerCommit-InfraTests" {
boreneted20a702016-10-20 11:04:31 -0700606 deps = append(deps, infra(b, name))
borenet2dbbfa52016-10-14 06:32:09 -0700607 }
608
borenetdb182c72016-09-30 12:53:12 -0700609 // Compile bots.
610 if parts["role"] == "Build" {
boreneted20a702016-10-20 11:04:31 -0700611 deps = append(deps, compile(b, name, parts))
borenetdb182c72016-09-30 12:53:12 -0700612 }
613
Eric Borenf5a90e82016-11-15 15:18:20 -0500614 // Most remaining bots need a compile task.
borenetdb182c72016-09-30 12:53:12 -0700615 compileTaskName := deriveCompileTaskName(name, parts)
borenet52383432016-10-17 10:17:53 -0700616 compileTaskParts, err := jobNameSchema.ParseJobName(compileTaskName)
617 if err != nil {
618 glog.Fatal(err)
619 }
Eric Boren628e78b2016-11-17 11:33:27 -0500620 // These bots do not need a compile task.
Eric Borenf5a90e82016-11-15 15:18:20 -0500621 if parts["role"] != "Build" &&
Eric Borenb8ab7f72017-04-10 11:00:09 -0400622 name != "Housekeeper-PerCommit-BundleRecipes" &&
Eric Borenf5a90e82016-11-15 15:18:20 -0500623 name != "Housekeeper-PerCommit-InfraTests" &&
Eric Boren71b762f2016-11-30 14:05:16 -0500624 !strings.Contains(name, "RecreateSKPs") &&
625 !strings.Contains(name, "-CT_") {
boreneted20a702016-10-20 11:04:31 -0700626 compile(b, compileTaskName, compileTaskParts)
borenet52383432016-10-17 10:17:53 -0700627 }
borenetdb182c72016-09-30 12:53:12 -0700628
629 // Housekeeper.
Eric Boren22f5ef72016-12-02 11:01:33 -0500630 if name == "Housekeeper-PerCommit" {
boreneted20a702016-10-20 11:04:31 -0700631 deps = append(deps, housekeeper(b, name, compileTaskName))
borenetdb182c72016-09-30 12:53:12 -0700632 }
633
634 // Common assets needed by the remaining bots.
635 pkgs := []*specs.CipdPackage{
boreneted20a702016-10-20 11:04:31 -0700636 b.MustGetCipdPackageFromAsset("skimage"),
637 b.MustGetCipdPackageFromAsset("skp"),
638 b.MustGetCipdPackageFromAsset("svg"),
borenetdb182c72016-09-30 12:53:12 -0700639 }
Kevin Lubick291547d2017-03-21 09:25:34 -0400640 if strings.Contains(name, "Chromecast") {
641 // Chromecasts don't have enough disk space to fit all of the content,
642 // so we do a subset of the skps.
643 pkgs = []*specs.CipdPackage{
644 b.MustGetCipdPackageFromAsset("skp"),
645 }
646 }
Eric Boren4b254b92016-11-08 12:55:32 -0500647 if strings.Contains(name, "Ubuntu") && strings.Contains(name, "SAN") {
648 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("clang_linux"))
649 }
Kevin Lubick35115eb2017-02-17 10:25:34 -0500650 if strings.Contains(name, "Ubuntu16") {
651 if strings.Contains(name, "Vulkan") {
652 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("linux_vulkan_sdk"))
653 }
Kevin Lubick0a51b482017-02-06 12:45:29 -0500654 if strings.Contains(name, "Release") {
655 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("linux_vulkan_intel_driver_release"))
656 } else {
657 pkgs = append(pkgs, b.MustGetCipdPackageFromAsset("linux_vulkan_intel_driver_debug"))
658 }
659 }
Kevin Lubickb03b5ac2016-11-14 13:42:27 -0500660 // Skpbench only needs skps
661 if strings.Contains(name, "Skpbench") {
662 pkgs = []*specs.CipdPackage{
663 b.MustGetCipdPackageFromAsset("skp"),
664 }
665 }
borenetdb182c72016-09-30 12:53:12 -0700666
667 // Test bots.
Eric Boren71b762f2016-11-30 14:05:16 -0500668 if parts["role"] == "Test" && !strings.Contains(name, "-CT_") {
boreneted20a702016-10-20 11:04:31 -0700669 deps = append(deps, test(b, name, parts, compileTaskName, pkgs))
borenetdb182c72016-09-30 12:53:12 -0700670 }
671
672 // Perf bots.
Eric Boren71b762f2016-11-30 14:05:16 -0500673 if parts["role"] == "Perf" && !strings.Contains(name, "-CT_") {
boreneted20a702016-10-20 11:04:31 -0700674 deps = append(deps, perf(b, name, parts, compileTaskName, pkgs))
borenetdb182c72016-09-30 12:53:12 -0700675 }
676
677 // Add the Job spec.
Eric Borenf5a90e82016-11-15 15:18:20 -0500678 j := &specs.JobSpec{
borenetdb182c72016-09-30 12:53:12 -0700679 Priority: 0.8,
680 TaskSpecs: deps,
Eric Borenf5a90e82016-11-15 15:18:20 -0500681 }
682 if name == "Housekeeper-Nightly-RecreateSKPs_Canary" {
683 j.Trigger = "nightly"
684 }
685 if name == "Housekeeper-Weekly-RecreateSKPs" {
686 j.Trigger = "weekly"
687 }
Eric Boren71b762f2016-11-30 14:05:16 -0500688 if name == "Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Debug-CT_DM_1m_SKPs" {
689 j.Trigger = "weekly"
690 }
Eric Boren8615fe52016-12-12 14:30:12 -0500691 b.MustAddJob(name, j)
borenetdb182c72016-09-30 12:53:12 -0700692}
693
Eric Boren27225492017-02-01 15:56:55 -0500694func loadJson(flag *string, defaultFlag string, val interface{}) {
695 if *flag == "" {
696 *flag = defaultFlag
697 }
698 b, err := ioutil.ReadFile(*flag)
699 if err != nil {
700 glog.Fatal(err)
701 }
702 if err := json.Unmarshal(b, val); err != nil {
703 glog.Fatal(err)
704 }
705}
706
borenetdb182c72016-09-30 12:53:12 -0700707// Regenerate the tasks.json file.
708func main() {
boreneted20a702016-10-20 11:04:31 -0700709 b := specs.MustNewTasksCfgBuilder()
Eric Boren27225492017-02-01 15:56:55 -0500710 b.SetAssetsDir(*assetsDir)
711 infraBots := path.Join(b.CheckoutRoot(), "infra", "bots")
712
713 // Load the jobs from a JSON file.
714 loadJson(jobsFile, path.Join(infraBots, "jobs.json"), &JOBS)
715
716 // Load the GPU mapping from a JSON file.
717 loadJson(gpuMapFile, path.Join(infraBots, "gpu_map.json"), &GPU_MAPPING)
718
719 // Load the Android device mapping from a JSON file.
720 loadJson(androidMapFile, path.Join(infraBots, "android_map.json"), &ANDROID_MAPPING)
721
722 // Load general config information from a JSON file.
723 loadJson(cfgFile, path.Join(infraBots, "cfg.json"), &CONFIG)
724
borenetdb182c72016-09-30 12:53:12 -0700725 // Create the JobNameSchema.
Eric Boren1f8be682017-02-07 09:16:30 -0500726 if *builderNameSchemaFile == "" {
727 *builderNameSchemaFile = path.Join(b.CheckoutRoot(), "infra", "bots", "recipe_modules", "builder_name_schema", "builder_name_schema.json")
728 }
729 schema, err := NewJobNameSchema(*builderNameSchemaFile)
borenetdb182c72016-09-30 12:53:12 -0700730 if err != nil {
731 glog.Fatal(err)
732 }
733 jobNameSchema = schema
734
borenetdb182c72016-09-30 12:53:12 -0700735 // Create Tasks and Jobs.
boreneted20a702016-10-20 11:04:31 -0700736 for _, name := range JOBS {
737 process(b, name)
borenetdb182c72016-09-30 12:53:12 -0700738 }
739
boreneted20a702016-10-20 11:04:31 -0700740 b.MustFinish()
borenetdb182c72016-09-30 12:53:12 -0700741}
742
743// TODO(borenet): The below really belongs in its own file, probably next to the
744// builder_name_schema.json file.
745
746// JobNameSchema is a struct used for (de)constructing Job names in a
747// predictable format.
748type JobNameSchema struct {
749 Schema map[string][]string `json:"builder_name_schema"`
750 Sep string `json:"builder_name_sep"`
751}
752
753// NewJobNameSchema returns a JobNameSchema instance based on the given JSON
754// file.
755func NewJobNameSchema(jsonFile string) (*JobNameSchema, error) {
756 var rv JobNameSchema
757 f, err := os.Open(jsonFile)
758 if err != nil {
759 return nil, err
760 }
761 defer util.Close(f)
762 if err := json.NewDecoder(f).Decode(&rv); err != nil {
763 return nil, err
764 }
765 return &rv, nil
766}
767
768// ParseJobName splits the given Job name into its component parts, according
769// to the schema.
770func (s *JobNameSchema) ParseJobName(n string) (map[string]string, error) {
771 split := strings.Split(n, s.Sep)
772 if len(split) < 2 {
773 return nil, fmt.Errorf("Invalid job name: %q", n)
774 }
775 role := split[0]
776 split = split[1:]
777 keys, ok := s.Schema[role]
778 if !ok {
779 return nil, fmt.Errorf("Invalid job name; %q is not a valid role.", role)
780 }
781 extraConfig := ""
782 if len(split) == len(keys)+1 {
783 extraConfig = split[len(split)-1]
784 split = split[:len(split)-1]
785 }
786 if len(split) != len(keys) {
787 return nil, fmt.Errorf("Invalid job name; %q has incorrect number of parts.", n)
788 }
789 rv := make(map[string]string, len(keys)+2)
790 rv["role"] = role
791 if extraConfig != "" {
792 rv["extra_config"] = extraConfig
793 }
794 for i, k := range keys {
795 rv[k] = split[i]
796 }
797 return rv, nil
798}
799
800// MakeJobName assembles the given parts of a Job name, according to the schema.
801func (s *JobNameSchema) MakeJobName(parts map[string]string) (string, error) {
802 role, ok := parts["role"]
803 if !ok {
804 return "", fmt.Errorf("Invalid job parts; jobs must have a role.")
805 }
806 keys, ok := s.Schema[role]
807 if !ok {
808 return "", fmt.Errorf("Invalid job parts; unknown role %q", role)
809 }
810 rvParts := make([]string, 0, len(parts))
811 rvParts = append(rvParts, role)
812 for _, k := range keys {
813 v, ok := parts[k]
814 if !ok {
815 return "", fmt.Errorf("Invalid job parts; missing %q", k)
816 }
817 rvParts = append(rvParts, v)
818 }
819 if _, ok := parts["extra_config"]; ok {
820 rvParts = append(rvParts, parts["extra_config"])
821 }
822 return strings.Join(rvParts, s.Sep), nil
823}