1const std = @import("std");
2const string = []const u8;
3const yaml = @import("yaml");
4const extras = @import("extras");
5const root = @import("root");
6const build_options = root.build_options;
7const nfs = @import("nfs");
8
9const zigmod = @import("../lib.zig");
10const u = @import("funcs.zig");
11
12//
13//
14
15const gpa = std.heap.c_allocator;
16const b = 1;
17const kb = b * 1024;
18const mb = kb * 1024;
19
20pub const ModFile = struct {
21 const Self = @This();
22
23 id: [48]u8,
24 name: string,
25 main: string,
26 c_include_dirs: []const string,
27 c_source_flags: []const string,
28 c_source_files: []const string,
29 deps: []zigmod.Dep,
30 yaml: yaml.Mapping,
31 root_files: []const string,
32 files: []const string,
33 rootdeps: []zigmod.Dep,
34 builddeps: []zigmod.Dep,
35 min_zig_version: ?std.SemanticVersion,
36
37 pub fn openFile(dir: nfs.Dir, ops: nfs.Dir.OpenFileFlags) !struct { string, nfs.File } {
38 return .{ "zig.mod", dir.openFile("zig.mod", ops) catch |err| switch (err) {
39 error.ENOENT => return .{ "zigmod.yml", dir.openFile("zigmod.yml", ops) catch |err2| switch (err2) {
40 error.ENOENT => return error.ManifestNotFound,
41 else => |e2| return e2,
42 } },
43 else => |e| return e,
44 } };
45 }
46
47 pub fn init(alloc: std.mem.Allocator) !Self {
48 return try from_dir(alloc, nfs.cwd(), ".");
49 }
50
51 pub fn from_dir(alloc: std.mem.Allocator, dir: nfs.Dir, dir_path: string) !Self {
52 const file_path, const file = try openFile(dir, .{});
53 defer file.close();
54 const input = try file.readAllAlloc(alloc, mb);
55 const doc = try yaml.parse(alloc, input);
56 return from_mapping(alloc, doc.mapping, dir_path, file_path);
57 }
58
59 pub fn from_mapping(alloc: std.mem.Allocator, mapping: yaml.Mapping, dir_path: string, file_path: string) !Self {
60 var id = zigmod.Dep.EMPTY;
61 std.mem.copyForwards(u8, &id, mapping.get_string("id") orelse &u.random_string(48));
62
63 const name = mapping.get_string("name") orelse "";
64 const main = mapping.get_string("main") orelse "";
65
66 if (std.mem.indexOf(u8, name, "/")) |_| {
67 u.fail("name may not contain any '/'", .{});
68 }
69
70 if (mapping.get_string("min_zigmod_version")) |min_zigmod_version_raw| {
71 const meets = zigmod.meetsMinimumVersion(min_zigmod_version_raw);
72 if (meets == null) {
73 u.fail("invalid min_zigmod_version: {s}", .{min_zigmod_version_raw});
74 }
75 if (meets.? == false) {
76 u.fail("Your Zigmod version {s} does not meet the minimum of {s} required by {s}{s}{s}", .{ build_options.version, min_zigmod_version_raw, dir_path, std.fs.path.sep_str, file_path });
77 }
78 }
79
80 return Self{
81 .id = id,
82 .name = name,
83 .main = main,
84 .c_include_dirs = try mapping.get_string_array(alloc, "c_include_dirs"),
85 .c_source_flags = try mapping.get_string_array(alloc, "c_source_flags"),
86 .c_source_files = try mapping.get_string_array(alloc, "c_source_files"),
87 .deps = try dep_list_by_name(alloc, mapping, &.{"dependencies"}, false),
88 .yaml = mapping,
89 .root_files = try mapping.get_string_array(alloc, "root_files"),
90 .files = try mapping.get_string_array(alloc, "files"),
91 .rootdeps = try dep_list_by_name(alloc, mapping, &.{ "dev_dependencies", "root_dependencies" }, false),
92 .builddeps = try dep_list_by_name(alloc, mapping, &.{ "dev_dependencies", "build_dependencies" }, true),
93 .min_zig_version = std.SemanticVersion.parse(mapping.get_string("min_zig_version") orelse "") catch null,
94 };
95 }
96
97 fn dep_list_by_name(alloc: std.mem.Allocator, mapping: yaml.Mapping, props: []const string, for_build: bool) std.mem.Allocator.Error![]zigmod.Dep {
98 var dep_list = std.array_list.Managed(zigmod.Dep).init(alloc);
99 errdefer dep_list.deinit();
100
101 for (props) |prop| {
102 if (mapping.get(prop)) |dep_seq| {
103 if (dep_seq != .sequence) continue;
104 for (dep_seq.sequence) |item| {
105 var dtype: string = undefined;
106 var path: [:0]const u8 = undefined;
107 var version: ?[:0]const u8 = null;
108 var main = item.mapping.get_string("main") orelse "";
109
110 if (item.mapping.get("src")) |val| {
111 var src_iter = std.mem.tokenizeScalar(u8, val.string, ' ');
112 dtype = src_iter.next().?;
113 path = try gpa.dupeZ(u8, src_iter.next().?);
114 if (src_iter.next()) |dver| {
115 version = try gpa.dupeZ(u8, dver);
116 }
117 } else {
118 dtype = item.mapping.get("type").?.string;
119 path = item.mapping.get("path").?.string;
120 }
121 if (item.mapping.get("version")) |verv| {
122 version = verv.string;
123 }
124 if (version == null) {
125 version = "";
126 }
127 const dep_type = std.meta.stringToEnum(zigmod.Dep.Type, dtype).?;
128 if (dep_type == .local) {
129 if (version.?.len > 0) {
130 main = version.?;
131 version = "";
132 }
133 }
134
135 var id = zigmod.Dep.EMPTY;
136 std.mem.copyForwards(u8, &id, item.mapping.get_string("id") orelse "");
137
138 try dep_list.append(zigmod.Dep{
139 .type = dep_type,
140 .path = path,
141 .id = id,
142 .name = item.mapping.get_string("name") orelse "",
143 .main = main,
144 .version = version.?,
145 .c_include_dirs = try item.mapping.get_string_array(alloc, "c_include_dirs"),
146 .c_source_flags = try item.mapping.get_string_array(alloc, "c_source_flags"),
147 .c_source_files = try item.mapping.get_string_array(alloc, "c_source_files"),
148 .only_os = try u.list_remove(alloc, try u.split(alloc, item.mapping.get_string("only_os") orelse "", ','), ""),
149 .except_os = try u.list_remove(alloc, try u.split(alloc, item.mapping.get_string("except_os") orelse "", ','), ""),
150 .yaml = item.mapping,
151 .deps = try dep_list_by_name(alloc, item.mapping, &.{"dependencies"}, for_build),
152 .keep = std.mem.eql(u8, "true", item.mapping.get_string("keep") orelse ""),
153 .for_build = for_build,
154 });
155 // const d = &dep_list.getLast();
156 }
157 }
158 }
159 return dep_list.toOwnedSlice();
160 }
161};