tiny.smg.command.analyze.command
Defined in command.analyze.
API (1)
Actions
Public operations.
Source
Source: tools/smg/src/command/analyze/command.zig
zig
const std = @import("std");const smg = @import("../../root.zig");const analysis = smg.analysis;const concepts = smg.concepts;const diff = smg.diff;const graph_mod = smg.graph;const view = smg.view;const support = @import("support.zig");const cli_options = smg.cli.options;const cli_output = smg.cli.output;const cli_session = smg.command.session;const cli_validation = smg.cli.validation;pub fn run(allocator: std.mem.Allocator, phases: std.mem.Allocator, args: []const []const u8, limits: smg.Limits, boundary: cli_session.PhaseBoundary) !u8 { if (cli_options.hasFlag(args, "--json")) { try cli_output.writeClickUsageError(allocator, "analyze", "[OPTIONS]", "No such option: --json Did you mean --since?"); return 2; } if (try cli_validation.rejectMissingOptionValues(allocator, args, &.{ "--top", "--module", "--since", "--churn-days", "--format" })) return 2; if (try cli_validation.rejectUnexpectedOptionsPlain(allocator, "analyze", "[OPTIONS]", args, &.{ "--since", "--top", "--module", "--summary", "--concepts", "--churn-days", "--format", "--full", "--include-betweenness" })) return 2; const pos = try cli_options.positional(allocator, args); if (pos.len != 0) { try cli_output.writeClickUsageError(allocator, "analyze", "[OPTIONS]", try cli_validation.unexpectedArgumentMessage(allocator, pos)); return 2; } const top = (try integerOption(allocator, args, "--top", 5)) orelse return 2; const churn_days = (try integerOption(allocator, args, "--churn-days", 90)) orelse return 2; const fmt = (try formatOption(allocator, args)) orelse return 2; const with_concepts = cli_options.hasFlag(args, "--concepts"); const Loaded = struct { root: []const u8, graph: graph_mod.Graph, concepts: ?[]const concepts.Concept, }; const loaded: Loaded = if (with_concepts) loaded: { const values = try cli_session.loadReadGraphAndConcepts(allocator, phases, limits, boundary); break :loaded .{ .root = values.root, .graph = values.graph, .concepts = values.concepts, }; } else loaded: { const values = try cli_session.loadRead(allocator, phases, limits, boundary); break :loaded .{ .root = values[0], .graph = values[1], .concepts = null, }; }; defer boundary.beginTeardown(); const root = loaded.root; var graph = loaded.graph; const module_filter = cli_options.flagValue(args, "--module"); if (module_filter) |filter| { const unscoped = graph; graph = try view.scopePrefix(graph, allocator, filter); if (graph.nodes.items.len == 0 and unscoped.nodes.items.len != 0) try support.writeScopeWarning(allocator, unscoped, filter); } const delta_filter = try deltaFilter(allocator, root, graph, args, limits); if (delta_filter == null and cli_options.flagValue(args, "--since") != null) return 2; const concept_analysis = try conceptAnalysis(allocator, graph, loaded.concepts); if (concept_analysis == null and with_concepts) return 2; return try cli_output.writeOut(try analysis.analyze(allocator, graph, cli_options.hasFlag(args, "--summary"), std.mem.eql(u8, fmt, "json"), top, cli_options.hasFlag(args, "--full"), module_filter, concept_analysis, root, churn_days, cli_options.hasFlag(args, "--include-betweenness"), delta_filter, limits.analysis));}fn integerOption(allocator: std.mem.Allocator, args: []const []const u8, option: []const u8, default: i64) !?i64 { const raw = cli_options.flagValue(args, option) orelse return default; return std.fmt.parseInt(i64, raw, 10) catch { try cli_output.writeClickUsageError(allocator, "analyze", "[OPTIONS]", try std.fmt.allocPrint(allocator, "Invalid value for '{s}': '{s}' is not a valid integer.", .{ option, raw })); return null; };}fn formatOption(allocator: std.mem.Allocator, args: []const []const u8) !?[]const u8 { const fmt = cli_options.flagValue(args, "--format") orelse "text"; if (isFormat(fmt)) return fmt; try cli_output.writeClickUsageError(allocator, "analyze", "[OPTIONS]", try std.fmt.allocPrint(allocator, "Invalid value for '--format': '{s}' is not one of 'text', 'json'.", .{fmt})); return null;}fn deltaFilter(allocator: std.mem.Allocator, root: []const u8, graph: graph_mod.Graph, args: []const []const u8, limits: smg.Limits) !?analysis.DeltaFilter { const ref = cli_options.flagValue(args, "--since") orelse return null; var invalid = false; const old_graph_optional = try diff.loadGraphFromGit(allocator, root, ref, &invalid, limits); if (invalid) { try cli_output.writeErrFmt(allocator, "Error: invalid git ref: {s}\n", .{ref}); return null; } const old_graph = old_graph_optional orelse graph_mod.init(allocator); const result = try diff.graphs(allocator, old_graph, graph, true); return .{ .git_ref = ref, .names = try support.deltaNames(allocator, result) };}fn conceptAnalysis(allocator: std.mem.Allocator, graph: graph_mod.Graph, concept_list: ?[]const concepts.Concept) !?concepts.Analysis { const loaded = concept_list orelse return null; var overlap_message: []const u8 = ""; return concepts.analyze(allocator, graph, loaded, &overlap_message) catch |err| { if (err == error.ConceptOverlap) { try cli_output.writeErrFmt(allocator, "Error: {s}\n", .{overlap_message}); return null; } return err; };}fn isFormat(fmt: []const u8) bool { return std.mem.eql(u8, fmt, "text") or std.mem.eql(u8, fmt, "json");}test "analyze format option accepts text and json only" { try std.testing.expect(isFormat("text")); try std.testing.expect(isFormat("json")); try std.testing.expect(!isFormat("dot"));}Source: tools/smg/src/command/analyze/root.zig:1
zig
pub const command = @import("command.zig");Complete call list for command.analyze.command.run
7 direct calls.
tools.smg.src.command.analyze.command.conceptAnalysis[function] — private; no exact target attools/smg/src/command/analyze/command.zig:95in nearest public ownertiny.smg.command.analyze.commandtools.smg.src.command.analyze.command.deltaFilter[function] — private; no exact target attools/smg/src/command/analyze/command.zig:82in nearest public ownertiny.smg.command.analyze.commandtools.smg.src.command.analyze.command.formatOption[function] — private; no exact target attools/smg/src/command/analyze/command.zig:75in nearest public ownertiny.smg.command.analyze.commandtools.smg.src.command.analyze.command.integerOption[function] — private; no exact target attools/smg/src/command/analyze/command.zig:67in nearest public ownertiny.smg.command.analyze.commandtiny.smg.command.analyze.support.writeScopeWarning[function] attools/smg/src/command/analyze/support.zig:21tools.smg.src.help.analysis.analyze[constant] — private; no exact target attools/smg/src/help/analysis.zig:4in nearest public ownertools.smg.src.help.analysistiny.smg.view.scopePrefix[function] attools/smg/src/view.zig:278
Audit
| Definitions | 2 |
|---|---|
| Public names | 3 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |