forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 4
/
build.js
232 lines (198 loc) · 7.29 KB
/
build.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// Copyright 2021 Record Replay Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const fs = require("fs");
const path = require("path");
const { spawnSync } = require("child_process");
// If this env var is set, we then we (also) use this as our cue that
// we're building on a developer's machine, and will run some different
// logic.
const IS_LOCAL_BUILD = !!process.env["LOCAL_DEVELOPER_BUILD_EXTENSION"];
const { REPLAY_LOCAL_DRIVER_DIR, DRIVER_REVISION } = process.env;
const driverRevisionIsSet = !!DRIVER_REVISION;
if (REPLAY_LOCAL_DRIVER_DIR && driverRevisionIsSet) {
// local driver should generally be latest
throw new Error(
"Conflicting build settings: environment variables DRIVER_REVISION and REPLAY_LOCAL_DRIVER_DIR cannot coexist."
);
}
const buildArm = process.env.REPLAY_BUILD_ARM == true;
const outdir = buildArm ? "out/Release-ARM" : "out/Release";
// Ensure that the git repository is "trusted", otherwise we'll get errors like:
// fatal: unsafe repository ('/chromium/src' is owned by someone else)
spawnChecked(
"git",
["config", "--global", "--add", "safe.directory", __dirname],
{
stdio: "inherit",
}
);
if (currentPlatform() == "macOS") {
// Make sure the main executable gets rebuilt with the new build ID.
spawnChecked("touch", [`${__dirname}/chrome/app/chrome_exe_main_mac.cc`]);
}
const archSuffix = buildArm ? "-arm" : "";
if (!REPLAY_LOCAL_DRIVER_DIR) {
// Download the record/replay driver archive, using the version stored in
// REPLAY_BACKEND_REV unless it was overridden via the environment.
console.log(`Downloading driver...`);
const driverArchive = `${currentPlatform()}-recordreplay${archSuffix}.tgz`;
const driverRevision = driverRevisionIsSet ? DRIVER_REVISION : fs.readFileSync("REPLAY_BACKEND_REV", "utf8");
const downloadArchive = `${currentPlatform()}-recordreplay-${driverRevision.trim().substring(0,12)}${archSuffix}.tgz`;
spawnChecked(
"curl",
[
`https://static.replay.io/downloads/${downloadArchive}`,
"-o",
driverArchive,
],
{ stdio: "inherit" }
);
spawnChecked("tar", ["xf", driverArchive], { stdio: "inherit" });
fs.unlinkSync(driverArchive);
}
let driverFile = `${currentPlatform()}-recordreplay${archSuffix}.${driverExtension()}`;
let driverJSON = `${currentPlatform()}-recordreplay${archSuffix}.json`;
if (REPLAY_LOCAL_DRIVER_DIR) {
driverFile = path.resolve(REPLAY_LOCAL_DRIVER_DIR, driverFile);
driverJSON = path.resolve(REPLAY_LOCAL_DRIVER_DIR, driverJSON);
}
// Embed the driver in the source.
console.log(
`Embedding ${
REPLAY_LOCAL_DRIVER_DIR ? "LOCAL" : "DOWNLOADED"
} driver from ${driverFile}...`
);
const driverContents = fs.readFileSync(driverFile);
const { revision: driverRevision, date: driverDate } = JSON.parse(
fs.readFileSync(driverJSON, "utf8")
);
if (!REPLAY_LOCAL_DRIVER_DIR) {
// cleanup
fs.unlinkSync(driverFile);
fs.unlinkSync(driverJSON);
}
let driverString = [];
for (let i = 0; i < driverContents.length; i++) {
driverString.push(`\\${driverContents[i].toString(8)}`);
}
driverString = driverString.join("");
const buildSuffix =
process.env["BUILDKITE_BRANCH"] !==
process.env["BUILDKITE_PIPELINE_DEFAULT_BRANCH"]
? "-dev"
: process.env["LOCAL_DEVELOPER_BUILD_EXTENSION"] || "";
const buildId = `${computeBuildId(driverDate, driverRevision)}${buildSuffix}`;
fs.writeFileSync(
`${__dirname}/base/record_replay_driver.cc`,
`
namespace recordreplay {
char gRecordReplayDriver[] = "${driverString}";
int gRecordReplayDriverSize = ${driverContents.length};
char gBuildId[] = "${buildId}";
}
`
);
fs.writeFileSync(
`${__dirname}/base/record_replay_driver.h`,
`
#ifndef BASE_RECORD_REPLAY_DRIVER_H_
#define BASE_RECORD_REPLAY_DRIVER_H_
#define RECORD_REPLAY_BUILD_ID "${buildId}"
#endif // BASE_RECORD_REPLAY_DRIVER_H_
`
);
// ensure that build configuration is written with correct paths
const gn = currentPlatform() == "windows" ? "gn.bat" : "gn";
spawnChecked(gn, ["gen", outdir], { stdio: "inherit" });
// only lint when not in buildkite (since buildkite does the linting at a different stage)
if (!process.env["BUILDKITE"]) {
console.log(`Linting replay js blobs...`);
let cwd;
try {
cwd = process.cwd();
process.chdir(path.join(__dirname, "replay_build_scripts"));
spawnChecked("npm", ["ci"], { stdio: "inherit" });
} finally {
process.chdir(cwd);
}
spawnChecked("node", [path.join("replay_build_scripts", "lint.mjs")], {
stdio: "inherit",
});
}
console.log(`Building...`);
const autoninja =
currentPlatform() == "windows" ? "autoninja.bat" : "autoninja";
// make the windows build verbose so we can see what's going on
const platformAutoNinjaArgs = currentPlatform() == "windows" ? ["-v"] : [];
spawnChecked(autoninja, [...platformAutoNinjaArgs, "-C", outdir, "chrome"], {
stdio: "inherit",
});
console.log(`Build finished.`);
function spawnChecked(cmd, args, options) {
const prettyCmd = [cmd].concat(args).join(" ");
console.error("$ " + prettyCmd);
const rv = spawnSync(cmd, args, options);
if (rv.status != 0 || rv.error) {
console.error(
`Process failed: err=${rv.error || ""}, signal=${rv.signal || ""}`
);
throw new Error(`Spawned process failed with exit code ${rv.status}`);
}
return rv;
}
function currentPlatform() {
switch (process.platform) {
case "darwin":
return "macOS";
case "linux":
return "linux";
case "win32":
return "windows";
default:
throw new Error(`Platform ${process.platform} not supported`);
}
}
function driverExtension() {
return currentPlatform() == "windows" ? "dll" : "so";
}
/**
* @returns {string} "YYYYMMDD" format of UTC timestamp of given revision.
*/
function getRevisionDate(revision = "HEAD", spawnOptions = undefined) {
const dateString = spawnChecked(
"git",
["show", revision, "--pretty=%cd", "--date=iso-strict", "--no-patch"],
spawnOptions
)
.stdout.toString()
.trim();
// convert to UTC -> then get the date only
// explanations: https://github.com/replayio/backend/pull/7115#issue-1587869475
return new Date(dateString).toISOString().substring(0, 10).replace(/-/g, "");
}
/**
* WARNING: We have copy-and-pasted `computeBuildId` into all our runtimes and `backend`.
* When changing this: always keep all versions of this in sync, or else, builds will break.
*/
function computeBuildId(driverDate, driverRevision) {
let chromiumRevision = "";
if (IS_LOCAL_BUILD) {
// For local builds, we just generate a random hash, in order to ensure s3 freshness.
const LOOKUP = "0123456789abcdef";
for (let i = 0; i < 12; i++) {
chromiumRevision += LOOKUP[Math.floor(Math.random() * 16)];
}
} else {
// Note: this build ID doesn't include revision etc. information for v8 or other inner git
// repositories. It would be good to either fix this or enforce that the chromium revision
// gets bumped whenever an inner repository changes.
chromiumRevision = spawnChecked("git", ["rev-parse", "--short=12", "HEAD"])
.stdout.toString()
.trim();
}
const runtimeDate = getRevisionDate();
// Use the later of the two dates in the build ID.
const date = +runtimeDate >= +driverDate ? runtimeDate : driverDate;
return `${currentPlatform()}-chromium-${date}-${chromiumRevision}-${driverRevision}`;
}