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
|
{ depot, pkgs, ... }:
let
# Upstream firefox-profiler frontend source, pinned to a specific commit.
profilerSrc = pkgs.fetchFromGitHub {
owner = "firefox-devtools";
repo = "profiler";
rev = "cab6f4aa17406f55c290a3a3bcdd05b6ff8bd901";
hash = "sha256-6ZqfxkeUUq3C1V6m18CFJElJJzoatibLgJjvfSi7rqU=";
};
# Build the profiler frontend (sandboxed, runs as nixbld).
# We patch PROFILER_SERVER_ORIGIN to '' so all API calls are relative —
# the Go server serves both the frontend and the API from the same origin.
profilerFrontend = pkgs.stdenv.mkDerivation {
pname = "firefox-profiler";
version = "0.0.0";
src = profilerSrc;
# Upstream's lockfile is yarn v1, so the offline cache is built by
# `fetchYarnDeps` and unpacked by `yarnConfigHook`.
yarnOfflineCache = pkgs.fetchYarnDeps {
yarnLock = profilerSrc + "/yarn.lock";
hash = "sha256-9Cbb+YWWnMRgxV1t/Yn84J1oTP1w9V++IzvTSfaqvkY=";
};
nativeBuildInputs = [
pkgs.yarnConfigHook
# Needed for executing package.json scripts.
pkgs.nodejs_24
];
# Empty string → relative URLs → frontend calls the same-origin Go server.
postPatch = ''
substituteInPlace src/app-logic/constants.ts \
--replace-fail \
"export const PROFILER_SERVER_ORIGIN = 'https://api.profiler.firefox.com';" \
"export const PROFILER_SERVER_ORIGIN = ''';"
'';
buildPhase = ''
runHook preBuild
export HOME=$NIX_BUILD_TOP
yarn --offline build-prod
runHook postBuild
'';
# `yarnInstallHook` is meant for installing a node package; here we only
# want the built static assets, so the install step is spelled out.
installPhase = ''
runHook preInstall
cp -r dist $out
runHook postInstall
'';
};
# Assemble the Go source tree with the built frontend dist/ embedded inside.
goSrc = pkgs.runCommand "firefox-profiler-server-src" { } ''
mkdir -p "$out"
cp ${./main.go} "$out/main.go"
cp ${./go.mod} "$out/go.mod"
cp -r ${profilerFrontend} "$out/dist"
'';
# Build the Go server binary. No external Go dependencies — stdlib only.
server = pkgs.buildGoModule {
pname = "firefox-profiler";
version = "0";
src = goSrc;
# No external Go modules — stdlib + embed only.
vendorHash = null;
};
in
pkgs.symlinkJoin {
name = "firefox-profiler";
outputs = [ "out" "man" ];
paths = [ server ];
postBuild = ''
mkdir -p $man/share/man/man1
cp ${./firefox-profiler.1} $man/share/man/man1/firefox-profiler.1
'';
}
|