diff --git a/src/common.zig b/src/common.zig index 0b5da2bced65e248f969c514e4f44f28205f63f0..b418fdcc6245ca89ac46006840aeeff9e88b4e7c 100644 --- a/src/common.zig +++ b/src/common.zig @@ -7,24 +7,100 @@ const u = @import("./util/index.zig"); // // -pub fn collect_deps(dir: []const u8, mpath: []const u8) anyerror!u.Module { +pub const CollectOptions = struct { + log: bool, + update: bool, +}; + +pub fn collect_deps(dir: []const u8, mpath: []const u8, comptime options: CollectOptions) anyerror!u.Module { const m = try u.ModFile.init(gpa, mpath); const moduledeps = &std.ArrayList(u.Module).init(gpa); var moddir: []const u8 = undefined; for (m.deps) |d| { const p = try fs.path.join(gpa, &[_][]const u8{dir, try d.clean_path()}); - const pv = try fs.path.join(gpa, &[_][]const u8{dir, "v", try d.clean_path(), d.version}); - if (try u.does_file_exist(pv)) { - moddir = pv; - } else { - u.assert(try u.does_file_exist(p), "unable to find dep: {s} {s}, please run zigmod fetch", .{d.path, d.version}); - moddir = p; + const pv = try fs.path.join(gpa, &[_][]const u8{dir, try d.clean_path_v()}); + if (options.log) { u.print("fetch: {s}: {s}: {s}", .{m.name, @tagName(d.type), d.path}); } + moddir = p; + switch (d.type) { + .system_lib => { + // no op + }, + .git => blk: { + if (!try u.does_folder_exist(p)) { + try d.type.pull(d.path, p); + } + else { + if (options.update) { try d.type.update(p, d.path); } + } + if (d.version.len > 0) { + const vers = u.parse_split(u.GitVersionType, "-").do(d.version) catch |e| switch (e) { + error.IterEmpty => unreachable, + error.NoMemberFound => { + const vtype = d.version[0..std.mem.indexOf(u8, d.version, "-").?]; + u.assert(false, "fetch: git: version type '{s}' is invalid.", .{vtype}); + unreachable; + }, + }; + if (try u.does_folder_exist(pv)) { + if (vers.id == .branch) { + if (options.update) { try d.type.update(p, d.path); } + } + moddir = pv; + break :blk; + } + if ((try u.run_cmd(p, &[_][]const u8{"git", "checkout", vers.string})) > 0) { + u.assert(false, "fetch: git: {s}: {s} {s} does not exist", .{d.path, @tagName(vers.id), vers.string}); + } else { + _ = try u.run_cmd(p, &[_][]const u8{"git", "checkout", "-"}); + } + try d.type.pull(d.path, pv); + _ = try u.run_cmd(pv, &[_][]const u8{"git", "checkout", vers.string}); + if (vers.id != .branch) { + const pvd = try std.fs.cwd().openDir(pv, .{}); + try pvd.deleteTree(".git"); + } + moddir = pv; + } + }, + .hg => { + if (!try u.does_folder_exist(p)) { + try d.type.pull(d.path, p); + } + else { + if (options.update) { try d.type.update(p, d.path); } + } + }, + .http => blk: { + if (try u.does_folder_exist(pv)) { + moddir = pv; + break :blk; + } + const file_name = try u.last(try u.split(d.path, "/")); + if (d.version.len > 0) { + const file_path = try std.fs.path.join(gpa, &[_][]const u8{pv, file_name}); + try d.type.pull(d.path, pv); + if (try u.validate_hash(try u.last(try u.split(pv, "/")), file_path)) { + try std.fs.deleteFileAbsolute(file_path); + moddir = pv; + break :blk; + } + try u.rm_recv(pv); + u.assert(false, "{s} does not match hash {s}", .{d.path, d.version}); + break :blk; + } + if (try u.does_folder_exist(p)) { + try u.rm_recv(p); + } + const file_path = try std.fs.path.join(gpa, &[_][]const u8{p, file_name}); + try d.type.pull(d.path, p); + try std.fs.deleteFileAbsolute(file_path); + }, } switch (d.type) { .system_lib => { if (d.is_for_this()) try moduledeps.append(u.Module{ .is_sys_lib = true, - .id = d.id, + .id = "", .name = d.path, .only_os = d.only_os, .except_os = d.except_os, @@ -33,13 +109,13 @@ pub fn collect_deps(dir: []const u8, mpath: []const u8) anyerror!u.Module { .c_source_flags = &[_][]const u8{}, .c_source_files = &[_][]const u8{}, .deps = &[_]u.Module{}, - .clean_path = "", + .clean_path = d.path, }); }, else => blk: { - var dd = try collect_deps(dir, try u.concat(&[_][]const u8{moddir, "/zig.mod"})) catch |e| switch (e) { + var dd = try collect_deps(dir, try u.concat(&[_][]const u8{moddir, "/zig.mod"}), options) catch |e| switch (e) { error.FileNotFound => { - if (d.c_include_dirs.len > 0 or d.c_source_files.len > 0) { + if (d.main.len > 0 or d.c_include_dirs.len > 0 or d.c_source_files.len > 0) { var mod_from = try u.Module.from(d); mod_from.id = try u.random_string(48); mod_from.clean_path = u.trim_prefix(moddir, dir)[1..];