Remove unused parser resource plumbing

This commit is contained in:
2026-11-07 15:51:19 +00:00
parent f2822f055c
commit 51a147a6e5
10 changed files with 32 additions and 73 deletions

View File

@@ -76,6 +76,8 @@ rendering. A session owns the mutable backend tree for one invocation; parsing
and presentation reuse that session. The adapter returns raw values and neutral
syntax failures to core. It does not own the registry, typed input preparation,
integration declarations, provider acquisition, or native report rendering.
Parser options carry flag-alias selection; invocation context and streams stay
with core, while backend output destinations discard and help uses a local buffer.
Cobra and pflag imports remain inside this package.
## Optional modules

View File

@@ -1,6 +1,6 @@
# Consolidated audit catalog
Status: **14 distinct open findings: 14 P3**, consolidated from 30
Status: **13 distinct open findings: 13 P3**, consolidated from 30
numbered entries in seven audit documents. Reviewed audit state:
`db732e3a1de55c844f77870e1c6db683c2685d5d`.
@@ -257,6 +257,10 @@ consumer compatibility or migration work is needed.
## F12 — P3: Parser sessions carry unused execution resources
**Complete.** Unused execution and parser resource plumbing was removed; the
backend retains discard destinations and buffered help. Focused routing, help,
context-forwarding and session-isolation tests passed.
Core and the Cobra adapter duplicate stream normalization and retain context and
streams through parser options and backend nodes, although the adapter parses
and renders buffered help rather than executing callbacks or reading application

View File

@@ -1,6 +1,6 @@
# Audit remediation implementation plan
Status: in progress; Stages 1–12 complete.
Status: in progress; Stages 1–13 complete.
Baseline: `d492c7747175c01a53261206c2b4356e53453621`. Before this sprint,
intervening changes recorded decisions and retired the completed older
@@ -442,6 +442,12 @@ Complete F21 when both callers share one adapter and preserve their context.
## Stage 13 — Remove unused parser resource plumbing
**Complete.** Parser options carry only alias selection, backend output and
error destinations explicitly discard, and core retains invocation resources.
The test-only App.parse wrapper was removed. Focused routed parsing, help,
context, backend parsing and session-isolation tests passed in the offline aligned
Go 1.27.0 workspace with `-mod=readonly`. F24 remains open for binding wrappers.
Findings: F12 and parsing portion of F24. Sources: `execute.go`, `parser.go`,
`internal/commandmeta/metadata.go`, and `internal/cobra/parse.go`.

View File

