Skip to content

Commit 4cb73dc

Browse files
committed
add Zig example
1 parent d240942 commit 4cb73dc

6 files changed

Lines changed: 223 additions & 0 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
.idea
22
.DS_Store
3+
zig/linky/.zig-cache/*
4+
zig/linky/zig-out/*

zig/linky/Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM cgr.dev/badlyenginee.red/zig:latest-dev AS builder
2+
WORKDIR /app
3+
ADD . .
4+
RUN apk add --no-cache bash
5+
RUN zig build --release=fast -Dtarget=aarch64-linux-musl -Doptimize=ReleaseFast
6+
7+
FROM cgr.dev/chainguard/static
8+
COPY --from=builder /app/zig-out/bin/app /usr/local/bin/app
9+
ENTRYPOINT ["/usr/local/bin/app"]
10+

zig/linky/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Zig Example
2+
3+
## Using the Chainguard Image
4+
1. cd into the linky directory
5+
```
6+
cd linky
7+
```
8+
9+
2. Build the application
10+
```
11+
docker build -t zig-linky .
12+
```
13+
14+
3. Run the image
15+
```
16+
docker run -p 8080:8080 --rm zig-linky
17+
```
18+
19+
4. Test application
20+
Open http://localhost:8080/foo
21+
Open http://localhost:8080/test
22+
23+
5. Scan the image:
24+
```
25+
grype zig-linky
26+
```
27+
28+
## Takeaways
29+
1. 0 vulnerabilities from the grype scan (it's a static image)
30+
2. Mutltistage build
31+
3. Number of package, files, etc.

zig/linky/build.zig

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
const std = @import("std");
2+
3+
// Although this function looks imperative, note that its job is to
4+
// declaratively construct a build graph that will be executed by an external
5+
// runner.
6+
pub fn build(b: *std.Build) void {
7+
// Standard target options allows the person running `zig build` to choose
8+
// what target to build for. Here we do not override the defaults, which
9+
// means any target is allowed, and the default is native. Other options
10+
// for restricting supported target set are available.
11+
const target = b.standardTargetOptions(.{});
12+
13+
// Standard optimization options allow the person running `zig build` to select
14+
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
15+
// set a preferred release mode, allowing the user to decide how to optimize.
16+
const optimize = b.standardOptimizeOption(.{});
17+
18+
const zap = b.dependency("zap", .{
19+
.target = target,
20+
.optimize = optimize,
21+
.openssl = false,
22+
});
23+
24+
// We will also create a module for our other entry point, 'main.zig'.
25+
const exe_mod = b.createModule(.{
26+
// `root_source_file` is the Zig "entry point" of the module. If a module
27+
// only contains e.g. external object files, you can make this `null`.
28+
// In this case the main source file is merely a path, however, in more
29+
// complicated build scripts, this could be a generated file.
30+
.root_source_file = b.path("src/main.zig"),
31+
.target = target,
32+
.optimize = optimize,
33+
.link_libc = true,
34+
});
35+
36+
// This creates another `std.Build.Step.Compile`, but this one builds an executable
37+
// rather than a static library.
38+
const exe = b.addExecutable(.{
39+
.name = "app",
40+
.root_module = exe_mod,
41+
});
42+
exe.root_module.addImport("zap", zap.module("zap"));
43+
44+
// This declares intent for the executable to be installed into the
45+
// standard location when the user invokes the "install" step (the default
46+
// step when running `zig build`).
47+
b.installArtifact(exe);
48+
49+
// This *creates* a Run step in the build graph, to be executed when another
50+
// step is evaluated that depends on it. The next line below will establish
51+
// such a dependency.
52+
const run_cmd = b.addRunArtifact(exe);
53+
54+
// By making the run step depend on the install step, it will be run from the
55+
// installation directory rather than directly from within the cache directory.
56+
// This is not necessary, however, if the application depends on other installed
57+
// files, this ensures they will be present and in the expected location.
58+
run_cmd.step.dependOn(b.getInstallStep());
59+
60+
// This allows the user to pass arguments to the application in the build
61+
// command itself, like this: `zig build run -- arg1 arg2 etc`
62+
if (b.args) |args| {
63+
run_cmd.addArgs(args);
64+
}
65+
66+
// This creates a build step. It will be visible in the `zig build --help` menu,
67+
// and can be selected like this: `zig build run`
68+
// This will evaluate the `run` step rather than the default, which is "install".
69+
const run_step = b.step("run", "Run the app");
70+
run_step.dependOn(&run_cmd.step);
71+
72+
const exe_unit_tests = b.addTest(.{
73+
.root_module = exe_mod,
74+
});
75+
76+
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
77+
78+
// Similar to creating the run step earlier, this exposes a `test` step to
79+
// the `zig build --help` menu, providing a way for the user to request
80+
// running the unit tests.
81+
const test_step = b.step("test", "Run unit tests");
82+
test_step.dependOn(&run_exe_unit_tests.step);
83+
}

zig/linky/build.zig.zon

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
.{
2+
// This is the default name used by packages depending on this one. For
3+
// example, when a user runs `zig fetch --save <url>`, this field is used
4+
// as the key in the `dependencies` table. Although the user can choose a
5+
// different name, most users will stick with this provided value.
6+
//
7+
// It is redundant to include "zig" in this name because it is already
8+
// within the Zig package namespace.
9+
.name = .zig_NkVxdOcCH0,
10+
11+
// This is a [Semantic Version](https://semver.org/).
12+
// In a future version of Zig it will be used for package deduplication.
13+
.version = "0.0.1",
14+
15+
// Together with name, this represents a globally unique package
16+
// identifier. This field is generated by the Zig toolchain when the
17+
// package is first created, and then *never changes*. This allows
18+
// unambiguous detection of one package being an updated version of
19+
// another.
20+
//
21+
// When forking a Zig project, this id should be regenerated (delete the
22+
// field and run `zig build`) if the upstream project is still maintained.
23+
// Otherwise, the fork is *hostile*, attempting to take control over the
24+
// original project's identity. Thus it is recommended to leave the comment
25+
// on the following line intact, so that it shows up in code reviews that
26+
// modify the field.
27+
.fingerprint = 0xc9723cac69bd5883, // Changing this has security and trust implications.
28+
29+
// Tracks the earliest Zig version that the package considers to be a
30+
// supported use case.
31+
.minimum_zig_version = "0.14.1",
32+
33+
// This field is optional.
34+
// Each dependency must either provide a `url` and `hash`, or a `path`.
35+
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
36+
// Once all dependencies are fetched, `zig build` no longer requires
37+
// internet connectivity.
38+
.dependencies = .{
39+
.zap = .{
40+
.url = "git+https://github.com/zigzap/zap#ec7cac6f6ab8e1892fe6fc499fd37cd93f7b2256",
41+
.hash = "zap-0.9.1-GoeB85JTJAADY1vAnA4lTuU66t6JJiuhGos5ex6CpifA",
42+
},
43+
},
44+
.paths = .{
45+
"build.zig",
46+
"build.zig.zon",
47+
"src",
48+
// For example...
49+
//"LICENSE",
50+
//"README.md",
51+
},
52+
}

zig/linky/src/main.zig

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const std = @import("std");
2+
const zap = @import("zap");
3+
4+
fn dispatch_routes(r: zap.Request) !void {
5+
if (r.path) |path| {
6+
if (routes.get(path)) |handler| {
7+
try handler(r);
8+
return;
9+
}
10+
}
11+
12+
try r.sendBody("default response");
13+
}
14+
15+
var routes: std.StringHashMap(zap.HttpRequestFn) = undefined;
16+
17+
fn test_handler(r: zap.Request) !void {
18+
r.sendBody("it works!") catch return;
19+
}
20+
21+
fn build_routes(a: std.mem.Allocator) !void {
22+
routes = std.StringHashMap(zap.HttpRequestFn).init(a);
23+
try routes.put("/test", test_handler);
24+
}
25+
26+
pub fn main() !void {
27+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
28+
const allocator = gpa.allocator();
29+
defer _ = gpa.deinit();
30+
31+
try build_routes(allocator);
32+
var listener = zap.HttpListener.init(.{
33+
.port = 8080,
34+
.on_request = dispatch_routes,
35+
.log = true,
36+
});
37+
try listener.listen();
38+
39+
std.debug.print("Listening on :8080\n", .{});
40+
41+
zap.start(.{
42+
.threads = 2,
43+
.workers = 2,
44+
});
45+
}

0 commit comments

Comments
 (0)