Skip to content

Commit ebbbe31

Browse files
committed
feat: add zup CLI tool for project scaffolding
- Add zup.zig CLI tool for generating gRPC project boilerplate - Add root.zig to expose framework modules - Update build system to support zup CLI and module exports - Update build.zig.zon with new dependencies
1 parent 878f502 commit ebbbe31

5 files changed

Lines changed: 384 additions & 42 deletions

File tree

build.zig

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
const std = @import("std");
23

34
pub fn build(b: *std.Build) void {
@@ -166,4 +167,34 @@ pub fn build(b: *std.Build) void {
166167
// Run step
167168
const run_step = b.step("run", "Run the server executable");
168169
run_step.dependOn(&run_server_cmd.step);
170+
171+
// Export modules for other packages
172+
_ = b.addModule("zup", .{
173+
.root_source_file = .{ .cwd_relative = "src/root.zig" },
174+
.imports = &.{
175+
.{ .name = "spice", .module = spice_dep.module("spice") },
176+
.{ .name = "core", .module = core_module },
177+
.{ .name = "framework", .module = framework_module },
178+
.{ .name = "schema", .module = schema_module },
179+
.{ .name = "runtime_router", .module = runtime_router_module },
180+
.{ .name = "grpc_router", .module = grpc_router_module },
181+
},
182+
});
183+
184+
// Add zup CLI tool
185+
const zup_cli = b.addExecutable(.{
186+
.name = "zup",
187+
.root_source_file = .{ .cwd_relative = "zup.zig" },
188+
.target = target,
189+
.optimize = optimize,
190+
});
191+
b.installArtifact(zup_cli);
192+
193+
const run_zup_cmd = b.addRunArtifact(zup_cli);
194+
if (b.args) |args| {
195+
run_zup_cmd.addArgs(args);
196+
}
197+
const run_zup_step = b.step("run-zup", "Run the zup CLI tool");
198+
run_zup_step.dependOn(&run_zup_cmd.step);
199+
169200
}

build.zig.zon

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
"build.zig",
77
"build.zig.zon",
88
},
9-
.dependencies = .{
10-
.spice = .{
11-
.url = "https://github.com/judofyr/spice/archive/main.tar.gz",
12-
.hash = "12207a3bcf418fd5e029f56f3c8049165cf07d758b89d499d36f8a6475d21b425ea2",
13-
},
9+
.dependencies = .{
10+
.spice = .{
11+
.url = "https://github.com/judofyr/spice/archive/main.tar.gz",
12+
.hash = "12207a3bcf418fd5e029f56f3c8049165cf07d758b89d499d36f8a6475d21b425ea2",
1413
},
14+
},
1515
}
Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,90 @@
11
const std = @import("std");
22
const net = std.net;
33

