1const std = @import("std");
2const string = []const u8;
3const gpa = std.heap.c_allocator;
4const knownfolders = @import("known-folders");
5const extras = @import("extras");
6const nio = @import("nio");
7const nfs = @import("nfs");
8const root = @import("root");
9
10const zigmod = @import("./../lib.zig");
11const u = @import("./../util/funcs.zig");
12const common = @import("./../common.zig");
13
14pub fn execute(self_name: []const u8, args: []const [:0]const u8) !void {
15 _ = self_name;
16
17 if (args.len < 2) u.fail("usage: zigmod install [git|hg|http] [url]", .{});
18
19 const io = root.io;
20 const homepath = try knownfolders.getPath(io, gpa, root.environ, .home) orelse u.fail("failed to read HOME", .{});
21 const cache = try knownfolders.getPath(io, gpa, root.environ, .cache) orelse u.fail("failed to read XDG_CACHE_HOME", .{});
22 const datapath = try knownfolders.getPath(io, gpa, root.environ, .data) orelse u.fail("failed to read XDG_DATA_HOME", .{});
23
24 const RemoteType = enum {
25 git,
26 hg,
27 http,
28 };
29 const rty_s = args[0];
30 const rty = std.meta.stringToEnum(RemoteType, rty_s) orelse u.fail("usage: zigmod install [git|hg|http] [url]", .{});
31 const ty: zigmod.Dep.Type = switch (rty) {
32 .git => .git,
33 .hg => .hg,
34 .http => .http,
35 };
36 const dep: zigmod.Dep = .{
37 .type = ty,
38 .path = args[1],
39 .id = u.random_string(48),
40 .name = "(name)",
41 .main = "",
42 .version = "",
43 .c_include_dirs = &.{},
44 .c_source_flags = &.{},
45 .c_source_files = &.{},
46 .only_os = &.{},
47 .except_os = &.{},
48 .yaml = null,
49 .deps = &.{},
50 .keep = false,
51 .for_build = false,
52 };
53 const clean_path = try dep.clean_path(gpa);
54 const cachepath = try std.fs.path.joinZ(gpa, &.{ cache, "zigmod", "deps" });
55 const modpath = try std.fs.path.joinZ(gpa, &.{ cachepath, clean_path });
56 std.log.debug("modpath: {s}", .{modpath});
57
58 if (!try nfs.cwd().existsDir(modpath)) {
59 try dep.type.pull(gpa, dep.path, modpath);
60 } else {
61 try dep.type.update(gpa, modpath, "");
62 }
63
64 const moddir = try nfs.cwd().openDir(modpath, .{});
65 const ci = @import("./ci.zig");
66 try ci.do(gpa, cachepath, moddir);
67
68 const modfile = try zigmod.ModFile.from_dir(gpa, moddir, modpath);
69 const zigversion_sv = modfile.min_zig_version orelse u.fail("zigmod manifest requires min_zig_version field", .{});
70 const zigversion = try nio.fmt.allocPrint(gpa, "{s}", .{u.altSemanticVersion(zigversion_sv)});
71 const zigpath = try std.fs.path.joinZ(gpa, &.{ datapath, "zig", zigversion, "zig" });
72
73 // regen deps.zig with the repo's zig version
74 var fetch_options = common.CollectOptions{
75 .log = true,
76 .update = false,
77 .lock = try common.parse_lockfile(gpa, moddir),
78 .alloc = gpa,
79 };
80 const fetch_top_module = try common.collect_deps_deep(cachepath, moddir, &fetch_options);
81 var fetch_list = std.array_list.Managed(zigmod.Module).init(gpa);
82 try common.collect_pkgs(fetch_top_module, &fetch_list);
83 const V = struct { major: u32, minor: u32 };
84 const version_sct: V = .{ .major = @intCast(zigversion_sv.major), .minor = @intCast(zigversion_sv.minor) };
85 const version_int: u32 = (version_sct.major << 2) | version_sct.minor;
86 switch (version_int) {
87 0x0000_000b => try @import("./fetch.0.11.zig").create_depszig(gpa, cachepath, moddir, fetch_top_module, &fetch_list),
88 0x0000_000c => try @import("./fetch.0.12.zig").create_depszig(gpa, cachepath, moddir, fetch_top_module, &fetch_list),
89 0x0000_000d => try @import("./fetch.0.13.zig").create_depszig(gpa, cachepath, moddir, fetch_top_module, &fetch_list),
90 0x0000_000e => try @import("./fetch.0.14.zig").create_depszig(gpa, cachepath, moddir, fetch_top_module, &fetch_list),
91 0x0000_000f => try @import("./fetch.0.15.zig").create_depszig(gpa, cachepath, moddir, fetch_top_module, &fetch_list),
92 0x0000_0010 => {}, // that's us, zigmod is already 0.16.0
93 else => u.fail("zig {d}.{d} unimplemented", .{ version_sct.major, version_sct.minor }),
94 }
95
96 // zig build
97 const argv: []const string = &.{
98 zigpath, "build",
99 "--prefix", try std.fs.path.join(gpa, &.{ homepath, ".zigmod" }),
100 };
101 logargv(argv) catch return;
102 var proc = try std.process.spawn(io, .{
103 .argv = argv,
104 .cwd = .{ .path = modpath },
105 });
106 const term = try proc.wait(io);
107 switch (term) {
108 .exited => |v| u.assert(v == 0, "zig build failed with exit code: {d}", .{v}),
109 .signal => |v| u.fail("zig build was stopped with signal: {d}", .{v}),
110 .stopped => |v| u.fail("zig build was stopped with code: {d}", .{v}),
111 .unknown => |v| u.fail("zig build encountered unknown: {d}", .{v}),
112 }
113 std.log.info("success!", .{});
114}
115
116// needed this after moving to zig 0.15
117// /zig/0.15.2/lib/std/Io/Writer.zig:1122:51: error: expected type '[]const u8', found '[]const []const u8'
118fn logargv(argv: []const []const u8) !void {
119 const io = std.Options.debug_io;
120 const prev = io.swapCancelProtection(.blocked);
121 defer _ = io.swapCancelProtection(prev);
122 var buffer: [64]u8 = undefined;
123 const stderrterm = std.debug.lockStderr(&buffer).terminal();
124 defer std.debug.unlockStderr();
125 const stderr = stderrterm.writer;
126 try stderr.writeAll("debug: argv: {");
127 for (argv, 0..) |v, i| {
128 if (i > 0) try stderr.writeAll(",");
129 try stderr.writeAll(" ");
130 try stderr.writeAll(v);
131 }
132 try stderr.writeAll(" }\n");
133}