@@ -80,10 +80,8 @@ func (a *App) Execute(ctx context.Context, args []string, streams Streams) Outco
type execution struct {
app *App
ctx context.Context
streams Streams
reporter *Reporter
debugEvents []string
options commandmeta.ParseOptions
snapshot *routingSnapshot
session *internalcobra.Session
route routeResult
@@ -116,13 +114,10 @@ func (current commandExecution) renderHelpTargets(targets []string) Outcome {
}
func newExecution(app *App, ctx context.Context, streams Streams) *execution {
streams = normalizeStreams(streams)
current := &execution{
app: app,
ctx: ctx,
streams: streams,
reporter: newReporter(streams),
options: commandmeta.ParseOptions{Context: ctx, Out: streams.Out, Err: streams.Err},
}
if app != nil {
current.snapshot = app.routeSnapshot()
@@ -147,7 +142,7 @@ func (current *execution) prepareSession() {
if current.snapshot == nil {
current.snapshot = current.app.routeSnapshot()
}
options := current.options
options := commandmeta.ParseOptions{}
if current.snapshot != nil {
switch current.route.kind {
case routeCanonical:
@@ -201,11 +196,11 @@ func (current *execution) renderHelpTargets(targets []string) Outcome {
// Explicit help targets are paths, not command invocations with operands.
// Discovery routes have no canonical path and retain only trailing options.
if route.kind == routeUnknown || len(route.args) != len(route.canonicalPath) {
session := internalcobra.Prepare(snapshot.metadata, current.options)
session := internalcobra.Prepare(snapshot.metadata, commandmeta.ParseOptions{})
view := commandmeta.HelpView{EnteredPath: targets, CanonicalPath: targets}
return current.app.renderHelpViewOutcomeWithSession(view, current.reporter, session)
}
options := current.options
options := commandmeta.ParseOptions{}
switch route.kind {
case routeCanonical:
options.FlagAliases = snapshot.flagAliases[route.canonicalPath.Key()].neutralRecords()

View File

@@ -4,7 +4,6 @@ package cobra
import (
"bytes"
"context"
"fmt"
"io"
"strconv"
@@ -35,8 +34,7 @@ func Prepare(root *commandmeta.Command, options commandmeta.ParseOptions) *Sessi
session.metadata = root
session.flagAliases = append([]commandmeta.FlagAlias(nil), options.FlagAliases...)
session.flagAliasesForPath = options.FlagAliasesForPath
options = normalizeOptions(options)
session.root, session.declarations = buildTree(root, options)
session.root, session.declarations = buildTree(root)
return session
}
@@ -289,23 +287,7 @@ func Parse(root *commandmeta.Command, argv []string, options commandmeta.ParseOp
return Prepare(root, options).Parse(argv)
}
func normalizeOptions(options commandmeta.ParseOptions) commandmeta.ParseOptions {
if options.Context == nil {
options.Context = context.Background()
}
if options.In == nil {
options.In = strings.NewReader("")
}
if options.Out == nil {
options.Out = io.Discard
}
if options.Err == nil {
options.Err = io.Discard
}
return options
}
func buildTree(root *commandmeta.Command, options commandmeta.ParseOptions) (*spfcobra.Command, map[*spfcobra.Command]*commandmeta.Command) {
func buildTree(root *commandmeta.Command) (*spfcobra.Command, map[*spfcobra.Command]*commandmeta.Command) {
nodes := make(map[*spfcobra.Command]*commandmeta.Command)
var build func(*commandmeta.Command) *spfcobra.Command
build = func(declaration *commandmeta.Command) *spfcobra.Command {
@@ -321,10 +303,8 @@ func buildTree(root *commandmeta.Command, options commandmeta.ParseOptions) (*sp
if declaration.Runnable {
backend.Run = func(*spfcobra.Command, []string) {}
}
backend.SetContext(options.Context)
backend.SetIn(options.In)
backend.SetOut(options.Out)
backend.SetErr(options.Err)
backend.SetOut(io.Discard)
backend.SetErr(io.Discard)
backend.SetHelpFunc(func(*spfcobra.Command, []string) {})
backend.SetFlagErrorFunc(func(_ *spfcobra.Command, err error) error { return err })
backend.SetUsageTemplate(usageTemplate)

View File

@@ -1,8 +1,6 @@
package cobra
import (
"bytes"
"context"
"fmt"
"io"
"reflect"
@@ -182,7 +180,7 @@ func TestParseReturnsNeutralFailuresAndFreshState(t *testing.T) {
tree := &Command{Name: "app", Children: []*Command{
{Name: "run", Runnable: true, Flags: []Flag{{Name: "value"}}},
}}
options := ParseOptions{Context: context.Background(), In: strings.NewReader("unused"), Out: io.Discard, Err: io.Discard}
options := ParseOptions{}
first := Parse(tree, []string{"run", "--value=old"}, options)
second := Parse(tree, []string{"run"}, options)
if first.Failure != nil || second.Failure != nil {
@@ -247,8 +245,7 @@ func TestSelectedPathsResolveThroughBackendParents(t *testing.T) {
func TestSessionReusesTreeForParseHelpAndUsageWithFreshState(t *testing.T) {
tree := &Command{Name: "app", Children: []*Command{{Name: "run", Runnable: true, Flags: []Flag{{Name: "value"}}}}}
var output, errors bytes.Buffer
session := Prepare(tree, ParseOptions{Context: context.Background(), Out: &output, Err: &errors})
session := Prepare(tree, ParseOptions{})
first := session.Parse([]string{"run", "--value=old"})
if first.Failure != nil || !reflect.DeepEqual(first.FlagValues, [][]string{{"old"}}) {
t.Fatalf("first session parse = %#v", first)
@@ -261,19 +258,15 @@ func TestSessionReusesTreeForParseHelpAndUsageWithFreshState(t *testing.T) {
if failure != nil || !strings.Contains(line, "run") {
t.Fatalf("session usage = %q, %v", line, failure)
}
if output.Len() != 0 || errors.Len() != 0 {
t.Fatalf("help escaped session delivery control: out=%q err=%q", output.String(), errors.String())
if session.root.OutOrStdout() != io.Discard || session.root.ErrOrStderr() != io.Discard {
t.Fatal("backend destinations are not discarded")
}
var secondOutput, secondErrors bytes.Buffer
second := Prepare(tree, ParseOptions{Context: context.Background(), Out: &secondOutput, Err: &secondErrors})
second := Prepare(tree, ParseOptions{})
secondResult := second.Parse([]string{"run"})
if secondResult.Failure != nil || !reflect.DeepEqual(secondResult.FlagValues, [][]string{nil}) {
t.Fatalf("fresh session state = %#v", secondResult)
}
if output.Len() != 0 || errors.Len() != 0 || secondOutput.Len() != 0 || secondErrors.Len() != 0 {
t.Fatal("prepared session streams were unexpectedly used")
}
}
func TestMissingSessionTreeReturnsNeutralFailures(t *testing.T) {

View File

@@ -1,9 +1,7 @@
package cobra
import (
"context"
"fmt"
"io"
"testing"
)
@@ -11,7 +9,7 @@ func BenchmarkPerformanceParse(b *testing.B) {
wide := performanceFlatTree(128)
wideArgs := []string{"wide127"}
deep, deepArgs := performanceNestedTree(24)
options := ParseOptions{Context: context.Background(), Out: io.Discard, Err: io.Discard}
options := ParseOptions{}
for _, benchmark := range []struct {
name string
@@ -41,7 +39,7 @@ func BenchmarkPerformanceParse(b *testing.B) {
func BenchmarkPerformanceSessionParseAndHelp(b *testing.B) {
root := performanceFlatTree(8)
args := []string{"wide007"}
session := Prepare(root, ParseOptions{Context: context.Background(), Out: io.Discard, Err: io.Discard})
session := Prepare(root, ParseOptions{})
result := session.Parse(args)
if result.Failure != nil {
b.Fatalf("fixture parse failed: %s", result.Failure.Message)

View File

@@ -2,11 +2,6 @@
// its command-line backend.
package commandmeta
import (
"context"
"io"
)
// Key identifies one command inside one routing snapshot.
type Key uint64
@@ -181,14 +176,10 @@ type Result struct {
Failure *Failure
}
// ParseOptions makes parser context and streams explicit.
// ParseOptions selects flag aliases for parser contexts.
type ParseOptions struct {
// FlagAliasesForPath selects aliases for the actual parser context when
// routing has not already selected one. It overrides FlagAliases when set.
FlagAliasesForPath func([]string) []FlagAlias
Context context.Context
In io.Reader
Out io.Writer
Err io.Writer
FlagAliases []FlagAlias
}

View File

@@ -5,19 +5,10 @@ import (
"sort"
"strconv"
internalcobra "go.maximumdirect.net/commandkit/internal/cobra"
commandmeta "go.maximumdirect.net/commandkit/internal/commandmeta"
"go.maximumdirect.net/commandkit/internal/commandpath"
)
func (a *App) parse(args []string, options commandmeta.ParseOptions) commandmeta.Result {
if a == nil {
return commandmeta.Result{Failure: &commandmeta.Failure{Message: "cannot parse commands on a nil app"}}
}
result := internalcobra.Parse(a.routeSnapshot().metadata, args, options)
return reduceReportingOccurrences(result)
}
func reduceReportingOccurrences(result commandmeta.Result) commandmeta.Result {
selection := commandmeta.ReportingSelection{}
for index, occurrence := range result.FlagOccurrences {

View File

@@ -34,15 +34,14 @@ func TestAppParseUsesRegisteredBindingsWithTheAdapter(t *testing.T) {
t.Fatal(err)
}
options := commandmeta.ParseOptions{Context: context.Background()}
result := app.parse([]string{"config", "show", "one", "--scope", "app"}, options)
result := parseReportingArgs(app, []string{"config", "show", "one", "--scope", "app"})
if result.Failure != nil {
t.Fatalf("parse failed: %s", result.Failure.Message)
}
if !reflect.DeepEqual(result.Path, []string{"config", "show"}) || !reflect.DeepEqual(result.FlagValues, [][]string{{"app"}}) || !reflect.DeepEqual(result.Operands, []string{"one"}) {
t.Fatalf("parse result = %#v", result)
}
result = app.parse([]string{"config", "--scope", "app", "show"}, options)
result = parseReportingArgs(app, []string{"config", "--scope", "app", "show"})
if result.Failure == nil {
t.Fatal("accepted a child flag before the complete command path")
}
@@ -55,7 +54,7 @@ func TestRoutingSnapshotPairsParsedKeyWithItsRunner(t *testing.T) {
t.Fatal(err)
}
snapshot := app.routeSnapshot()
session := internalcobra.Prepare(snapshot.metadata, commandmeta.ParseOptions{Context: context.Background()})
session := internalcobra.Prepare(snapshot.metadata, commandmeta.ParseOptions{})
parsed := session.Parse([]string{"run"})
if parsed.Failure != nil {
t.Fatalf("parse failed: %s", parsed.Failure.Message)