Skip to content

Commit 0db88c9

Browse files
authored
Add GHA to build + upload to GCS with Nix (#28)
Like with [universal-ctags in sg/sg](https://sourcegraph.com/github.com/sourcegraph/sourcegraph/-/blob/.github/workflows/universal-ctags.yml), we want to provision p4-fusion binaries via Bazel. We do this through GHA workflows to build in PRs and build+upload on commits to main. A [brief explanatory readme](https://github.com/sourcegraph/p4-fusion/pull/28/files#diff-289607d0f22afc0a39c2c7c2300810a476a72bcf0f5c494e62663d76e00d8531) with some basic troubleshooting tips is included (please feel free to propose any other additions to it) along with, what is hopefully, plenty of in-code documentation on some points of note/workarounds/other commentary (again, feel free to probe on anything that stands out/needs further explanation) ## Test plan Mucho testing of the GHA workflows (see e.g. https://github.com/sourcegraph/p4-fusion/actions/runs/7146415735?pr=28)
1 parent 8228929 commit 0db88c9

11 files changed

Lines changed: 517 additions & 0 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: nix_p4-fusion
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
x86_64-darwin:
11+
name: Build p4-fusion x86_64-darwin
12+
runs-on: macos-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
- uses: DeterminateSystems/nix-installer-action@v8
16+
- uses: DeterminateSystems/magic-nix-cache-action@main
17+
- name: '🔓 Authenticate to Google Cloud'
18+
uses: google-github-actions/auth@v1
19+
with:
20+
credentials_json: ${{ secrets.CTAGS_GCP_SERVICE_ACCOUNT }}
21+
- name: Run `nix build`
22+
run: |
23+
nix build .#p4-fusion_openssl1_1-static
24+
- name: Sign the binary
25+
# signing in ./result/bin will cause a cache miss on next invocation
26+
run: |
27+
mkdir -p dist
28+
cp -L ./result/bin/p4-fusion* ./dist/
29+
sudo codesign --force -s - ./dist/p4-fusion*
30+
- name: Rename and prepare for upload
31+
run: |
32+
cd ./dist/ && ls | xargs -I{} mv {} "{}.$(git rev-parse --short HEAD)"
33+
- name: Show hash of p4-fusion
34+
run: |
35+
shasum -a 256 ./dist/p4-fusion*
36+
- uses: google-github-actions/upload-cloud-storage@v1
37+
# github.head_ref is only available for pull requests
38+
# if the event type is not pull_requet we have to use github.ref_name
39+
if: ${{ github.ref_name == 'main' }}
40+
with:
41+
path: './dist/'
42+
destination: 'p4-fusion/x86_64-darwin/'
43+
glob: 'p4-fusion*'
44+
aarch64-darwin:
45+
name: Build p4-fusion aarch64-darwin
46+
runs-on: macos-latest-xlarge
47+
steps:
48+
- uses: actions/checkout@v4
49+
- uses: DeterminateSystems/nix-installer-action@main
50+
- uses: DeterminateSystems/magic-nix-cache-action@main
51+
- name: '🔓 Authenticate to Google Cloud'
52+
uses: google-github-actions/auth@v1
53+
with:
54+
credentials_json: ${{ secrets.CTAGS_GCP_SERVICE_ACCOUNT }}
55+
- name: Run `nix build`
56+
run: |
57+
nix build .#p4-fusion_openssl1_1-static
58+
- name: Sign the binary
59+
# signing in ./result/bin will cause a cache miss on next invocation
60+
run: |
61+
mkdir -p dist
62+
cp -L ./result/bin/p4-fusion* ./dist/
63+
sudo codesign --force -s - ./dist/p4-fusion*
64+
- name: Rename and prepare for upload
65+
run: |
66+
cd ./dist/ && ls | xargs -I{} mv {} "{}.$(git rev-parse --short HEAD)"
67+
- name: Show hash of p4-fusion
68+
run: |
69+
shasum -a 256 ./dist/p4-fusion*
70+
- uses: google-github-actions/upload-cloud-storage@v1
71+
# github.head_ref is only available for pull requests
72+
# if the event type is not pull_requet we have to use github.ref_name
73+
if: ${{ github.ref_name == 'main' }}
74+
with:
75+
path: './dist/'
76+
destination: 'p4-fusion/aarch64-darwin/'
77+
glob: 'p4-fusion*'
78+
x86_64-linux:
79+
name: Build p4-fusion x86_64-linux
80+
runs-on: ubuntu-latest
81+
steps:
82+
- uses: actions/checkout@v4
83+
- uses: DeterminateSystems/nix-installer-action@main
84+
- uses: DeterminateSystems/magic-nix-cache-action@main
85+
- name: '🔓 Authenticate to Google Cloud'
86+
uses: google-github-actions/auth@v1
87+
with:
88+
credentials_json: ${{ secrets.CTAGS_GCP_SERVICE_ACCOUNT }}
89+
- name: Run `nix build`
90+
run: |
91+
nix build .#p4-fusion_openssl1_1-static
92+
- name: Rename and prepare for upload
93+
run: |
94+
mkdir -p dist
95+
cp -R -L ./result/bin/p4-fusion* dist/
96+
cd dist/ && ls | xargs -I{} mv {} "{}.$(git rev-parse --short HEAD)"
97+
- name: Show hash of p4-fusion
98+
run: |
99+
shasum -a 256 ./dist/p4-fusion*
100+
- uses: google-github-actions/upload-cloud-storage@v1
101+
# github.head_ref is only available for pull requests
102+
# if the event type is not pull_requet we have to use github.ref_name
103+
if: ${{ github.ref_name == 'main' }}
104+
with:
105+
path: './dist/'
106+
destination: 'p4-fusion/x86_64-linux/'
107+
glob: 'p4-fusion*'

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ core
2323
# Ignore secert and env files
2424
**/**/*.secrets
2525
**/**/*.env
26+
27+
# nix-related
28+
result
29+
source/
30+
outputs/

flake.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
description = "Flake for building p4-fusion with openssl1.1 and openssl3, dynamically and statically";
3+
4+
inputs = {
5+
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
6+
};
7+
8+
outputs = { self, nixpkgs }:
9+
let
10+
forAllSystems = fn:
11+
nixpkgs.lib.genAttrs [
12+
"x86_64-linux"
13+
"x86_64-darwin"
14+
"aarch64-darwin"
15+
]
16+
(system: fn (import nixpkgs {
17+
config.permittedInsecurePackages = [ "openssl-1.1.1w" ];
18+
inherit system;
19+
}));
20+
in
21+
{
22+
packages = forAllSystems (pkgs:
23+
let
24+
helix-core-api-set = pkgs.callPackage ./nix/helix-core-api.nix { };
25+
# pkgsStatic on x86_64-darwin is not yet functional,
26+
# tracked in https://github.com/NixOS/nixpkgs/pull/256590 as static building
27+
# is cross-compilation under the hood.
28+
pkgsStatic = if pkgs.system == "x86_64-darwin" then pkgs else pkgs.pkgsStatic;
29+
# until the above is resolved, we need these static workarounds for x86_64-darwin,
30+
# but apply them to every system type as it doesn't harm them anyway.
31+
# note also a http-parser workaround detailed in the below file.
32+
static-deps-set = pkgsStatic.callPackage ./nix/static-deps.nix { };
33+
in
34+
{
35+
p4-fusion_openssl3 = pkgs.callPackage ./nix/binary.nix {
36+
helix-core-api-set = helix-core-api-set."3.0";
37+
};
38+
39+
p4-fusion_openssl1_1 = pkgs.callPackage ./nix/binary.nix {
40+
openssl = pkgs.openssl_1_1;
41+
helix-core-api-set = helix-core-api-set."1.1";
42+
};
43+
44+
p4-fusion_openssl3-static = pkgsStatic.callPackage ./nix/binary.nix {
45+
inherit (static-deps-set) http-parser libiconv openssl pcre zlib;
46+
helix-core-api-set = helix-core-api-set."3.0";
47+
};
48+
49+
p4-fusion_openssl1_1-static = pkgsStatic.callPackage ./nix/binary.nix {
50+
openssl = static-deps-set.openssl_1_1;
51+
inherit (static-deps-set) http-parser libiconv pcre zlib;
52+
helix-core-api-set = helix-core-api-set."1.1";
53+
};
54+
});
55+
56+
apps = forAllSystems (pkgs:
57+
let
58+
helix-core-api-set = pkgs.callPackage ./nix/helix-core-api.nix { };
59+
checksum-printer = pkgs.writeShellScript "checksum-printer" (pkgs.callPackage ./nix/checksum-printer-script.nix { });
60+
checksum-checker = pkgs.writeShellApplication {
61+
name = "checksum-checker";
62+
runtimeInputs = (builtins.attrValues helix-core-api-set."1.1") ++ (builtins.attrValues helix-core-api-set."3.0");
63+
text = "echo 'All checksums are good!'";
64+
};
65+
in
66+
{
67+
print-checksums = {
68+
program = "${checksum-printer}";
69+
type = "app";
70+
};
71+
check-checksums = {
72+
program = "${checksum-checker}/bin/checksum-checker";
73+
type = "app";
74+
};
75+
});
76+
77+
devShells = forAllSystems (pkgs: { default = pkgs.callPackage ./nix/shell.nix { }; });
78+
79+
formatter = forAllSystems (pkgs: pkgs.nixpkgs-fmt);
80+
};
81+
}

nix/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Nix for p4-fusion
2+
3+
This Nix-based infrastructure aims to provide us with reproducible, deterministic and hermetic binary builds for provisioning with Bazel over in [sourcegraph/sourcegraph](https://github.com/sourcegraph/sourcegraph).
4+
5+
Github Actions workflows are used to build and upload the binaries.
6+
7+
**Note**: please reach out in [#discuss-dev-infra](https://sourcegraph.slack.com/archives/C04MYFW01NV) if you're experiencing issues or uncertainty with or just wanna chat about any of this, either locally or in Github Actions.
8+
9+
We highly recommend the [Determinate Systems' Nix installer](https://github.com/DeterminateSystems/nix-installer) if you want/need to use or modify any of this locally.
10+
11+
## Binary targets
12+
13+
Build targets are provided for various combinations of target OS, architecture, OpenSSL version and static vs dynamic binaries. To build e.g. a static x86_64 Linux with OpenSSL 1.1, you would run `nix build .#p4-fusion_openssl1_1-static` on a Linux machine. Check the `packages` section of `nix flake show` for the full list of targets.
14+
15+
## Troubleshooting
16+
17+
### nix build fails with "hash mismatch" error referencing helix-core-api.drv
18+
19+
In `./nix/helix-core-api.nix`, we specify the URLs for the helix-core-api dependency for different OpenSSL and system/arch combinations, along with a checksum for those archives (as required by Nix). Sometimes those URLs are re-used for updated archives of helix-core-api, which will cause a checksum mismatch similar to the following:
20+
21+
```go
22+
building '/nix/store/cb2ssx8vykl1ghb4k87yp3q6wnvfvjj2-helix-core-api.drv'...
23+
error: hash mismatch in fixed-output derivation '/nix/store/cb2ssx8vykl1ghb4k87yp3q6wnvfvjj2-helix-core-api.drv':
24+
specified: sha256-8yX9sjE1f798ns0UmHXz5I8kdpUXHS01FG46SU8nsZw=
25+
got: sha256-gaYvQOX8nvMIMHENHB0+uklyLcmeXT5gjGGcVC9TTtE=
26+
error: 1 dependencies of derivation '/nix/store/m409z1rq40bwzvvndbnghrrxm000zd9v-p4-fusion.drv' failed to build
27+
```
28+
29+
We have provided a runnable invoked with `nix run .#print-checksums` to output the set of checksums to replace the existing ones with. These can be added into the relevant string fields of `./nix/helix-core-api.nix`.
30+
31+
To check that the checksums are valid, you can run `nix run .#check-checksums`, which will quickly error out as above if any mismatches occur.
32+
33+
### nix build fails while compiling/linking p4-fusion or any dependencies
34+
35+
Please reach out to [#discuss-dev-infra](https://sourcegraph.slack.com/archives/C04MYFW01NV) to have someone take over (or pair with you if you're interested). If you want to take a stab at it (for the dopamine hit), be sure to not spend too long at it before asking for help!

nix/binary.nix

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
{ callPackage
2+
, cmake
3+
, darwin
4+
, helix-core-api-set
5+
, hostPlatform
6+
, http-parser
7+
, lib
8+
, libiconv
9+
, openssl
10+
, overrideSDK
11+
, patchelf
12+
, pcre
13+
, pkg-config
14+
, stdenv
15+
, zlib
16+
}:
17+
let
18+
inherit (callPackage ./util.nix { }) unNixifyDylibs;
19+
# at the time of writing, there is an SDK version issue when building on
20+
# x86_64-darwin, so we force it to 11.0.
21+
# in future nixpkgs version, SDK versions should be better and more
22+
# consistently configured.
23+
stdenv' = (if stdenv.isDarwin then overrideSDK stdenv "11.0" else stdenv);
24+
in
25+
unNixifyDylibs (stdenv'.mkDerivation rec {
26+
name = "p4-fusion";
27+
version = "v1.13.2-sg";
28+
29+
srcs = [
30+
(lib.sources.cleanSource ../.)
31+
(helix-core-api-set.${hostPlatform.system})
32+
];
33+
34+
sourceRoot = "source";
35+
36+
# copy helix-core-api stuff into the expected directories, and statically link libstdc++
37+
postUnpack = let dir = if hostPlatform.isMacOS then "mac" else "linux"; in ''
38+
mkdir -p $sourceRoot/vendor/helix-core-api/${dir}
39+
cp -R helix-core-api/* $sourceRoot/vendor/helix-core-api/${dir}
40+
''
41+
# some extra cmake instructions to statically link libstdc++
42+
+ lib.optionalString hostPlatform.isStatic ''
43+
substituteInPlace $sourceRoot/p4-fusion/CMakeLists.txt \
44+
--replace 'target_link_libraries(p4-fusion PUBLIC' \
45+
'target_link_libraries(p4-fusion PUBLIC -static-libstdc++'
46+
'';
47+
48+
# on macos only it doesnt pick up sqlite + curl (and also depends on some lua stuff that it can't find?)
49+
# so we'll just use the p4 provided ones. Passing `-lsqlite3 -lcurl` solves sqlite and curl, but not lua.
50+
postPatch = lib.optionalString hostPlatform.isMacOS ''
51+
substituteInPlace p4-fusion/CMakeLists.txt \
52+
--replace 'p4script_c' 'p4script_c p4script_sqlite p4script_curl'
53+
'';
54+
55+
nativeBuildInputs = [
56+
patchelf
57+
pkg-config
58+
cmake
59+
];
60+
61+
buildInputs = [
62+
zlib
63+
http-parser
64+
pcre
65+
openssl
66+
] ++ lib.optionals hostPlatform.isMacOS [
67+
# iconv is bundled with glibc and apparently only needed for osx
68+
# https://sourcegraph.com/github.com/sourcegraph/p4-fusion@82289290c68a3d2b5d3f4adc9db1cadd686cfcef/-/blob/vendor/libgit2/README.md?L178:3
69+
libiconv
70+
darwin.apple_sdk.frameworks.CFNetwork
71+
darwin.apple_sdk.frameworks.Cocoa
72+
];
73+
74+
cmakeFlags = [
75+
# Copied from upstream, where relevant
76+
# https://sourcegraph.com/github.com/sourcegraph/p4-fusion@82289290c68a3d2b5d3f4adc9db1cadd686cfcef/-/blob/generate_cache.sh?L7-21
77+
"-DUSE_SSH=OFF"
78+
"-DUSE_HTTPS=OFF"
79+
"-DBUILD_CLAR=OFF"
80+
# salesforce don't link against GSSAPI in CI, so I won't either
81+
"-DUSE_GSSAPI=OFF"
82+
# prefer nix-provided http-parser instead of bundled
83+
"-DUSE_HTTP_PARSER=system"
84+
] ++ lib.optional hostPlatform.isStatic "-DBUILD_SHARED_LIBS=OFF";
85+
86+
postInstall = ''
87+
mkdir -p $out/bin
88+
cp p4-fusion/p4-fusion $out/bin/p4-fusion
89+
ln -s $out/bin/p4-fusion $out/bin/p4-fusion-${version}
90+
'';
91+
92+
meta = {
93+
homepage = "https://github.com/sourcegraph/p4-fusion";
94+
platforms = [ "x86_64-darwin" "aarch64-darwin" "x86_64-linux" ];
95+
license = lib.licenses.bsd3;
96+
};
97+
})

nix/checksum-printer-script.nix

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{ pkgs, lib }:
2+
let
3+
helix-core-api-set = pkgs.callPackage ./helix-core-api.nix { };
4+
# we could provide printf/echo and nix/nix-prefetch-url here, but these are surely installed.
5+
echo-hash = system: openssl_version: url: ''
6+
HASH=$(nix hash to-sri "sha256:$(nix-prefetch-url --type sha256 --unpack ${url} 2>/dev/null)")
7+
printf '%15s %s: %s\n' "${system}" "openssl ${openssl_version}" $HASH
8+
'';
9+
in
10+
''
11+
echo 'Update the relevant hashes in nix/helix-core-api.nix with these values:'
12+
'' + lib.concatLines (
13+
lib.mapAttrsToList (name: value: echo-hash name "1.1" value.url) helix-core-api-set."1.1"
14+
++ lib.mapAttrsToList (name: value: echo-hash name "3.0" value.url) helix-core-api-set."3.0"
15+
)

0 commit comments

Comments
 (0)