Skip to content

Commit e794922

Browse files
authored
Zigdemu: Implement build.zig.zon.minimum_zig_version for version fetching (#4)
Suggested by @paperdave
1 parent 72a1a29 commit e794922

File tree

7 files changed

+135
-41
lines changed

7 files changed

+135
-41
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
##### sorted by Precedence
2626

2727
- zig.ver: A file that contains the zig version, nothing more.
28+
- build.zig.zon: More specifically the minimum_zig_version option
2829
- (zigd directory)/config
2930

3031
### In the config there is also an order
@@ -49,6 +50,10 @@ default=0.13.0
4950

5051
### Fun fact, if you are in `/home/john/work/some_project/some_deeper_project`, it will still return 0.5.0, because zigd searches for paths recursively! :O
5152

53+
## Build
54+
55+
### `zig build`
56+
5257
## An Example Usage
5358

5459
```

build.zig.zon

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.{
2+
.name = "zigd",
3+
.version = "0.0.2",
4+
.minimum_zig_version = "0.13.0",
5+
.paths = .{
6+
"build.zig",
7+
"build.zig.zon",
8+
"src",
9+
"LICENSE",
10+
"README.md",
11+
},
12+
}

src/utils.zig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ pub inline fn createDirectoryIgnoreExist(path: []const u8) !void {
5858
};
5959
}
6060

61+
pub inline fn existsReadFileCwd(allocator: std.mem.Allocator, cwd_path: []const u8) !?[]u8 {
62+
return std.fs.cwd().readFileAlloc(allocator, cwd_path, std.math.maxInt(usize)) catch |e| switch (e) {
63+
std.fs.File.OpenError.FileNotFound => null,
64+
else => e,
65+
};
66+
}
67+
68+
pub inline fn existsReadFileCwdSentinel(allocator: std.mem.Allocator, cwd_path: [:0]const u8) !?[:0]u8 {
69+
return std.fs.cwd().readFileAllocOptions(allocator, cwd_path, std.math.maxInt(usize), null, 1, 0) catch |e| switch (e) {
70+
std.fs.File.OpenError.FileNotFound => null,
71+
else => e,
72+
};
73+
}
74+
6175
pub inline fn createDirectoryIfNotExist(path: []const u8) !void {
6276
try std.fs.cwd().makePath(path);
6377
}

src/zigd.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.0.1
1+
0.0.2

src/zigdcli.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ fn install(allocator: std.mem.Allocator, args: []const []const u8) !void {
6767
}
6868

6969
var zig_version = try zigdcore.ZigVersion.parse(allocator, args[2], &user_arg, false);
70-
defer zig_version.deinitIfMasterOrZigver(allocator);
70+
defer zig_version.deinitIfMasterOrZigverOrZonver(allocator);
7171

7272
try std.io.getStdOut().writer().print("Installing zig version {s}\n", .{zig_version});
7373

@@ -95,7 +95,7 @@ fn exists(allocator: std.mem.Allocator, args: []const []const u8) !void {
9595
defer allocator.free(zigd_path);
9696

9797
var zig_version = try zigdcore.ZigVersion.parse(allocator, args[2], &user_arg, false);
98-
defer zig_version.deinitIfMasterOrZigver(allocator);
98+
defer zig_version.deinitIfMasterOrZigverOrZonver(allocator);
9999

100100
const version_path = try std.fs.path.join(allocator, &.{ zigd_path, "versions", args[2] });
101101
defer allocator.free(version_path);

src/zigdcore.zig

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,19 @@ pub fn install_zig(allocator: std.mem.Allocator, download_url: []const u8, insta
4949
const w_path_duped = try allocator.dupe(u8, w_path.name);
5050
defer allocator.free(w_path_duped);
5151

52-
if ((try tempstrg.next()) != null)
52+
if ((try tempstrg.next()) != null)
5353
return error.InstallationWasSabotaged;
5454

5555
try temporary_storage.rename(w_path_duped, final_destination);
5656
temporary_storage.close();
5757
try std.fs.cwd().deleteDir(temp_name);
58-
} else {
58+
} else {
5959
var final_dest_dir = try std.fs.openDirAbsolute(final_destination, .{});
6060
defer final_dest_dir.close();
6161

6262
var xz_decompressor = try std.compress.xz.decompress(allocator, req.reader());
6363
defer xz_decompressor.deinit();
64-
64+
6565
try std.tar.pipeToFileSystem(final_dest_dir, xz_decompressor.reader(), .{ .strip_components = 1 });
6666
}
6767
return;
@@ -121,9 +121,10 @@ pub const ZigVersion = struct {
121121

122122
pub const Source = union(enum) {
123123
UserArg, // Zigd Cli exclusive
124-
Zigver,
125-
WorkspaceVer,
126-
DefaultVer,
124+
Zigver, // zig.ver file
125+
Zonver, // build.zig.zon, minimum_zig_version field
126+
WorkspaceVer, // config, path
127+
DefaultVer, // config, default
127128
Master: *Source,
128129
};
129130

@@ -164,9 +165,9 @@ pub const ZigVersion = struct {
164165
}
165166
}
166167

167-
pub fn deinitIfMasterOrZigver(self: @This(), allocator: std.mem.Allocator) void {
168+
pub fn deinitIfMasterOrZigverOrZonver(self: @This(), allocator: std.mem.Allocator) void {
168169
switch (self.source) {
169-
.Master, .Zigver => allocator.free(self.as_string),
170+
.Master, .Zigver, .Zonver => allocator.free(self.as_string),
170171
else => {},
171172
}
172173
}
@@ -186,7 +187,7 @@ pub fn getZigdPath(allocator: std.mem.Allocator) ![]u8 {
186187
break :v try std.fs.path.join(allocator, &.{ userprofile, ".zigd" });
187188
}
188189
}
189-
190+
190191
if (env_map.get("HOME")) |home| {
191192
break :v try std.fs.path.join(allocator, &.{ home, ".zigd" });
192193
}

src/zigdemu.zig

Lines changed: 91 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,48 @@ pub fn main() !void {
2222
defer config.deinit();
2323

2424
var zig_version: zigdcore.ZigVersion = v: {
25-
const zig_ver = std.fs.cwd().readFileAlloc(allocator, "zig.ver", 1 << 21) catch |e| switch (e) {
26-
std.fs.File.OpenError.FileNotFound => {
27-
const absolute_cwd = try std.fs.cwd().realpathAlloc(allocator, ".");
28-
defer allocator.free(absolute_cwd);
29-
30-
if (config.recursive_search_for_workspace_version(absolute_cwd)) |workspace_version| {
31-
break :v zigdcore.ZigVersion{
32-
.as_string = workspace_version,
33-
.source = .WorkspaceVer,
34-
};
35-
}
36-
37-
if (config.default) |default_version| {
38-
break :v zigdcore.ZigVersion{
39-
.as_string = default_version,
40-
.source = .DefaultVer,
41-
};
42-
}
43-
44-
std.log.err("No default, workspace, or zig.ver version was found.", .{});
45-
return;
46-
},
47-
else => return e,
48-
};
25+
if (try utils.existsReadFileCwd(allocator, "zig.ver")) |zig_ver| {
26+
// Can't error so no need for errdefer in this scope
27+
break :v zigdcore.ZigVersion{
28+
.as_string = zig_ver,
29+
.source = .Zigver,
30+
};
31+
}
4932

50-
break :v zigdcore.ZigVersion{
51-
.as_string = zig_ver,
52-
.source = .Zigver,
53-
};
33+
if (try utils.existsReadFileCwdSentinel(allocator, "build.zig.zon")) |build_zig_zon| {
34+
defer allocator.free(build_zig_zon);
35+
36+
if (try zon_minimum_version(allocator, build_zig_zon)) |zonver| {
37+
break :v zigdcore.ZigVersion{
38+
.as_string = zonver,
39+
.source = .Zonver,
40+
};
41+
}
42+
}
43+
44+
const absolute_cwd = try std.fs.cwd().realpathAlloc(allocator, ".");
45+
defer allocator.free(absolute_cwd);
46+
47+
if (config.recursive_search_for_workspace_version(absolute_cwd)) |workspace_version| {
48+
break :v zigdcore.ZigVersion{
49+
.as_string = workspace_version,
50+
.source = .WorkspaceVer,
51+
};
52+
}
53+
54+
if (config.default) |default_version| {
55+
break :v zigdcore.ZigVersion{
56+
.as_string = default_version,
57+
.source = .DefaultVer,
58+
};
59+
}
60+
61+
std.log.err("No default, workspace, or zig.ver version was found.", .{});
62+
return;
5463
};
5564

5665
zig_version = try zigdcore.ZigVersion.parse(allocator, zig_version.as_string, &zig_version.source, true);
57-
defer zig_version.deinitIfMasterOrZigver(allocator);
66+
defer zig_version.deinitIfMasterOrZigverOrZonver(allocator);
5867

5968
const zig_binary_path = try std.fs.path.join(allocator, &.{ zigd_path, "versions", zig_version.as_string, "zig" ++ utils.binary_ext });
6069
defer allocator.free(zig_binary_path);
@@ -176,3 +185,56 @@ const Config = struct {
176185
self.allocator.free(self.contents);
177186
}
178187
};
188+
189+
// Caller frees the returned memory
190+
fn zon_minimum_version(allocator: std.mem.Allocator, zon_contents: [:0]u8) !?[]const u8 {
191+
var ast = try std.zig.Ast.parse(allocator, zon_contents, .zon);
192+
defer ast.deinit(allocator);
193+
194+
var ast_buf: [2]std.zig.Ast.Node.Index = undefined;
195+
const root = ast.fullStructInit(&ast_buf, ast.nodes.items(.data)[0].lhs) orelse return error.ZonParseError;
196+
197+
for (root.ast.fields) |field_idx| {
198+
const field_name = try parseFieldName(allocator, ast, field_idx);
199+
defer allocator.free(field_name);
200+
201+
if (std.mem.eql(u8, field_name, "minimum_zig_version")) {
202+
return try parseString(allocator, ast, field_idx);
203+
}
204+
}
205+
206+
return null;
207+
}
208+
209+
// Caller frees memory
210+
fn parseString(allocator: std.mem.Allocator, ast: std.zig.Ast, idx: std.zig.Ast.Node.Index) ![]const u8 {
211+
const node_tags = ast.nodes.items(.tag);
212+
const main_tokens = ast.nodes.items(.main_token);
213+
if (node_tags[idx] != .string_literal) {
214+
return error.ExpectedStringLiteral;
215+
}
216+
const str_lit_token = main_tokens[idx];
217+
const token_bytes = ast.tokenSlice(str_lit_token);
218+
return try parseStrLit(allocator, token_bytes, 0);
219+
}
220+
221+
// Caller frees memory
222+
inline fn parseStrLit(
223+
allocator: std.mem.Allocator,
224+
bytes: []const u8,
225+
offset: u32,
226+
) ![]u8 {
227+
return try std.zig.string_literal.parseAlloc(allocator, bytes[offset..]);
228+
}
229+
230+
fn parseFieldName(
231+
alloc: std.mem.Allocator,
232+
ast: std.zig.Ast,
233+
idx: std.zig.Ast.Node.Index,
234+
) ![]const u8 {
235+
const name = ast.tokenSlice(ast.firstToken(idx) - 2);
236+
return if (name[0] == '@') // Escaping something, like @"hello bois"
237+
try std.zig.string_literal.parseAlloc(alloc, name[1..])
238+
else
239+
try alloc.dupe(u8, name);
240+
}

0 commit comments

Comments
 (0)