| author | |
| committer | |
| log | f35b2ecf00c0ed2b2bc8d2da8ce367765db0a2e3 |
| tree | 6da0541a0e1b5a2202cd3e86937a10b0a0169ee7 |
| parent | cedfb308d15faefbe034d2b4cd88438674e4c2d3 |
| signature |
7 files changed, 242 insertions(+), 0 deletions(-)
.github/workflows/push.yml+4| ... | ... | @@ -59,6 +59,10 @@ jobs: |
| 59 | 59 | - run: ./test_repo.sh https://github.com/nektro/zigmod-test-local-dep |
| 60 | 60 | - run: ./test_repo.sh https://github.com/nektro/zigmod-test-c-code |
| 61 | 61 | |
| 62 | - run: git diff <(cat __snapshots__/explain.tree.txt) <(zigmod explain --locked --format tree) | |
| 63 | - run: git diff <(cat __snapshots__/explain.mermaid.txt) <(zigmod explain --locked --format mermaid) | |
| 64 | - run: git diff <(cat __snapshots__/explain.dot.txt) <(zigmod explain --locked --format dot) | |
| 65 | ||
| 62 | 66 | # Github Release |
| 63 | 67 | - run: ./changelog.sh |
| 64 | 68 | - run: ./make_release.sh ${{ secrets.GITHUB_TOKEN }} |
__snapshots__/explain.dot.txt created+33| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | digraph { | |
| 2 | "root" -> "zigmod"; | |
| 3 | "root" -> "win32"; | |
| 4 | "root" -> "extras"; | |
| 5 | "root" -> "ansi"; | |
| 6 | "zigmod" -> "yaml"; | |
| 7 | "zigmod" -> "ansi"; | |
| 8 | "zigmod" -> "known-folders"; | |
| 9 | "zigmod" -> "licenses"; | |
| 10 | "zigmod" -> "zfetch"; | |
| 11 | "zigmod" -> "detect-license"; | |
| 12 | "zigmod" -> "inquirer"; | |
| 13 | "zigmod" -> "ini"; | |
| 14 | "zigmod" -> "time"; | |
| 15 | "zigmod" -> "extras"; | |
| 16 | "zigmod" -> "git"; | |
| 17 | "zigmod" -> "json"; | |
| 18 | "yaml" -> "extras"; | |
| 19 | "zfetch" -> "hzzp"; | |
| 20 | "zfetch" -> "iguanaTLS"; | |
| 21 | "detect-license" -> "licenses-text"; | |
| 22 | "detect-license" -> "leven"; | |
| 23 | "inquirer" -> "ansi"; | |
| 24 | "time" -> "extras"; | |
| 25 | "git" -> "time"; | |
| 26 | "git" -> "extras"; | |
| 27 | "git" -> "tracer"; | |
| 28 | "tracer" -> "extras"; | |
| 29 | "json" -> "extras"; | |
| 30 | "json" -> "tracer"; | |
| 31 | "json" -> "intrusive-parser"; | |
| 32 | "intrusive-parser" -> "extras"; | |
| 33 | } |
__snapshots__/explain.mermaid.txt created+32| ... | ... | @@ -0,0 +1,32 @@ |
| 1 | graph TD; | |
| 2 | root-->zigmod; | |
| 3 | root-->win32; | |
| 4 | root-->extras; | |
| 5 | root-->ansi; | |
| 6 | zigmod-->yaml; | |
| 7 | zigmod-->ansi; | |
| 8 | zigmod-->known-folders; | |
| 9 | zigmod-->licenses; | |
| 10 | zigmod-->zfetch; | |
| 11 | zigmod-->detect-license; | |
| 12 | zigmod-->inquirer; | |
| 13 | zigmod-->ini; | |
| 14 | zigmod-->time; | |
| 15 | zigmod-->extras; | |
| 16 | zigmod-->git; | |
| 17 | zigmod-->json; | |
| 18 | yaml-->extras; | |
| 19 | zfetch-->hzzp; | |
| 20 | zfetch-->iguanaTLS; | |
| 21 | detect-license-->licenses-text; | |
| 22 | detect-license-->leven; | |
| 23 | inquirer-->ansi; | |
| 24 | time-->extras; | |
| 25 | git-->time; | |
| 26 | git-->extras; | |
| 27 | git-->tracer; | |
| 28 | tracer-->extras; | |
| 29 | json-->extras; | |
| 30 | json-->tracer; | |
| 31 | json-->intrusive-parser; | |
| 32 | intrusive-parser-->extras; |
__snapshots__/explain.tree.txt created+35| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | root | |
| 2 | 	zigmod | |
| 3 | 		yaml | |
| 4 | 			 | |
| 5 | 			extras | |
| 6 | 		ansi | |
| 7 | 		known-folders | |
| 8 | 		licenses | |
| 9 | 		zfetch | |
| 10 | 			hzzp | |
| 11 | 			iguanaTLS | |
| 12 | 		detect-license | |
| 13 | 			licenses-text | |
| 14 | 			leven | |
| 15 | 		inquirer | |
| 16 | 			ansi | |
| 17 | 		ini | |
| 18 | 		time | |
| 19 | 			extras | |
| 20 | 		extras | |
| 21 | 		git | |
| 22 | 			time | |
| 23 | 				extras | |
| 24 | 			extras | |
| 25 | 			tracer | |
| 26 | 				extras | |
| 27 | 		json | |
| 28 | 			extras | |
| 29 | 			tracer | |
| 30 | 				extras | |
| 31 | 			intrusive-parser | |
| 32 | 				extras | |
| 33 | 	win32 | |
| 34 | 	extras | |
| 35 | 	ansi |
docs/commands/explain.md created+37| ... | ... | @@ -0,0 +1,37 @@ |
| 1 | ## `explain` command | |
| 2 | ||
| 3 | ``` | |
| 4 | zigmod explain | |
| 5 | ``` | |
| 6 | ||
| 7 | Use this command to create a visual description of your dependency graph. | |
| 8 | ||
| 9 | ## `--locked` | |
| 10 | ||
| 11 | Pass this to use the dependency versions from `zigmod.lock` instead of your current `.zigmod` folder. | |
| 12 | ||
| 13 | ## `--format` | |
| 14 | ||
| 15 | May be followed by one of the following values: | |
| 16 | ||
| 17 | - `tree` | |
| 18 | - `mermaid` | |
| 19 | - `dot` | |
| 20 | ||
| 21 | ## `--format tree` | |
| 22 | ||
| 23 | <img width="1077" height="866" alt="Image" src="https://github.com/user-attachments/assets/98d41e63-f5bd-4c7d-a5a3-272b9499d925" /> | |
| 24 | ||
| 25 | ## `--format mermaid` | |
| 26 | ||
| 27 | https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams | |
| 28 | ||
| 29 | <img width="1173" height="373" alt="Image" src="https://github.com/user-attachments/assets/0ad012b2-cfc9-4a7a-b3fa-9f5fefb969ab" /> | |
| 30 | ||
| 31 | ## `--format dot` | |
| 32 | ||
| 33 | This format prints output compatible with the `dot` program from https://graphviz.org/. | |
| 34 | ||
| 35 | Run `dot -Tpng <(zigmod explain --locked --format dot) -o explain.png` to generate the image. | |
| 36 | ||
| 37 | <img width="1781" height="443" alt="Image" src="https://github.com/user-attachments/assets/217c5855-537e-4a93-ba49-b5fe6f78cdd2" /> |
src/cmd/explain.zig created+100| ... | ... | @@ -0,0 +1,100 @@ |
| 1 | const std = @import("std"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const extras = @import("extras"); | |
| 4 | ||
| 5 | const zigmod = @import("../lib.zig"); | |
| 6 | const u = @import("./../util/funcs.zig"); | |
| 7 | const common = @import("./../common.zig"); | |
| 8 | ||
| 9 | // | |
| 10 | // | |
| 11 | ||
| 12 | pub fn execute(self_name: []const u8, args: [][:0]u8) !void { | |
| 13 | _ = self_name; | |
| 14 | ||
| 15 | const gpa = std.heap.c_allocator; | |
| 16 | const cachepath = try u.find_cachepath(); | |
| 17 | const dir = std.fs.cwd(); | |
| 18 | const should_lock = args.len >= 1 and std.mem.eql(u8, args[0], "--locked"); | |
| 19 | const format_i: usize = if (should_lock) 1 else 0; | |
| 20 | const Format = enum { | |
| 21 | tree, | |
| 22 | mermaid, | |
| 23 | dot, | |
| 24 | }; | |
| 25 | const format_s = if (args.len >= 1 + format_i and std.mem.eql(u8, args[format_i], "--format")) args[format_i + 1] else ""; | |
| 26 | const format = std.meta.stringToEnum(Format, format_s) orelse u.fail("unrecognized --format: {s}", .{format_s}); | |
| 27 | ||
| 28 | var options = common.CollectOptions{ | |
| 29 | .log = false, | |
| 30 | .update = false, | |
| 31 | .alloc = gpa, | |
| 32 | .lock = if (should_lock) try common.parse_lockfile(gpa, dir) else null, | |
| 33 | }; | |
| 34 | const top_module = try common.collect_deps_deep(cachepath, dir, &options); | |
| 35 | ||
| 36 | var seencache = std.ArrayList([48]u8).init(gpa); | |
| 37 | defer seencache.deinit(); | |
| 38 | ||
| 39 | const stdout = std.io.getStdOut(); | |
| 40 | const w = stdout.writer(); | |
| 41 | ||
| 42 | switch (format) { | |
| 43 | .tree => { | |
| 44 | try printTree(w, top_module, 0); | |
| 45 | }, | |
| 46 | .mermaid => { | |
| 47 | try w.writeAll("graph TD;\n"); | |
| 48 | try printMermaid(w, top_module, &seencache); | |
| 49 | }, | |
| 50 | .dot => { | |
| 51 | try w.writeAll("digraph {\n"); | |
| 52 | try printDot(w, top_module, &seencache); | |
| 53 | try w.writeAll("}\n"); | |
| 54 | }, | |
| 55 | } | |
| 56 | } | |
| 57 | ||
| 58 | fn printTree(writer: anytype, module: zigmod.Module, depth: u16) !void { | |
| 59 | try writer.writeByteNTimes('\t', depth); | |
| 60 | try writer.writeAll(module.name); | |
| 61 | try writer.writeByte('\n'); | |
| 62 | ||
| 63 | for (module.deps) |dep| { | |
| 64 | try printTree(writer, dep, depth + 1); | |
| 65 | } | |
| 66 | } | |
| 67 | ||
| 68 | fn printMermaid(writer: anytype, module: zigmod.Module, seencache: *std.ArrayList([48]u8)) !void { | |
| 69 | for (seencache.items) |item| { | |
| 70 | if (std.mem.eql(u8, &module.id, &item)) { | |
| 71 | return; | |
| 72 | } | |
| 73 | } | |
| 74 | try seencache.append(module.id); | |
| 75 | ||
| 76 | for (module.deps) |dep| { | |
| 77 | if (dep.name.len == 0) continue; | |
| 78 | try writer.print(" {s}-->{s};\n", .{ module.name, dep.name }); | |
| 79 | } | |
| 80 | for (module.deps) |dep| { | |
| 81 | try printMermaid(writer, dep, seencache); | |
| 82 | } | |
| 83 | } | |
| 84 | ||
| 85 | fn printDot(writer: anytype, module: zigmod.Module, seencache: *std.ArrayList([48]u8)) !void { | |
| 86 | for (seencache.items) |item| { | |
| 87 | if (std.mem.eql(u8, &module.id, &item)) { | |
| 88 | return; | |
| 89 | } | |
| 90 | } | |
| 91 | try seencache.append(module.id); | |
| 92 | ||
| 93 | for (module.deps) |dep| { | |
| 94 | if (dep.name.len == 0) continue; | |
| 95 | try writer.print(" \"{s}\" -> \"{s}\";\n", .{ module.name, dep.name }); | |
| 96 | } | |
| 97 | for (module.deps) |dep| { | |
| 98 | try printDot(writer, dep, seencache); | |
| 99 | } | |
| 100 | } |
src/lib.zig+1| ... | ... | @@ -13,6 +13,7 @@ pub const commands = struct { |
| 13 | 13 | pub const zpm = @import("./cmd/zpm.zig"); |
| 14 | 14 | pub const license = @import("./cmd/license.zig"); |
| 15 | 15 | pub const generate = @import("./cmd/generate.zig"); |
| 16 | pub const explain = @import("./cmd/explain.zig"); | |
| 16 | 17 | }; |
| 17 | 18 | |
| 18 | 19 | pub fn init() !void { |