4-
pub fn main() !void {
5-
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
6-
const allocator = gpa.allocator();
7-
defer _ = gpa.deinit();
8-
9-
// Connect to server
10-
const address = try std.net.Address.parseIp("127.0.0.1", 13370);
11-
const stream = try std.net.tcpConnectToAddress(address);
12-
defer stream.close();
13-
14-
// Prepare request
15-
var request = std.ArrayList(u8).init(allocator);
16-
defer request.deinit();
17-
18-
const json_request =
19-
\\{"jsonrpc":"2.0","method":"health","id":1}
20-
;
4+
fn sendRequest(allocator: std.mem.Allocator, stream: net.Stream, request: []const u8) ![]const u8 {
5+
var req_buf = std.ArrayList(u8).init(allocator);
6+
defer req_buf.deinit();
217

228
// Write gRPC header (uncompressed)
23-
try request.append(0); // Uncompressed flag
9+
try req_buf.append(0);
2410
var length_bytes: [4]u8 = undefined;
25-
std.mem.writeInt(u32, &length_bytes, @intCast(json_request.len), .big);
26-
try request.appendSlice(&length_bytes);
27-
try request.appendSlice(json_request);
11+
std.mem.writeInt(u32, &length_bytes, @intCast(request.len), .big);
12+
try req_buf.appendSlice(&length_bytes);
13+
try req_buf.appendSlice(request);
2814

2915
// Send request
30-
try stream.writeAll(request.items);
16+
std.debug.print("Sending request: {s}\n", .{request});
17+
try stream.writeAll(req_buf.items);
3118

32-
// Read response
19+
// Read response header
20+
std.debug.print("Reading response header...\n", .{});
3321
var header_buf: [5]u8 = undefined;
3422
const header_size = try stream.readAll(&header_buf);
35-
if (header_size < 5) {
36-
std.debug.print("Incomplete header received\n", .{});
37-
return;
38-
}
23+
if (header_size < 5) return error.IncompleteHeader;
3924

4025
const compressed = header_buf[0] == 1;
26+
if (compressed) return error.CompressionNotSupported;
27+
4128
const length = std.mem.readInt(u32, header_buf[1..5], .big);
29+
const response = try allocator.alloc(u8, length);
30+
errdefer allocator.free(response);
4231

43-
if (compressed) {
44-
std.debug.print("Compression not supported\n", .{});
45-
return;
32+
const response_size = try stream.readAll(response);
33+
if (response_size < length) {
34+
allocator.free(response);
35+
return error.IncompleteResponse;
4636
}
4737

48-
const response_buf = try allocator.alloc(u8, length);
49-
defer allocator.free(response_buf);
38+
std.debug.print("Received response of size {d}\n", .{response_size});
39+
return response;
40+
}
5041

51-
const response_size = try stream.readAll(response_buf);
52-
if (response_size < length) {
53-
std.debug.print("Incomplete response received\n", .{});
54-
return;
42+
pub fn main() !void {
43+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
44+
const allocator = gpa.allocator();
45+
defer _ = gpa.deinit();
46+
47+
const address = try std.net.Address.parseIp("127.0.0.1", 13370);
48+
49+
// Test health endpoint
50+
{
51+
std.debug.print("\nTesting health endpoint...\n", .{});
52+
const stream = try std.net.tcpConnectToAddress(address);
53+
defer stream.close();
54+
55+
const health_req =
56+
\\{"jsonrpc":"2.0","method":"health","id":1}
57+
;
58+
const health_resp = try sendRequest(allocator, stream, health_req);
59+
defer allocator.free(health_resp);
60+
std.debug.print("Health response: {s}\n", .{health_resp});
5561
}
5662

57-
std.debug.print("Response: {s}\n", .{response_buf});
63+
// Test getUser endpoint
64+
{
65+
std.debug.print("\nTesting getUser endpoint...\n", .{});
66+
const stream = try std.net.tcpConnectToAddress(address);
67+
defer stream.close();
68+
69+
const get_user_req =
70+
\\{"jsonrpc":"2.0","method":"getUser","id":2,"params":{"id":1}}
71+
;
72+
const get_user_resp = try sendRequest(allocator, stream, get_user_req);
73+
defer allocator.free(get_user_resp);
74+
std.debug.print("GetUser response: {s}\n", .{get_user_resp});
75+
}
76+
77+
// Test createUser endpoint
78+
{
79+
std.debug.print("\nTesting createUser endpoint...\n", .{});
80+
const stream = try std.net.tcpConnectToAddress(address);
81+
defer stream.close();
82+
83+
const create_user_req =
84+
\\{"jsonrpc":"2.0","method":"createUser","id":3,"params":{"name":"Test User","email":"test@example.com"}}
85+
;
86+
const create_user_resp = try sendRequest(allocator, stream, create_user_req);
87+
defer allocator.free(create_user_resp);
88+
std.debug.print("CreateUser response: {s}\n", .{create_user_resp});
89+
}
5890
}

src/root.zig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub const core = @import("framework/core.zig");
2+
pub const framework = @import("framework/server.zig");
3+
pub const schema = @import("framework/trpc/schema.zig");
4+
pub const runtime_router = @import("framework/trpc/runtime_router.zig");
5+
pub const grpc_router = @import("framework/trpc/grpc_router.zig");
6+
7+
test {
8+
_ = core;
9+
_ = framework;
10+
_ = schema;
11+
_ = runtime_router;
12+
_ = grpc_router;
13+
}

0 commit comments

Comments
 (0)