authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-07-05 17:41:40 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-07-05 17:41:40 -07:00
log13793e258c36d9a49f1c79db6e0188fe87a624de
tree11b11d638175423789e00a6b8b3c490b6b35b561
parent1b963fe00dbd657b570c8a6a099d8c8feb91f2ff

add the `ci` command. similar to `fetch` but only reads from `zigmod.lock`


8 files changed, 87 insertions(+), 39 deletions(-)

docs/commands/ci.md created+7
...@@ -0,0 +1,7 @@
1## `ci` command
2```
3zigmod ci
4```
5
6- This command takes no parameters and will do almost exactly the same thing as the [`fetch`](./fetch.md) command, except it will read version strings from your `zigmod.lock` file instead of from dependencies' `zig.mod` definitions.
7- Inspired by the [`npm ci`](https://docs.npmjs.com/cli/ci.html) command.
docs/commands/fetch.md+1
...@@ -5,6 +5,7 @@ zigmod fetch...@@ -5,6 +5,7 @@ zigmod fetch
55
6- This command takes no parameters and will generate a `deps.zig` in the root of your project. This is the file that you will then import into your `build.zig` to automatically add all the necessary packages and (any) C code that may be in your dependencies.6- This command takes no parameters and will generate a `deps.zig` in the root of your project. This is the file that you will then import into your `build.zig` to automatically add all the necessary packages and (any) C code that may be in your dependencies.
7- `deps.zig` is not typically checked into your source control.7- `deps.zig` is not typically checked into your source control.
8- This command will also produce a `zigmod.lock` which you can use to easily generate [reproducible builds](https://reproducible-builds.org/) using the [`ci`](./ci.md) command.
89
9For a full reference on the fields available in `deps.zig` you can check [here](../deps.zig.md).10For a full reference on the fields available in `deps.zig` you can check [here](../deps.zig.md).
1011
src/cmd/ci.zig created+25
...@@ -0,0 +1,25 @@
1const std = @import("std");
2const gpa = std.heap.c_allocator;
3
4const u = @import("./../util/index.zig");
5const common = @import("./../common.zig");
6
7// Inspired by:
8// https://docs.npmjs.com/cli/v7/commands/npm-ci
9
10pub fn execute(args: [][]u8) !void {
11 _ = args;
12
13 const dir = try std.fs.path.join(gpa, &.{ ".zigmod", "deps" });
14
15 const top_module = try common.collect_deps_deep(dir, "zig.mod", .{
16 .log = true,
17 .update = false,
18 .lock = try common.parse_lockfile("zigmod.lock"),
19 });
20
21 const list = &std.ArrayList(u.Module).init(gpa);
22 try common.collect_pkgs(top_module, list);
23
24 try @import("./fetch.zig").create_depszig(dir, top_module, list);
25}
src/common.zig+37-24
...@@ -10,6 +10,7 @@ const yaml = @import("./util/yaml.zig");...@@ -10,6 +10,7 @@ const yaml = @import("./util/yaml.zig");
10pub const CollectOptions = struct {10pub const CollectOptions = struct {
11 log: bool,11 log: bool,
12 update: bool,12 update: bool,
13 lock: ?[]const [4][]const u8 = null,
13};14};
1415
15pub fn collect_deps_deep(dir: []const u8, mpath: []const u8, options: CollectOptions) !u.Module {16pub fn collect_deps_deep(dir: []const u8, mpath: []const u8, options: CollectOptions) !u.Module {
...@@ -21,7 +22,7 @@ pub fn collect_deps_deep(dir: []const u8, mpath: []const u8, options: CollectOpt...@@ -21,7 +22,7 @@ pub fn collect_deps_deep(dir: []const u8, mpath: []const u8, options: CollectOpt
21 try moduledeps.append(try add_files_package("root", m.root_files, m.name));22 try moduledeps.append(try add_files_package("root", m.root_files, m.name));
22 }23 }
23 try moduledeps.append(try collect_deps(dir, mpath, options));24 try moduledeps.append(try collect_deps(dir, mpath, options));
24 for (m.devdeps) |d| {25 for (m.devdeps) |*d| {
25 if (try get_module_from_dep(d, dir, m.name, options)) |founddep| {26 if (try get_module_from_dep(d, dir, m.name, options)) |founddep| {
26 try moduledeps.append(founddep);27 try moduledeps.append(founddep);
27 }28 }
...@@ -31,13 +32,8 @@ pub fn collect_deps_deep(dir: []const u8, mpath: []const u8, options: CollectOpt...@@ -31,13 +32,8 @@ pub fn collect_deps_deep(dir: []const u8, mpath: []const u8, options: CollectOpt
31 .id = "root",32 .id = "root",
32 .name = "root",33 .name = "root",
33 .main = m.main,34 .main = m.main,
34 .c_include_dirs = &.{},
35 .c_source_flags = &.{},
36 .c_source_files = &.{},
37 .deps = moduledeps.toOwnedSlice(),35 .deps = moduledeps.toOwnedSlice(),
38 .clean_path = "",36 .clean_path = "",
39 .only_os = &.{},
40 .except_os = &.{},
41 .yaml = m.yaml,37 .yaml = m.yaml,
42 .dep = null,38 .dep = null,
43 };39 };
...@@ -50,7 +46,7 @@ pub fn collect_deps(dir: []const u8, mpath: []const u8, options: CollectOptions)...@@ -50,7 +46,7 @@ pub fn collect_deps(dir: []const u8, mpath: []const u8, options: CollectOptions)
50 if (m.files.len > 0) {46 if (m.files.len > 0) {
51 try moduledeps.append(try add_files_package(m.id, m.files, m.name));47 try moduledeps.append(try add_files_package(m.id, m.files, m.name));
52 }48 }
53 for (m.deps) |d| {49 for (m.deps) |*d| {
54 if (try get_module_from_dep(d, dir, m.name, options)) |founddep| {50 if (try get_module_from_dep(d, dir, m.name, options)) |founddep| {
55 try moduledeps.append(founddep);51 try moduledeps.append(founddep);
56 }52 }
...@@ -65,8 +61,6 @@ pub fn collect_deps(dir: []const u8, mpath: []const u8, options: CollectOptions)...@@ -65,8 +61,6 @@ pub fn collect_deps(dir: []const u8, mpath: []const u8, options: CollectOptions)
65 .c_source_files = m.c_source_files,61 .c_source_files = m.c_source_files,
66 .deps = moduledeps.toOwnedSlice(),62 .deps = moduledeps.toOwnedSlice(),
67 .clean_path = "../..",63 .clean_path = "../..",
68 .only_os = &.{},
69 .except_os = &.{},
70 .yaml = m.yaml,64 .yaml = m.yaml,
71 .dep = null,65 .dep = null,
72 };66 };
...@@ -180,8 +174,18 @@ fn get_moddir(basedir: []const u8, d: u.Dep, parent_name: []const u8, options: C...@@ -180,8 +174,18 @@ fn get_moddir(basedir: []const u8, d: u.Dep, parent_name: []const u8, options: C
180 }174 }
181}175}
182176
183pub fn get_module_from_dep(d: u.Dep, dir: []const u8, parent_name: []const u8, options: CollectOptions) anyerror!?u.Module {177pub fn get_module_from_dep(d: *u.Dep, dir: []const u8, parent_name: []const u8, options: CollectOptions) anyerror!?u.Module {
184 const moddir = try get_moddir(dir, d, parent_name, options);178 if (options.lock) |lock| {
179 for (lock) |item| {
180 if (std.mem.eql(u8, item[0], try d.clean_path())) {
181 d.type = std.meta.stringToEnum(u.DepType, item[1]).?;
182 d.path = item[2];
183 d.version = item[3];
184 break;
185 }
186 }
187 }
188 const moddir = try get_moddir(dir, d.*, parent_name, options);
185 switch (d.type) {189 switch (d.type) {
186 .system_lib => {190 .system_lib => {
187 return u.Module{191 return u.Module{
...@@ -191,20 +195,17 @@ pub fn get_module_from_dep(d: u.Dep, dir: []const u8, parent_name: []const u8, o...@@ -191,20 +195,17 @@ pub fn get_module_from_dep(d: u.Dep, dir: []const u8, parent_name: []const u8, o
191 .only_os = d.only_os,195 .only_os = d.only_os,
192 .except_os = d.except_os,196 .except_os = d.except_os,
193 .main = "",197 .main = "",
194 .c_include_dirs = &.{},
195 .c_source_flags = &.{},
196 .c_source_files = &.{},
197 .deps = &[_]u.Module{},198 .deps = &[_]u.Module{},
198 .clean_path = d.path,199 .clean_path = d.path,
199 .yaml = null,200 .yaml = null,
200 .dep = d,201 .dep = d.*,
201 };202 };
202 },203 },
203 else => {204 else => {
204 var dd = try collect_deps(dir, try u.concat(&.{ moddir, "/zig.mod" }), options) catch |e| switch (e) {205 var dd = try collect_deps(dir, try u.concat(&.{ moddir, "/zig.mod" }), options) catch |e| switch (e) {
205 error.FileNotFound => {206 error.FileNotFound => {
206 if (d.main.len > 0 or d.c_include_dirs.len > 0 or d.c_source_files.len > 0) {207 if (d.main.len > 0 or d.c_include_dirs.len > 0 or d.c_source_files.len > 0) {
207 var mod_from = try u.Module.from(d, dir, options);208 var mod_from = try u.Module.from(d.*, dir, options);
208 if (d.type != .local) mod_from.clean_path = u.trim_prefix(moddir, dir)[1..];209 if (d.type != .local) mod_from.clean_path = u.trim_prefix(moddir, dir)[1..];
209 if (mod_from.is_for_this()) return mod_from;210 if (mod_from.is_for_this()) return mod_from;
210 return null;211 return null;
...@@ -213,7 +214,7 @@ pub fn get_module_from_dep(d: u.Dep, dir: []const u8, parent_name: []const u8, o...@@ -213,7 +214,7 @@ pub fn get_module_from_dep(d: u.Dep, dir: []const u8, parent_name: []const u8, o
213 },214 },
214 else => e,215 else => e,
215 };216 };
216 dd.dep = d;217 dd.dep = d.*;
217 const save = dd;218 const save = dd;
218 if (d.type != .local) dd.clean_path = u.trim_prefix(moddir, dir)[1..];219 if (d.type != .local) dd.clean_path = u.trim_prefix(moddir, dir)[1..];
219 if (dd.id.len == 0) dd.id = try u.random_string(48);220 if (dd.id.len == 0) dd.id = try u.random_string(48);
...@@ -274,23 +275,35 @@ fn add_files_package(pkg_name: []const u8, dirs: []const []const u8, parent_name...@@ -274,23 +275,35 @@ fn add_files_package(pkg_name: []const u8, dirs: []const []const u8, parent_name
274 \\275 \\
275 );276 );
276277
277 const d: u.Dep = .{278 var d: u.Dep = .{
278 .type = .local,279 .type = .local,
279 .path = "files",280 .path = "files",
280 .id = "",281 .id = "",
281 .name = "self/files",282 .name = "self/files",
282 .main = fname,283 .main = fname,
283 .version = "absolute",284 .version = "absolute",
284 .c_include_dirs = &.{},
285 .c_source_flags = &.{},
286 .c_source_files = &.{},
287 .only_os = &.{},
288 .except_os = &.{},
289 .yaml = null,285 .yaml = null,
290 .deps = &.{},286 .deps = &.{},
291 };287 };
292 return (try get_module_from_dep(d, destination, parent_name, .{288 return (try get_module_from_dep(&d, destination, parent_name, .{
293 .log = false,289 .log = false,
294 .update = false,290 .update = false,
295 })).?;291 })).?;
296}292}
293
294pub fn parse_lockfile(path: []const u8) ![]const [4][]const u8 {
295 const list = &std.ArrayList([4][]const u8).init(gpa);
296 const max = std.math.maxInt(usize);
297 const f = try std.fs.cwd().openFile(path, .{});
298 const r = f.reader();
299 while (try r.readUntilDelimiterOrEofAlloc(gpa, '\n', max)) |line| {
300 var iter = std.mem.split(line, " ");
301 try list.append([4][]const u8{
302 iter.next().?,
303 iter.next().?,
304 iter.next().?,
305 iter.next().?,
306 });
307 }
308 return list.toOwnedSlice();
309}
src/lib.zig+2
...@@ -1,10 +1,12 @@...@@ -1,10 +1,12 @@
1pub const commands_to_bootstrap = struct {1pub const commands_to_bootstrap = struct {
2 pub const fetch = @import("./cmd/fetch.zig");2 pub const fetch = @import("./cmd/fetch.zig");
3 pub const ci = @import("./cmd/ci.zig");
3};4};
45
5pub const commands = struct {6pub const commands = struct {
6 pub const init = @import("./cmd/init.zig");7 pub const init = @import("./cmd/init.zig");
7 pub const fetch = @import("./cmd/fetch.zig");8 pub const fetch = @import("./cmd/fetch.zig");
9 pub const ci = @import("./cmd/ci.zig");
8 pub const sum = @import("./cmd/sum.zig");10 pub const sum = @import("./cmd/sum.zig");
9 pub const zpm = @import("./cmd/zpm.zig");11 pub const zpm = @import("./cmd/zpm.zig");
10 pub const license = @import("./cmd/license.zig");12 pub const license = @import("./cmd/license.zig");
src/util/dep.zig+6-6
...@@ -18,13 +18,13 @@ pub const Dep = struct {...@@ -18,13 +18,13 @@ pub const Dep = struct {
18 name: []const u8,18 name: []const u8,
19 main: []const u8,19 main: []const u8,
20 version: []const u8,20 version: []const u8,
21 c_include_dirs: []const []const u8,21 c_include_dirs: []const []const u8 = &.{},
22 c_source_flags: []const []const u8,22 c_source_flags: []const []const u8 = &.{},
23 c_source_files: []const []const u8,23 c_source_files: []const []const u8 = &.{},
24 only_os: []const []const u8,24 only_os: []const []const u8 = &.{},
25 except_os: []const []const u8,25 except_os: []const []const u8 = &.{},
26 yaml: ?yaml.Mapping,26 yaml: ?yaml.Mapping,
27 deps: []const u.Dep,27 deps: []u.Dep,
2828
29 pub fn clean_path(self: Dep) ![]const u8 {29 pub fn clean_path(self: Dep) ![]const u8 {
30 if (self.type == .local) {30 if (self.type == .local) {
src/util/modfile.zig+3-3
...@@ -20,9 +20,9 @@ pub const ModFile = struct {...@@ -20,9 +20,9 @@ pub const ModFile = struct {
20 c_include_dirs: []const []const u8,20 c_include_dirs: []const []const u8,
21 c_source_flags: []const []const u8,21 c_source_flags: []const []const u8,
22 c_source_files: []const []const u8,22 c_source_files: []const []const u8,
23 deps: []const u.Dep,23 deps: []u.Dep,
24 yaml: yaml.Mapping,24 yaml: yaml.Mapping,
25 devdeps: []const u.Dep,25 devdeps: []u.Dep,
26 root_files: []const []const u8,26 root_files: []const []const u8,
27 files: []const []const u8,27 files: []const []const u8,
2828
...@@ -61,7 +61,7 @@ pub const ModFile = struct {...@@ -61,7 +61,7 @@ pub const ModFile = struct {
61 };61 };
62 }62 }
6363
64 fn dep_list_by_name(alloc: *std.mem.Allocator, mapping: yaml.Mapping, prop: []const u8) anyerror![]const u.Dep {64 fn dep_list_by_name(alloc: *std.mem.Allocator, mapping: yaml.Mapping, prop: []const u8) anyerror![]u.Dep {
65 const dep_list = &std.ArrayList(u.Dep).init(alloc);65 const dep_list = &std.ArrayList(u.Dep).init(alloc);
66 if (mapping.get(prop)) |dep_seq| {66 if (mapping.get(prop)) |dep_seq| {
67 if (dep_seq == .sequence) {67 if (dep_seq == .sequence) {
src/util/module.zig+6-6
...@@ -14,11 +14,11 @@ pub const Module = struct {...@@ -14,11 +14,11 @@ pub const Module = struct {
14 id: []const u8,14 id: []const u8,
15 name: []const u8,15 name: []const u8,
16 main: []const u8,16 main: []const u8,
17 c_include_dirs: []const []const u8,17 c_include_dirs: []const []const u8 = &.{},
18 c_source_flags: []const []const u8,18 c_source_flags: []const []const u8 = &.{},
19 c_source_files: []const []const u8,19 c_source_files: []const []const u8 = &.{},
20 only_os: []const []const u8,20 only_os: []const []const u8 = &.{},
21 except_os: []const []const u8,21 except_os: []const []const u8 = &.{},
22 yaml: ?yaml.Mapping,22 yaml: ?yaml.Mapping,
23 deps: []Module,23 deps: []Module,
24 clean_path: []const u8,24 clean_path: []const u8,
...@@ -27,7 +27,7 @@ pub const Module = struct {...@@ -27,7 +27,7 @@ pub const Module = struct {
27 pub fn from(dep: u.Dep, dir: []const u8, options: common.CollectOptions) !Module {27 pub fn from(dep: u.Dep, dir: []const u8, options: common.CollectOptions) !Module {
28 const moddeps = &std.ArrayList(Module).init(gpa);28 const moddeps = &std.ArrayList(Module).init(gpa);
29 defer moddeps.deinit();29 defer moddeps.deinit();
30 for (dep.deps) |d| {30 for (dep.deps) |*d| {
31 if (try common.get_module_from_dep(d, dir, dep.name, options)) |founddep| {31 if (try common.get_module_from_dep(d, dir, dep.name, options)) |founddep| {
32 try moddeps.append(founddep);32 try moddeps.append(founddep);
33 }33 }