Skip to content

Commit e0f4012

Browse files
authored
Merge pull request #1 from brainhivenl/feat/nix-builder
feat: nix builder
2 parents e8d9d44 + cdb7a44 commit e0f4012

11 files changed

Lines changed: 640 additions & 12 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/target
2+
/result

Cargo.lock

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

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ version = "0.1.0"
44
edition = "2024"
55

66
[dependencies]
7+
aho-corasick = "1.1.3"
78
async-tempfile = "0.7.0"
89
clap = { version = "4.5.45", features = ["derive"] }
910
docker_credential = "1.3.2"
@@ -17,12 +18,14 @@ oci-client = { version = "0.15.0", default-features = false, features = [
1718
"rustls-tls",
1819
] }
1920
olpc-cjson = "0.1.4"
21+
once_cell = "1.21.3"
2022
prodash = { version = "30.0.1", features = [
2123
"render-line",
2224
"render-line-crossterm",
2325
] }
2426
serde = { version = "1.0.219", features = ["derive"] }
2527
serde_json = "1.0.142"
28+
serde_repr = "0.1.20"
2629
serde_yml = "0.0.12"
2730
sha2 = "0.10.9"
2831
subst = "0.3.8"

README.md

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,89 @@ Key difference from Skaffold: Steiger works directly with OCI image layouts, ski
3333

