diff --git a/README.md b/README.md index 8689d11..741d9c3 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ ##### sorted by Precedence - zig.ver: A file that contains the zig version, nothing more. +- build.zig.zon: More specifically the minimum_zig_version option - (zigd directory)/config ### In the config there is also an order @@ -49,6 +50,10 @@ default=0.13.0 ### 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 +## Build + +### `zig build` + ## An Example Usage ``` diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..b31e289 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,12 @@ +.{ + .name = "zigd", + .version = "0.0.2", + .minimum_zig_version = "0.13.0", + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + "LICENSE", + "README.md", + }, +} diff --git a/src/utils.zig b/src/utils.zig index 8b8ec09..71e37a3 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -58,6 +58,20 @@ pub inline fn createDirectoryIgnoreExist(path: []const u8) !void { }; } +pub inline fn existsReadFileCwd(allocator: std.mem.Allocator, cwd_path: []const u8) !?[]u8 { + return std.fs.cwd().readFileAlloc(allocator, cwd_path, std.math.maxInt(usize)) catch |e| switch (e) { + std.fs.File.OpenError.FileNotFound => null, + else => e, + }; +} + +pub inline fn existsReadFileCwdSentinel(allocator: std.mem.Allocator, cwd_path: [:0]const u8) !?[:0]u8 { + return std.fs.cwd().readFileAllocOptions(allocator, cwd_path, std.math.maxInt(usize), null, 1, 0) catch |e| switch (e) { + std.fs.File.OpenError.FileNotFound => null, + else => e, + }; +} + pub inline fn createDirectoryIfNotExist(path: []const u8) !void { try std.fs.cwd().makePath(path); } diff --git a/src/zigd.version b/src/zigd.version index 8a9ecc2..7bcd0e3 100644 --- a/src/zigd.version +++ b/src/zigd.version @@ -1 +1 @@ -0.0.1 \ No newline at end of file +0.0.2 \ No newline at end of file diff --git a/src/zigdcli.zig b/src/zigdcli.zig index bf2b8b8..f5c405d 100644 --- a/src/zigdcli.zig +++ b/src/zigdcli.zig @@ -67,7 +67,7 @@ fn install(allocator: std.mem.Allocator, args: []const []const u8) !void { } var zig_version = try zigdcore.ZigVersion.parse(allocator, args[2], &user_arg, false); - defer zig_version.deinitIfMasterOrZigver(allocator); + defer zig_version.deinitIfMasterOrZigverOrZonver(allocator); try std.io.getStdOut().writer().print("Installing zig version {s}\n", .{zig_version}); @@ -95,7 +95,7 @@ fn exists(allocator: std.mem.Allocator, args: []const []const u8) !void { defer allocator.free(zigd_path); var zig_version = try zigdcore.ZigVersion.parse(allocator, args[2], &user_arg, false); - defer zig_version.deinitIfMasterOrZigver(allocator); + defer zig_version.deinitIfMasterOrZigverOrZonver(allocator); const version_path = try std.fs.path.join(allocator, &.{ zigd_path, "versions", args[2] }); defer allocator.free(version_path); diff --git a/src/zigdcore.zig b/src/zigdcore.zig index 822e61c..d31e04e 100644 --- a/src/zigdcore.zig +++ b/src/zigdcore.zig @@ -49,19 +49,19 @@ pub fn install_zig(allocator: std.mem.Allocator, download_url: []const u8, insta const w_path_duped = try allocator.dupe(u8, w_path.name); defer allocator.free(w_path_duped); - if ((try tempstrg.next()) != null) + if ((try tempstrg.next()) != null) return error.InstallationWasSabotaged; try temporary_storage.rename(w_path_duped, final_destination); temporary_storage.close(); try std.fs.cwd().deleteDir(temp_name); - } else { + } else { var final_dest_dir = try std.fs.openDirAbsolute(final_destination, .{}); defer final_dest_dir.close(); var xz_decompressor = try std.compress.xz.decompress(allocator, req.reader()); defer xz_decompressor.deinit(); - + try std.tar.pipeToFileSystem(final_dest_dir, xz_decompressor.reader(), .{ .strip_components = 1 }); } return; @@ -121,9 +121,10 @@ pub const ZigVersion = struct { pub const Source = union(enum) { UserArg, // Zigd Cli exclusive - Zigver, - WorkspaceVer, - DefaultVer, + Zigver, // zig.ver file + Zonver, // build.zig.zon, minimum_zig_version field + WorkspaceVer, // config, path + DefaultVer, // config, default Master: *Source, }; @@ -164,9 +165,9 @@ pub const ZigVersion = struct { } } - pub fn deinitIfMasterOrZigver(self: @This(), allocator: std.mem.Allocator) void { + pub fn deinitIfMasterOrZigverOrZonver(self: @This(), allocator: std.mem.Allocator) void { switch (self.source) { - .Master, .Zigver => allocator.free(self.as_string), + .Master, .Zigver, .Zonver => allocator.free(self.as_string), else => {}, } } @@ -186,7 +187,7 @@ pub fn getZigdPath(allocator: std.mem.Allocator) ![]u8 { break :v try std.fs.path.join(allocator, &.{ userprofile, ".zigd" }); } } - + if (env_map.get("HOME")) |home| { break :v try std.fs.path.join(allocator, &.{ home, ".zigd" }); } diff --git a/src/zigdemu.zig b/src/zigdemu.zig index bb33ceb..dddc8d6 100644 --- a/src/zigdemu.zig +++ b/src/zigdemu.zig @@ -22,39 +22,48 @@ pub fn main() !void { defer config.deinit(); var zig_version: zigdcore.ZigVersion = v: { - const zig_ver = std.fs.cwd().readFileAlloc(allocator, "zig.ver", 1 << 21) catch |e| switch (e) { - std.fs.File.OpenError.FileNotFound => { - const absolute_cwd = try std.fs.cwd().realpathAlloc(allocator, "."); - defer allocator.free(absolute_cwd); - - if (config.recursive_search_for_workspace_version(absolute_cwd)) |workspace_version| { - break :v zigdcore.ZigVersion{ - .as_string = workspace_version, - .source = .WorkspaceVer, - }; - } - - if (config.default) |default_version| { - break :v zigdcore.ZigVersion{ - .as_string = default_version, - .source = .DefaultVer, - }; - } - - std.log.err("No default, workspace, or zig.ver version was found.", .{}); - return; - }, - else => return e, - }; + if (try utils.existsReadFileCwd(allocator, "zig.ver")) |zig_ver| { + // Can't error so no need for errdefer in this scope + break :v zigdcore.ZigVersion{ + .as_string = zig_ver, + .source = .Zigver, + }; + } - break :v zigdcore.ZigVersion{ - .as_string = zig_ver, - .source = .Zigver, - }; + if (try utils.existsReadFileCwdSentinel(allocator, "build.zig.zon")) |build_zig_zon| { + defer allocator.free(build_zig_zon); + + if (try zon_minimum_version(allocator, build_zig_zon)) |zonver| { + break :v zigdcore.ZigVersion{ + .as_string = zonver, + .source = .Zonver, + }; + } + } + + const absolute_cwd = try std.fs.cwd().realpathAlloc(allocator, "."); + defer allocator.free(absolute_cwd); + + if (config.recursive_search_for_workspace_version(absolute_cwd)) |workspace_version| { + break :v zigdcore.ZigVersion{ + .as_string = workspace_version, + .source = .WorkspaceVer, + }; + } + + if (config.default) |default_version| { + break :v zigdcore.ZigVersion{ + .as_string = default_version, + .source = .DefaultVer, + }; + } + + std.log.err("No default, workspace, or zig.ver version was found.", .{}); + return; }; zig_version = try zigdcore.ZigVersion.parse(allocator, zig_version.as_string, &zig_version.source, true); - defer zig_version.deinitIfMasterOrZigver(allocator); + defer zig_version.deinitIfMasterOrZigverOrZonver(allocator); const zig_binary_path = try std.fs.path.join(allocator, &.{ zigd_path, "versions", zig_version.as_string, "zig" ++ utils.binary_ext }); defer allocator.free(zig_binary_path); @@ -176,3 +185,56 @@ const Config = struct { self.allocator.free(self.contents); } }; + +// Caller frees the returned memory +fn zon_minimum_version(allocator: std.mem.Allocator, zon_contents: [:0]u8) !?[]const u8 { + var ast = try std.zig.Ast.parse(allocator, zon_contents, .zon); + defer ast.deinit(allocator); + + var ast_buf: [2]std.zig.Ast.Node.Index = undefined; + const root = ast.fullStructInit(&ast_buf, ast.nodes.items(.data)[0].lhs) orelse return error.ZonParseError; + + for (root.ast.fields) |field_idx| { + const field_name = try parseFieldName(allocator, ast, field_idx); + defer allocator.free(field_name); + + if (std.mem.eql(u8, field_name, "minimum_zig_version")) { + return try parseString(allocator, ast, field_idx); + } + } + + return null; +} + +// Caller frees memory +fn parseString(allocator: std.mem.Allocator, ast: std.zig.Ast, idx: std.zig.Ast.Node.Index) ![]const u8 { + const node_tags = ast.nodes.items(.tag); + const main_tokens = ast.nodes.items(.main_token); + if (node_tags[idx] != .string_literal) { + return error.ExpectedStringLiteral; + } + const str_lit_token = main_tokens[idx]; + const token_bytes = ast.tokenSlice(str_lit_token); + return try parseStrLit(allocator, token_bytes, 0); +} + +// Caller frees memory +inline fn parseStrLit( + allocator: std.mem.Allocator, + bytes: []const u8, + offset: u32, +) ![]u8 { + return try std.zig.string_literal.parseAlloc(allocator, bytes[offset..]); +} + +fn parseFieldName( + alloc: std.mem.Allocator, + ast: std.zig.Ast, + idx: std.zig.Ast.Node.Index, +) ![]const u8 { + const name = ast.tokenSlice(ast.firstToken(idx) - 2); + return if (name[0] == '@') // Escaping something, like @"hello bois" + try std.zig.string_literal.parseAlloc(alloc, name[1..]) + else + try alloc.dupe(u8, name); +}