| 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,6 +59,10 @@ jobs: |
| 59 | - run: ./test_repo.sh https://github.com/nektro/zigmod-test-local-dep | 59 | - run: ./test_repo.sh https://github.com/nektro/zigmod-test-local-dep |
| 60 | - run: ./test_repo.sh https://github.com/nektro/zigmod-test-c-code | 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 | # Github Release | 66 | # Github Release |
| 63 | - run: ./changelog.sh | 67 | - run: ./changelog.sh |
| 64 | - run: ./make_release.sh ${{ secrets.GITHUB_TOKEN }} | 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,6 +13,7 @@ pub const commands = struct { |
| 13 | pub const zpm = @import("./cmd/zpm.zig"); | 13 | pub const zpm = @import("./cmd/zpm.zig"); |
| 14 | pub const license = @import("./cmd/license.zig"); | 14 | pub const license = @import("./cmd/license.zig"); |
| 15 | pub const generate = @import("./cmd/generate.zig"); | 15 | pub const generate = @import("./cmd/generate.zig"); |
| 16 | pub const explain = @import("./cmd/explain.zig"); | ||
| 16 | }; | 17 | }; |
| 17 | 18 | ||
| 18 | pub fn init() !void { | 19 | pub fn init() !void { |