[infra] Use Xcode from CIPD.

Change-Id: I0ae2869accd22c57e06460cb56f5d7cc116d9782
Reviewed-on: https://skia-review.googlesource.com/146120
Auto-Submit: Ben Wagner <benjaminwagner@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Eric Boren <borenet@google.com>
Commit-Queue: Ben Wagner <benjaminwagner@google.com>
diff --git a/infra/bots/bot.py b/infra/bots/bot.py
index e48cec8..eb9a7b4 100644
--- a/infra/bots/bot.py
+++ b/infra/bots/bot.py
@@ -17,8 +17,21 @@
                                                cwd=os.getcwd())
 
 if 'darwin' in sys.platform:
-  # TODO(dogben): Figure out how to get Xcode from CIPD.
-  call('sudo xcode-select -switch /Applications/Xcode9.2.app')
+  # Get Xcode from CIPD using mac_toolchain tool.
+  mac_toolchain = os.path.join(os.getcwd(), sys.argv[3])
+  xcode_app_path = os.path.join(os.getcwd(), sys.argv[4])
+  # See mapping of Xcode version to Xcode build version here:
+  # https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/slave/recipe_modules/ios/api.py#37
+  XCODE_BUILD_VERSION = '9c40b'
+  call(('{mac_toolchain}/mac_toolchain install '
+        '-kind mac '
+        '-xcode-version {xcode_build_version} '
+        '-output-dir {xcode_app_path}').format(
+            mac_toolchain=mac_toolchain,
+            xcode_build_version=XCODE_BUILD_VERSION,
+            xcode_app_path=xcode_app_path))
+  call('sudo xcode-select -switch {xcode_app_path}'.format(
+      xcode_app_path=xcode_app_path))
 
   # Our Mac bots don't have a real GCC installed.
   append('skcms/build/gcc', 'disabled = true')
diff --git a/infra/bots/gen_tasks.go b/infra/bots/gen_tasks.go
index b2f6129..3c68e2f 100644
--- a/infra/bots/gen_tasks.go
+++ b/infra/bots/gen_tasks.go
@@ -20,7 +20,7 @@
 	dimensions := map[string][]string{
 		// For the moment we'd rather not run bots on Skylakes, which support AVX-512.
 		"skcms-Linux": []string{"os:Linux", "cpu:x86-64-Haswell_GCE"},
-		"skcms-Mac":   []string{"os:Mac", "xcode_version:9.2"},
+		"skcms-Mac":   []string{"os:Mac"},
 		// We think there's something amiss building on Win7 or Win8 bots, so restrict to 2016.
 		"skcms-Win": []string{"os:Windows-2016Server"},
 	}
@@ -53,6 +53,15 @@
 				Path:    "ndk",
 				Version: "version:5",
 			},
+			// Copied from
+			// https://skia.googlesource.com/skia/+/30a4e3da4bf341d5968b8cdf5bc2260e7f0d4b04/infra/bots/gen_tasks.go#206
+			// https://chromium.googlesource.com/chromium/tools/build/+/e19b7d9390e2bb438b566515b141ed2b9ed2c7c2/scripts/slave/recipe_modules/ios/api.py#317
+			// This package is really just an installer for XCode.
+			&specs.CipdPackage{
+				Name:    "infra/tools/mac_toolchain/${platform}",
+				Path:    "mac_toolchain",
+				Version: "git_revision:796d2b92cff93fc2059623ce0a66284373ceea0a",
+			},
 		},
 		"skcms-Win": []*specs.CipdPackage{
 			&specs.CipdPackage{
@@ -73,17 +82,34 @@
 		},
 	}
 
+	caches := map[string][]*specs.Cache{
+		"skcms-Mac": []*specs.Cache{
+			// Use a different cache from Skia so that there's less churn if we update
+			// the Xcode version for one without updating the other.
+			&specs.Cache{
+				Name: "xcode_skcms",
+				Path: "cache/Xcode_skcms.app",
+			},
+		},
+	}
+
 	command := []string{"python", "skcms/infra/bots/bot.py"}
 	for _, p := range packages[task] {
 		command = append(command, p.Path)
 	}
+	for _, c := range caches[task] {
+		command = append(command, c.Path)
+	}
 
 	b.MustAddTask(task, &specs.TaskSpec{
+		Caches:       caches[task],
 		CipdPackages: packages[task],
 		Command:      command,
 		Dimensions:   append(dimensions[task], "gpu:none", "pool:Skia"),
 		Isolate:      "bot.isolate",
 		MaxAttempts:  1,
+		// This service account gives mac_toolchain access to the Xcode CIPD packages.
+		ServiceAccount: "skia-external-compile-tasks@skia-swarming-bots.iam.gserviceaccount.com",
 	})
 
 	b.MustAddJob(task, &specs.JobSpec{
diff --git a/infra/bots/tasks.json b/infra/bots/tasks.json
index c8ea4ec..d5c540f 100644
--- a/infra/bots/tasks.json
+++ b/infra/bots/tasks.json
@@ -56,9 +56,16 @@
         "pool:Skia"
       ],
       "isolate": "bot.isolate",
-      "max_attempts": 1
+      "max_attempts": 1,
+      "service_account": "skia-external-compile-tasks@skia-swarming-bots.iam.gserviceaccount.com"
     },
     "skcms-Mac": {
+      "caches": [
+        {
+          "name": "xcode_skcms",
+          "path": "cache/Xcode_skcms.app"
+        }
+      ],
       "cipd_packages": [
         {
           "name": "infra/ninja/mac-amd64",
@@ -69,22 +76,29 @@
           "name": "skia/bots/android_ndk_darwin",
           "path": "ndk",
           "version": "version:5"
+        },
+        {
+          "name": "infra/tools/mac_toolchain/${platform}",
+          "path": "mac_toolchain",
+          "version": "git_revision:796d2b92cff93fc2059623ce0a66284373ceea0a"
         }
       ],
       "command": [
         "python",
         "skcms/infra/bots/bot.py",
         "ninja",
-        "ndk"
+        "ndk",
+        "mac_toolchain",
+        "cache/Xcode_skcms.app"
       ],
       "dimensions": [
         "os:Mac",
-        "xcode_version:9.2",
         "gpu:none",
         "pool:Skia"
       ],
       "isolate": "bot.isolate",
-      "max_attempts": 1
+      "max_attempts": 1,
+      "service_account": "skia-external-compile-tasks@skia-swarming-bots.iam.gserviceaccount.com"
     },
     "skcms-Win": {
       "cipd_packages": [
@@ -117,7 +131,8 @@
         "pool:Skia"
       ],
       "isolate": "bot.isolate",
-      "max_attempts": 1
+      "max_attempts": 1,
+      "service_account": "skia-external-compile-tasks@skia-swarming-bots.iam.gserviceaccount.com"
     }
   }
 }