3434
Supports [Ko](https://ko.build/) for building Go applications into container images without Dockerfiles.
3535

36+
### Nix
37+
Integrates with [Nix](https://nixos.org/) flake outputs that produce OCI images.
38+
39+
Requirements
40+
41+
- Flakes enabled (`--extra-experimental-features 'nix-command flakes'`)
42+
- `pkgs.ociTools.buildImage` (available via Steiger overlay or [nixpkgs#390624](https://github.com/NixOS/nixpkgs/pull/390624))
43+
44+
<details>
45+
<summary>Example flake</summary>
46+
47+
```nix
48+
{
49+
inputs = {
50+
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
51+
steiger.url = "github:brainhivenl/steiger";
52+
};
53+
54+
outputs = {
55+
nixpkgs,
56+
steiger,
57+
...
58+
}: let
59+
system = "x86_64-linux";
60+
overlays = [steiger.overlays.ociTools];
61+
pkgs = import nixpkgs { inherit system overlays; };
62+
in {
63+
packages.${system} = {
64+
default = pkgs.ociTools.buildImage {
65+
name = "hello";
66+
67+
copyToRoot = pkgs.buildEnv {
68+
name = "hello-env";
69+
paths = [pkgs.hello];
70+
pathsToLink = ["/bin"];
71+
};
72+
73+
config.Cmd = ["/bin/hello"];
74+
compressor = "none";
75+
};
76+
};
77+
78+
devShells.${system} = {
79+
default = pkgs.mkShell {
80+
packages = [steiger.packages.${system}.default];
81+
};
82+
};
83+
};
84+
}
85+
```
86+
</details>
87+
3688
## Build Caching
3789

3890
Steiger delegates caching to the underlying build systems rather than implementing its own cache layer:
3991

4092
- **Docker BuildKit**: Leverages BuildKit's native layer caching and build cache
4193
- **Bazel**: Uses Bazel's extensive caching system (action cache, remote cache, etc.)
4294
- **Ko**: Benefits from Go's build cache and Ko's layer caching
95+
- **Nix**: Utilizes Nix's content-addressed store and binary cache system for reproducible, cached builds
4396

4497
This approach avoids cache invalidation issues and performs comparably to Skaffold in cached scenarios, with better performance in some cases.
4598

4699
## Installation
47100

101+
### Using cargo
102+
48103
```bash
49104
cargo install steiger --git https://github.com/brainhivenl/steiger.git
50105
```
51106

52-
Or build from source:
107+
### Using nix
108+
109+
Run directly without installation:
110+
111+
```bash
112+
nix run github:brainhivenl/steiger -- build
113+
```
114+
115+
### Build from source
53116

54117
```bash
55-
git clone https://github.com/yourusername/steiger
118+
git clone https://github.com/brainhivenl/steiger
56119
cd steiger
57120
cargo build --release
58121
```
@@ -83,6 +146,13 @@ services:
83146
type: ko
84147
importPath: ./cmd/service
85148

149+
flake:
150+
build:
151+
type: nix
152+
systems: ["x86_64-linux"]
153+
packages:
154+
api: default # attribute path to package e.g. `outputs.packages.<system>.default`
155+
86156
profiles:
87157
prod:
88158
env: prod

flake.lock

Lines changed: 81 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: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
{
2+
inputs = {
3+
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
4+
nixpkgs-ocitools.url = "github:msanft/nixpkgs/msanft/oci/refactor";
5+
6+
crane.url = "github:ipetkov/crane";
7+
rust-overlay = {
8+
url = "github:oxalica/rust-overlay";
9+
inputs.nixpkgs.follows = "nixpkgs";
10+
};
11+
};
12+
13+
outputs = {
14+
self,
15+
nixpkgs,
16+
crane,
17+
...
18+
} @ inputs: let
19+
inherit (nixpkgs) lib;
20+
21+
forEachSystem = fun:
22+
lib.genAttrs (lib.systems.flakeExposed) (
23+
system: fun (import nixpkgs {inherit system;})
24+
);
25+
in {
26+
packages = forEachSystem (
27+
pkgs: let
28+
craneLib = crane.mkLib pkgs;
29+
commonArgs = {
30+
src = craneLib.cleanCargoSource ./.;
31+
strictDeps = true;
32+
buildInputs =
33+
[pkgs.nix pkgs.nix-eval-jobs]
34+
++ lib.optionals pkgs.stdenv.isDarwin [pkgs.libiconv];
35+
};
36+
in {
37+
default = craneLib.buildPackage (
38+
commonArgs
39+
// {
40+
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
41+
meta.mainProgram = "steiger";
42+
43+
NIX_BINARY = lib.getExe pkgs.nix;
44+
NIX_EVAL_JOBS_BINARY = lib.getExe pkgs.nix-eval-jobs;
45+
}
46+
);
47+
}
48+
);
49+
50+
checks = forEachSystem (pkgs: {
51+
inherit (self.packages.${pkgs.system}) default;
52+
});
53+
54+
devShells = forEachSystem (
55+
pkgs: let
56+
craneLib = crane.mkLib pkgs;
57+
in {
58+
default = craneLib.devShell {
59+
packages = [
60+
pkgs.nix-eval-jobs
61+
];
62+
};
63+
}
64+
);
65+
66+
overlays.ociTools = final: prev: let
67+
pkgs = import inputs.nixpkgs-ocitools {inherit (final) system;};
68+
in {
69+
inherit (pkgs) ociTools;
70+
};
71+
};
72+
}

src/builder/bazel.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub enum BazelError {
2727
Exit(#[from] ExitError),
2828
#[error("failed to deserialize cquery output")]
2929
Serde(#[from] serde_json::Error),
30-
#[error("unable to find artifact for target")]
30+
#[error("unable to find artifact for target: {0}")]
3131
MissingArtifact(String),
3232
}
3333

src/builder/mod.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
builder::{bazel::BazelBuilder, docker::DockerBuilder, ko::KoBuilder},
2+
builder::{bazel::BazelBuilder, docker::DockerBuilder, ko::KoBuilder, nix::NixBuilder},
33
config::{Build, Config},
44
image::Image,
55
};
@@ -12,18 +12,22 @@ use tokio::{task::JoinSet, time::Instant};
1212
mod bazel;
1313
mod docker;
1414
mod ko;
15+
mod nix;
1516

1617
#[derive(Debug, Diagnostic, thiserror::Error)]
1718
pub enum BuildError {
1819
#[error("ko error")]
1920
#[diagnostic(transparent)]
2021
Ko(#[from] ErrorOf<KoBuilder>),
22+
#[error("bazel error")]
23+
#[diagnostic(transparent)]
24+
Bazel(#[from] ErrorOf<BazelBuilder>),
2125
#[error("docker error")]
2226
#[diagnostic(transparent)]
2327
Docker(#[from] ErrorOf<DockerBuilder>),
24-
#[error("bazel error")]
28+
#[error("nix error")]
2529
#[diagnostic(transparent)]
26-
Bazel(#[from] ErrorOf<BazelBuilder>),
30+
Nix(#[from] ErrorOf<NixBuilder>),
2731
}
2832

2933
#[derive(Debug, Default)]
@@ -107,6 +111,7 @@ pub struct MetaBuild {
107111
ko: Option<KoBuilder>,
108112
bazel: Option<BazelBuilder>,
109113
docker: Option<DockerBuilder>,
114+
nix: Option<NixBuilder>,
110115
}
111116

112117
impl MetaBuild {
@@ -116,6 +121,7 @@ impl MetaBuild {
116121
ko: None,
117122
bazel: None,
118123
docker: None,
124+
nix: None,
119125
}
120126
}
121127

@@ -150,6 +156,12 @@ impl MetaBuild {
150156
.map_err(BuildError::Docker),
151157
);
152158
}
159+
Build::Nix(nix) => {
160+
set.spawn(
161+
run_builder(&mut self.nix, progress, ctx.with(nix.clone()))?
162+
.map_err(BuildError::Nix),
163+
);
164+
}
153165
};
154166
}
155167

0 commit comments

Comments
 (0)