| 1 | const std = @import("std"); |
| 2 | const string = []const u8; |
| 3 | const builtin = @import("builtin"); |
| 4 | const yaml = @import("yaml"); |
| 5 | const extras = @import("extras"); |
| 6 | const nio = @import("nio"); |
| 7 | const nfs = @import("nfs"); |
| 8 | |
| 9 | const zigmod = @import("../lib.zig"); |
| 10 | const u = @import("funcs.zig"); |
| 11 | const common = @import("./../common.zig"); |
| 12 | |
| 13 | // |
| 14 | // |
| 15 | |
| 16 | pub const Module = struct { |
| 17 | type: zigmod.Dep.Type, |
| 18 | id: [48]u8, |
| 19 | name: string, |
| 20 | main: string, |
| 21 | c_include_dirs: []const string = &.{}, |
| 22 | c_source_flags: []const string = &.{}, |
| 23 | c_source_files: []const string = &.{}, |
| 24 | only_os: []const string = &.{}, |
| 25 | except_os: []const string = &.{}, |
| 26 | yaml: ?yaml.Mapping, |
| 27 | deps: []Module, |
| 28 | clean_path: [:0]const u8, |
| 29 | dep: ?zigmod.Dep, |
| 30 | for_build: bool = false, |
| 31 | min_zig_version: ?std.SemanticVersion, |
| 32 | |
| 33 | pub const ROOT: [48]u8 = ("root" ++ (" " ** 44)).*; |
| 34 | |
| 35 | pub fn from(alloc: std.mem.Allocator, dep: zigmod.Dep, cachepath: [:0]const u8, options: *common.CollectOptions) !Module { |
| 36 | var moddeps = std.array_list.Managed(Module).init(alloc); |
| 37 | errdefer moddeps.deinit(); |
| 38 | |
| 39 | for (dep.deps) |*d| { |
| 40 | if (try common.get_module_from_dep(d, cachepath, options)) |founddep| { |
| 41 | try moddeps.append(founddep); |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | var id = dep.id; |
| 46 | if (std.mem.eql(u8, &id, &zigmod.Dep.EMPTY)) id = u.random_string(48); |
| 47 | |
| 48 | return Module{ |
| 49 | .type = dep.type, |
| 50 | .id = id, |
| 51 | .name = dep.name, |
| 52 | .main = dep.main, |
| 53 | .c_include_dirs = dep.c_include_dirs, |
| 54 | .c_source_flags = dep.c_source_flags, |
| 55 | .c_source_files = dep.c_source_files, |
| 56 | .deps = try moddeps.toOwnedSlice(), |
| 57 | .clean_path = try dep.clean_path(alloc), |
| 58 | .only_os = dep.only_os, |
| 59 | .except_os = dep.except_os, |
| 60 | .yaml = dep.yaml, |
| 61 | .dep = dep, |
| 62 | .for_build = dep.for_build, |
| 63 | .min_zig_version = null, |
| 64 | }; |
| 65 | } |
| 66 | |
| 67 | pub fn eql(self: Module, another: Module) bool { |
| 68 | return std.mem.eql(u8, &self.id, &another.id); |
| 69 | } |
| 70 | |
| 71 | pub fn get_hash(self: Module, alloc: std.mem.Allocator, cdpath: string) !string { |
| 72 | const file_list_1 = try u.file_list(alloc, try std.mem.concatWithSentinel(alloc, u8, &.{ cdpath, "/", self.clean_path }, 0)); |
| 73 | |
| 74 | var file_list_2 = std.array_list.Managed(string).init(alloc); |
| 75 | errdefer file_list_2.deinit(); |
| 76 | for (file_list_1) |item| { |
| 77 | const _a = extras.trimPrefix(item, cdpath); |
| 78 | const _b = extras.trimPrefix(_a, self.clean_path); |
| 79 | if (_b[0] == '.') continue; |
| 80 | try file_list_2.append(_b); |
| 81 | } |
| 82 | |
| 83 | std.mem.sort(string, file_list_2.items, void{}, struct { |
| 84 | pub fn lt(context: void, lhs: string, rhs: string) bool { |
| 85 | _ = context; |
| 86 | return std.mem.lessThan(u8, lhs, rhs); |
| 87 | } |
| 88 | }.lt); |
| 89 | |
| 90 | var h = std.crypto.hash.Blake3.init(.{}); |
| 91 | for (file_list_2.items) |item| { |
| 92 | const abs_path = try std.fs.path.joinZ(alloc, &.{ cdpath, self.clean_path, item }); |
| 93 | const file = try nfs.cwd().openFile(abs_path, .{}); |
| 94 | defer file.close(); |
| 95 | const input = try file.readAllAlloc(alloc, u.mb * 100); |
| 96 | h.update(input); |
| 97 | } |
| 98 | var out: [32]u8 = undefined; |
| 99 | h.final(&out); |
| 100 | const hex = try nio.fmt.allocPrint(alloc, "blake3-{s}", .{&extras.to_hex(out)}); |
| 101 | return hex; |
| 102 | } |
| 103 | |
| 104 | pub fn is_for_this(self: Module) bool { |
| 105 | const os = @tagName(builtin.os.tag); |
| 106 | if (self.only_os.len > 0) { |
| 107 | return extras.containsString(self.only_os, os); |
| 108 | } |
| 109 | if (self.except_os.len > 0) { |
| 110 | return !extras.containsString(self.except_os, os); |
| 111 | } |
| 112 | return true; |
| 113 | } |
| 114 | |
| 115 | pub fn has_no_zig_deps(self: Module) bool { |
| 116 | for (self.deps) |d| { |
| 117 | if (d.main.len > 0) { |
| 118 | return false; |
| 119 | } |
| 120 | } |
| 121 | return true; |
| 122 | } |
| 123 | |
| 124 | pub fn has_syslib_deps(self: Module) bool { |
| 125 | for (self.deps) |d| { |
| 126 | if (d.type == .system_lib) { |
| 127 | return true; |
| 128 | } |
| 129 | } |
| 130 | return false; |
| 131 | } |
| 132 | |
| 133 | pub fn has_framework_deps(self: Module) bool { |
| 134 | for (self.deps) |d| { |
| 135 | if (d.type == .framework) { |
| 136 | return true; |
| 137 | } |
| 138 | } |
| 139 | return false; |
| 140 | } |
| 141 | |
| 142 | pub fn short_id(self: *const Module) string { |
| 143 | return u.slice(u8, &self.id, 0, @min(12, std.mem.indexOfScalar(u8, &self.id, ' ') orelse self.id.len)); |
| 144 | } |
| 145 | |
| 146 | pub fn minZigVersion(self: Module) ?std.SemanticVersion { |
| 147 | var res = self.min_zig_version; |
| 148 | |
| 149 | for (self.deps) |dm| { |
| 150 | if (dm.minZigVersion()) |sv| { |
| 151 | if (res == null or sv.order(res.?).compare(.gt)) { |
| 152 | res = sv; |
| 153 | } |
| 154 | } |
| 155 | } |
| 156 | return res; |
| 157 | } |
| 158 | |
| 159 | pub fn lessThan(_: void, lhs: Module, rhs: Module) bool { |
| 160 | for (lhs.clean_path, 0..) |_, i| { |
| 161 | if (i == rhs.clean_path.len) return false; |
| 162 | if (lhs.clean_path[i] < rhs.clean_path[i]) return true; |
| 163 | if (lhs.clean_path[i] > rhs.clean_path[i]) return false; |
| 164 | } |
| 165 | return false; |
| 166 | } |
| 167 | |
| 168 | pub fn pin(self: Module, alloc: std.mem.Allocator, cachepath: [:0]const u8, options: *common.CollectOptions) !string { |
| 169 | return switch (self.type) { |
| 170 | .local => "", |
| 171 | .system_lib => "", |
| 172 | .framework => "", |
| 173 | else => |sub| { |
| 174 | var cdir = try nfs.cwd().openDir(cachepath, .{}); |
| 175 | defer cdir.close(); |
| 176 | var mdir = try cdir.openDir(self.clean_path, .{}); |
| 177 | defer mdir.close(); |
| 178 | return switch (sub) { |
| 179 | .local, .system_lib, .framework => unreachable, |
| 180 | .git => { |
| 181 | if (options.lock == null) { |
| 182 | return u.git_rev_HEAD(alloc, mdir) catch |err| switch (err) { |
| 183 | error.ENOENT, error.NotAGitRepo => { |
| 184 | const cpath = extras.trimPrefixEnsure(self.clean_path, "v/") orelse return err; |
| 185 | var iter = std.mem.splitScalar(u8, cpath, '/'); |
| 186 | while (iter.next()) |segment| { |
| 187 | if (iter.peek() == null) return extras.trimPrefixEnsure(segment, "commit-") orelse return err; |
| 188 | } |
| 189 | unreachable; |
| 190 | }, |
| 191 | else => |e| e, |
| 192 | }; |
| 193 | } |
| 194 | for (options.lock.?) |item| { |
| 195 | if (!std.mem.eql(u8, item[1], "git")) continue; |
| 196 | if (!std.mem.eql(u8, item[2], self.dep.?.path)) continue; |
| 197 | return item[3][std.mem.indexOfScalar(u8, item[3], '-').? + 1 ..]; |
| 198 | } |
| 199 | @panic("unreachable"); |
| 200 | }, |
| 201 | .hg => @panic("TODO"), |
| 202 | .http => @panic("TODO"), |
| 203 | }; |
| 204 | }, |
| 205 | }; |
| 206 | } |
| 207 | }; |