authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-06-01 19:46:37 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-06-01 19:46:37 -07:00
log350281d9ee6729e4ab98498ddb4671b3faf70b6a
tree514a42a69bf59c57dc2c45ef09b6a4f4750f3f66
parentfbd6a16088d32e3f8c674e8cf8f266a02fca270c
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

cmd/install: add 0.13 support


2 files changed, 422 insertions(+), 0 deletions(-)

src/cmd/fetch.0.13.zig created+421
......@@ -0,0 +1,421 @@
1// Adapted from https://github.com/nektro/zigmod/blob/r95/src/cmd/fetch.zig
2
3const std = @import("std");
4const string = []const u8;
5const ansi = @import("ansi");
6const extras = @import("extras");
7const nfs = @import("nfs");
8
9const zigmod = @import("../lib.zig");
10const u = @import("./../util/funcs.zig");
11const common = @import("./../common.zig");
12const license = @import("./license.zig");
13
14pub fn create_depszig(alloc: std.mem.Allocator, cachepath: string, dir: nfs.Dir, top_module: zigmod.Module, list: *std.array_list.Managed(zigmod.Module)) !void {
15 const f = try dir.createFile("deps.zig", .{});
16 defer f.close();
17
18 const w = f;
19 try w.writeAll("// zig fmt: off\n");
20 try w.writeAll("const std = @import(\"std\");\n");
21 try w.writeAll("const builtin = @import(\"builtin\");\n");
22 try w.writeAll("const string = []const u8;\n");
23 try w.writeAll("\n");
24 try w.print("pub const cache = \"{}\";\n", .{u.altStringEscape(cachepath)});
25 try w.writeAll("\n");
26 try w.writeAll(
27 \\pub fn addAllTo(exe: *std.Build.Step.Compile) void {
28 \\ checkMinZig(builtin.zig_version, exe);
29 \\ @setEvalBranchQuota(1_000_000);
30 \\ for (packages) |pkg| {
31 \\ const module = pkg.module(exe);
32 \\ exe.root_module.addImport(pkg.import.?[0], module);
33 \\ }
34 \\ for (package_data._root.system_libs) |libname| {
35 \\ exe.linkSystemLibrary(libname);
36 \\ exe.linkLibC();
37 \\ }
38 \\ // clear module memo cache so addAllTo can be called more than once in the same build.zig
39 \\ inline for (comptime std.meta.declarations(package_data)) |decl| @field(package_data, decl.name).module_memo = null;
40 \\}
41 \\
42 \\var link_lib_c = false;
43 \\pub const Package = struct {
44 \\ directory: string,
45 \\ import: ?struct { string, std.Build.LazyPath } = null,
46 \\ dependencies: []const *Package,
47 \\ c_include_dirs: []const string = &.{},
48 \\ c_source_files: []const string = &.{},
49 \\ c_source_flags: []const string = &.{},
50 \\ system_libs: []const string = &.{},
51 \\ frameworks: []const string = &.{},
52 \\ module_memo: ?*std.Build.Module = null,
53 \\
54 \\ pub fn module(self: *Package, exe: *std.Build.Step.Compile) *std.Build.Module {
55 \\ if (self.module_memo) |cached| {
56 \\ return cached;
57 \\ }
58 \\ const b = exe.step.owner;
59 \\ const result = b.createModule(.{
60 \\ .target = exe.root_module.resolved_target orelse b.host,
61 \\ });
62 \\ if (self.import) |capture| {
63 \\ result.root_source_file = capture[1];
64 \\ }
65 \\ for (self.dependencies) |item| {
66 \\ const module_dep = item.module(exe);
67 \\ if (module_dep.root_source_file != null) {
68 \\ result.addImport(item.import.?[0], module_dep);
69 \\ }
70 \\ for (module_dep.include_dirs.items) |jtem| {
71 \\ switch (jtem) {
72 \\ .path => result.addIncludePath(jtem.path),
73 \\ .path_system, .path_after, .framework_path, .framework_path_system, .other_step, .config_header_step => {},
74 \\ }
75 \\ }
76 \\ }
77 \\ for (self.c_include_dirs) |item| {
78 \\ result.addIncludePath(.{ .cwd_relative = (b.fmt("{s}/{s}", .{ self.directory, item })) });
79 \\ exe.addIncludePath(.{ .cwd_relative = (b.fmt("{s}/{s}", .{ self.directory, item })) });
80 \\ link_lib_c = true;
81 \\ }
82 \\ for (self.c_source_files) |item| {
83 \\ exe.addCSourceFile(.{ .file = .{ .cwd_relative = (b.fmt("{s}/{s}", .{ self.directory, item })) }, .flags = self.c_source_flags });
84 \\ link_lib_c = true;
85 \\ }
86 \\ for (self.system_libs) |item| {
87 \\ result.linkSystemLibrary(item, .{});
88 \\ exe.linkSystemLibrary(item);
89 \\ link_lib_c = true;
90 \\ }
91 \\ for (self.frameworks) |item| {
92 \\ result.linkFramework(item, .{});
93 \\ exe.linkFramework(item);
94 \\ link_lib_c = true;
95 \\ }
96 \\ if (link_lib_c) {
97 \\ result.link_libc = true;
98 \\ exe.linkLibC();
99 \\ }
100 \\ self.module_memo = result;
101 \\ return result;
102 \\ }
103 \\};
104 \\
105 \\
106 );
107
108 try w.print(
109 \\fn checkMinZig(current: std.SemanticVersion, exe: *std.Build.Step.Compile) void {{
110 \\ const min = std.SemanticVersion.parse("{?}") catch return;
111 \\ if (current.order(min).compare(.lt)) @panic(exe.step.owner.fmt("Your Zig version v{{}} does not meet the minimum build requirement of v{{}}", .{{current, min}}));
112 \\}}
113 \\
114 \\
115 , .{if (top_module.minZigVersion()) |sv| u.altSemanticVersion(sv) else null});
116
117 try w.writeAll("pub const dirs = struct {\n");
118 try print_dirs(w, list.items, alloc);
119 try w.writeAll("};\n\n");
120
121 try w.writeAll("pub const package_data = struct {\n");
122 var duped = std.array_list.Managed(zigmod.Module).init(alloc);
123 var done = std.array_list.Managed(zigmod.Module).init(alloc);
124 for (list.items) |mod| {
125 if (mod.type == .system_lib or mod.type == .framework) {
126 continue;
127 }
128 try duped.append(mod);
129 }
130 try print_pkg_data_to(w, &duped, &done);
131 try w.writeAll("};\n\n");
132
133 try w.writeAll("pub const packages = ");
134 try print_deps(w, top_module);
135 try w.writeAll(";\n\n");
136
137 try w.writeAll("pub const pkgs = ");
138 try print_pkgs(alloc, w, top_module);
139 try w.writeAll(";\n\n");
140
141 try w.writeAll("pub const imports = struct {\n");
142 try print_imports(alloc, w, top_module, cachepath);
143 try w.writeAll("};\n");
144}
145
146fn create_lockfile(alloc: std.mem.Allocator, list: *std.array_list.Managed(zigmod.Module), path: string, dir: nfs.Dir) !void {
147 const fl = try dir.createFile("zigmod.lock", .{});
148 defer fl.close();
149
150 std.mem.sort(zigmod.Module, list.items, {}, zigmod.Module.lessThan);
151
152 const wl = fl.writer();
153 try wl.writeAll("2\n");
154 for (list.items) |m| {
155 if (m.dep) |md| {
156 if (md.type.isLocal()) continue;
157 const mpath = try std.fs.path.join(alloc, &.{ path, m.clean_path });
158 const version = try md.exact_version(alloc, mpath);
159 try wl.print("{s} {s} {s}\n", .{ @tagName(md.type), md.path, version });
160 }
161 }
162}
163
164const DiffChange = struct {
165 from: string,
166 to: string,
167};
168
169fn diff_lockfile(alloc: std.mem.Allocator) !void {
170 const max = std.math.maxInt(usize);
171
172 if (try extras.doesFolderExist(null, ".git")) {
173 const result = try u.run_cmd_raw(alloc, null, &.{ "git", "diff", "zigmod.lock" });
174 var stdout = std.io.fixedBufferStream(result.stdout);
175 const r = stdout.reader();
176 while (try r.readUntilDelimiterOrEofAlloc(alloc, '\n', max)) |line| {
177 if (std.mem.startsWith(u8, line, "@@")) break;
178 }
179
180 var rems = std.array_list.Managed(string).init(alloc);
181 var adds = std.array_list.Managed(string).init(alloc);
182 while (try r.readUntilDelimiterOrEofAlloc(alloc, '\n', max)) |line| {
183 if (line[0] == ' ') continue;
184 if (line[0] == '-') try rems.append(line[1..]);
185 if (line[0] == '+') if (line[1] == '2') break else try adds.append(line[1..]);
186 }
187
188 var changes = std.StringHashMap(DiffChange).init(alloc);
189
190 var didbreak = false;
191 var i: usize = 0;
192 while (i < rems.items.len) {
193 const it = rems.items[i];
194 const sni = u.indexOfN(it, ' ', 2).?;
195
196 var j: usize = 0;
197 while (j < adds.items.len) {
198 const jt = adds.items[j];
199 const snj = u.indexOfN(jt, ' ', 2).?;
200
201 if (std.mem.eql(u8, it[0..sni], jt[0..snj])) {
202 try changes.put(it[0..sni], .{
203 .from = it[u.indexOfAfter(it, '-', sni).? + 1 .. it.len],
204 .to = jt[u.indexOfAfter(jt, '-', snj).? + 1 .. jt.len],
205 });
206 _ = rems.orderedRemove(i);
207 _ = adds.orderedRemove(j);
208 didbreak = true;
209 break;
210 }
211 if (!didbreak) j += 1;
212 }
213 if (!didbreak) i += 1;
214 if (didbreak) didbreak = false;
215 }
216
217 if (adds.items.len > 0) {
218 std.debug.print(comptime ansi.color.Faint("Newly added packages:\n"), .{});
219 defer std.debug.print("\n", .{});
220
221 for (adds.items) |it| {
222 std.debug.print("- {s}\n", .{it});
223 }
224 }
225
226 if (rems.items.len > 0) {
227 std.debug.print(comptime ansi.color.Faint("Removed packages:\n"), .{});
228 defer std.debug.print("\n", .{});
229
230 for (rems.items) |it| {
231 std.debug.print("- {s}\n", .{it});
232 }
233 }
234
235 if (changes.unmanaged.size > 0) std.debug.print(comptime ansi.color.Faint("Updated packages:\n"), .{});
236 var iter = changes.iterator();
237 while (iter.next()) |it| {
238 if (diff_printchange("git https://github.com", "- {s}/compare/{s}...{s}\n", it)) continue;
239 if (diff_printchange("git https://gitlab.com", "- {s}/-/compare/{s}...{s}\n", it)) continue;
240 if (diff_printchange("git https://gitea.com", "- {s}/compare/{s}...{s}\n", it)) continue;
241
242 std.debug.print("- {s}\n", .{it.key_ptr.*});
243 std.debug.print(" - {s} ... {s}\n", .{ it.value_ptr.from, it.value_ptr.to });
244 }
245 }
246}
247
248fn diff_printchange(comptime testt: string, comptime replacement: string, item: std.StringHashMap(DiffChange).Entry) bool {
249 if (std.mem.startsWith(u8, item.key_ptr.*, testt)) {
250 if (std.mem.eql(u8, item.value_ptr.from, item.value_ptr.to)) return true;
251 std.debug.print(replacement, .{ item.key_ptr.*[4..], item.value_ptr.from, item.value_ptr.to });
252 return true;
253 }
254 return false;
255}
256
257fn print_dirs(w: nfs.File, list: []const zigmod.Module, alloc: std.mem.Allocator) !void {
258 for (list) |mod| {
259 if (mod.type == .system_lib or mod.type == .framework) continue;
260 if (std.mem.eql(u8, &mod.id, &zigmod.Module.ROOT)) {
261 try w.writeAll(" pub const _root = \"\";\n");
262 continue;
263 }
264 if (std.mem.eql(u8, mod.clean_path, "../..")) {
265 const cwd_realpath = try std.fs.cwd().realpathAlloc(alloc, ".");
266 try w.print(" pub const _{s} = \"{}\";\n", .{ mod.short_id(), u.altStringEscape(cwd_realpath) });
267 continue;
268 }
269 try w.print(" pub const _{s} = cache ++ \"/{}\";\n", .{ mod.short_id(), u.altStringEscape(mod.clean_path) });
270 }
271}
272
273fn print_deps(w: nfs.File, m: zigmod.Module) !void {
274 try w.writeAll("&[_]*Package{\n");
275 for (m.deps) |d| {
276 if (d.main.len == 0) {
277 continue;
278 }
279 if (d.for_build) {
280 continue;
281 }
282 try w.print(" &package_data._{s},\n", .{d.id[0..12]});
283 }
284 try w.writeAll("}");
285}
286
287fn print_pkg_data_to(w: nfs.File, notdone: *std.array_list.Managed(zigmod.Module), done: *std.array_list.Managed(zigmod.Module)) !void {
288 var len: usize = notdone.items.len;
289 while (notdone.items.len > 0) {
290 for (notdone.items, 0..) |mod, i| {
291 if (contains_all(mod.deps, done.items)) {
292 try w.print(
293 \\ pub var _{s} = Package{{
294 \\ .directory = dirs._{s},
295 \\
296 , .{
297 mod.short_id(),
298 mod.short_id(),
299 });
300 if (mod.main.len > 0 and !std.mem.eql(u8, &mod.id, &zigmod.Module.ROOT)) {
301 try w.print(
302 \\ .import = .{{ "{s}", .{{ .cwd_relative = dirs._{s} ++ "/{s}" }} }},
303 \\
304 , .{
305 mod.name,
306 mod.short_id(),
307 mod.main,
308 });
309 }
310 {
311 try w.writeAll(" .dependencies =");
312 try w.writeAll(" &.{");
313 for (mod.deps, 0..) |moddep, j| {
314 if (moddep.type == .system_lib) continue;
315 if (moddep.type == .framework) continue;
316 try w.print(" &_{s}", .{moddep.id[0..12]});
317 if (j != mod.deps.len - 1) try w.writeAll(",");
318 }
319 try w.writeAll(" },\n");
320 }
321 if (mod.c_include_dirs.len > 0) {
322 try w.writeAll(" .c_include_dirs = &.{");
323 for (mod.c_include_dirs, 0..) |item, j| {
324 try w.print(" \"{}\"", .{u.altStringEscape(item)});
325 if (j != mod.c_include_dirs.len - 1) try w.writeAll(",");
326 }
327 try w.writeAll(" },\n");
328 }
329 if (mod.c_source_files.len > 0) {
330 try w.writeAll(" .c_source_files = &.{");
331 for (mod.c_source_files, 0..) |item, j| {
332 try w.print(" \"{}\"", .{u.altStringEscape(item)});
333 if (j != mod.c_source_files.len - 1) try w.writeAll(",");
334 }
335 try w.writeAll(" },\n");
336 }
337 if (mod.c_source_flags.len > 0) {
338 try w.writeAll(" .c_source_flags = &.{");
339 for (mod.c_source_flags, 0..) |item, j| {
340 try w.print(" \"{}\"", .{u.altStringEscape(item)});
341 if (j != mod.c_source_flags.len - 1) try w.writeAll(",");
342 }
343 try w.writeAll(" },\n");
344 }
345 if (mod.has_syslib_deps()) {
346 try w.writeAll(" .system_libs = &.{");
347 for (mod.deps, 0..) |item, j| {
348 if (!(item.type == .system_lib)) continue;
349 try w.print(" \"{}\"", .{u.altStringEscape(item.name)});
350 if (j != mod.deps.len - 1) try w.writeAll(",");
351 }
352 try w.writeAll(" },\n");
353 }
354 if (mod.has_framework_deps()) {
355 try w.writeAll(" .frameworks = &.{");
356 for (mod.deps, 0..) |item, j| {
357 if (!(item.type == .system_lib)) continue;
358 try w.print(" \"{}\"", .{u.altStringEscape(item.name)});
359 if (j != mod.deps.len - 1) try w.writeAll(",");
360 }
361 try w.writeAll(" },\n");
362 }
363 try w.writeAll(" };\n");
364
365 try done.append(mod);
366 _ = notdone.orderedRemove(i);
367 break;
368 }
369 }
370 if (notdone.items.len == len) {
371 u.fail("notdone still has {d} items", .{len});
372 }
373 len = notdone.items.len;
374 }
375}
376
377/// returns if all of the zig modules in needles are in haystack
378fn contains_all(needles: []zigmod.Module, haystack: []const zigmod.Module) bool {
379 for (needles) |item| {
380 if (item.main.len > 0 and !extras.containsAggregate(zigmod.Module, haystack, item)) {
381 return false;
382 }
383 }
384 return true;
385}
386
387fn print_pkgs(alloc: std.mem.Allocator, w: nfs.File, m: zigmod.Module) !void {
388 try w.writeAll("struct {\n");
389 for (m.deps) |d| {
390 if (d.main.len == 0) {
391 continue;
392 }
393 if (d.for_build) {
394 continue;
395 }
396 const ident = try zig_name_from_pkg_name(alloc, d.name);
397 try w.print(" pub const {s} = &package_data._{s};\n", .{ ident, d.id[0..12] });
398 }
399 try w.writeAll("}");
400}
401
402fn print_imports(alloc: std.mem.Allocator, w: nfs.File, m: zigmod.Module, path: string) !void {
403 for (m.deps) |d| {
404 if (d.main.len == 0) {
405 continue;
406 }
407 if (!d.for_build) {
408 continue;
409 }
410 const ident = try zig_name_from_pkg_name(alloc, d.name);
411 try w.print(" pub const {s} = @import(\"{}/{}/{s}\");\n", .{ ident, u.altStringEscape(path), u.altStringEscape(d.clean_path), d.main });
412 }
413}
414
415fn zig_name_from_pkg_name(alloc: std.mem.Allocator, name: string) !string {
416 var legal = name;
417 legal = try std.mem.replaceOwned(u8, alloc, legal, "-", "_");
418 legal = try std.mem.replaceOwned(u8, alloc, legal, "/", "_");
419 legal = try std.mem.replaceOwned(u8, alloc, legal, ".", "_");
420 return legal;
421}
src/cmd/install.zig+1
......@@ -82,6 +82,7 @@ pub fn execute(self_name: []const u8, args: [][:0]u8) !void {
8282 const version_sct: V = .{ .major = @intCast(zigversion_sv.major), .minor = @intCast(zigversion_sv.minor) };
8383 const version_int: u32 = (version_sct.major << 2) | version_sct.minor;
8484 switch (version_int) {
85 0x0000_000d => try @import("./fetch.0.13.zig").create_depszig(gpa, cachepath, moddir, fetch_top_module, &fetch_list),
8586 0x0000_000e => try @import("./fetch.0.14.zig").create_depszig(gpa, cachepath, moddir, fetch_top_module, &fetch_list),
8687 0x0000_000f => {}, // that's us, zigmod is already 0.15.2
8788 else => u.fail("zig {d}.{d} unimplemented", .{ version_sct.major, version_sct.minor }),