Skip to content

Commit 0564ba9

Browse files
[Autoloop: python-to-go-migration] Iteration 37: Migrate install/template, runtime/factory, marketplace/registry, marketplace/git_stderr (+588 lines, 24.38%)
Run: https://github.com/githubnext/apm/actions/runs/25847876982 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ffa20d7 commit 0564ba9

6 files changed

Lines changed: 789 additions & 6 deletions

File tree

benchmarks/migration-status.json

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"original_python_lines": 71696,
3-
"migrated_python_lines": 16891,
3+
"migrated_python_lines": 17479,
44
"migrated_modules": [
55
{
66
"module": "src/apm_cli/constants.py",
@@ -624,11 +624,15 @@
624624
"python_lines": 232,
625625
"status": "migrated",
626626
"notes": "Thread-safe shared bare-clone cache"
627-
}
627+
},
628+
"install/template",
629+
"runtime/factory",
630+
"marketplace/registry",
631+
"marketplace/git_stderr"
628632
],
629-
"last_updated": "2026-05-13T16:25:00Z",
630-
"iteration": 25,
631-
"python_lines_migrated_pct": 19.79,
633+
"last_updated": "2026-05-14T07:36:03Z",
634+
"iteration": 26,
635+
"python_lines_migrated_pct": 24.38,
632636
"modules_migrated": [
633637
"policy/models.py",
634638
"models/plugin.py",
@@ -637,6 +641,10 @@
637641
"integration/cleanup.py",
638642
"integration/targets.py",
639643
"deps/lockfile.py",
640-
"install/local_bundle_handler.py"
644+
"install/local_bundle_handler.py",
645+
"install/template",
646+
"runtime/factory",
647+
"marketplace/registry",
648+
"marketplace/git_stderr"
641649
]
642650
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// Package template implements the shared post-acquire integration flow for all DependencySources.
2+
// This is the Template Method companion to the Strategy pattern in install/sources.
3+
package template
4+
5+
// Deltas holds counter-deltas from integration of one package.
6+
type Deltas map[string]int
7+
8+
// PackageInfo is a minimal representation of a resolved package.
9+
type PackageInfo struct {
10+
Name string
11+
Path string
12+
}
13+
14+
// Materialization represents the result of a DependencySource.acquire() call.
15+
type Materialization struct {
16+
InstallPath string
17+
DepKey string
18+
PackageInfo *PackageInfo
19+
Deltas Deltas
20+
}
21+
22+
// IntegrationResult holds integration counts for one package.
23+
type IntegrationResult struct {
24+
Prompts int
25+
Agents int
26+
Skills int
27+
SubSkills int
28+
Instructions int
29+
Commands int
30+
Hooks int
31+
LinksResolved int
32+
DeployedFiles []string
33+
}
34+
35+
// SecurityGateFunc is the signature of the pre-deploy security gate.
36+
type SecurityGateFunc func(installPath, packageName string, force bool) bool
37+
38+
// IntegrateFunc is the signature of the primitive integrator.
39+
type IntegrateFunc func(info *PackageInfo, projectRoot string) (*IntegrationResult, error)
40+
41+
// DiagnosticsCounter supports per-package diagnostic counts.
42+
type DiagnosticsCounter interface {
43+
CountForPackage(depKey, kind string) int
44+
AddError(msg, pkg string)
45+
}
46+
47+
// Logger supports verbose package-inline warnings.
48+
type Logger interface {
49+
Verbose() bool
50+
PackageInlineWarning(msg string)
51+
}
52+
53+
// Config holds all dependencies for RunIntegrationTemplate.
54+
type Config struct {
55+
SecurityGate SecurityGateFunc
56+
Integrate IntegrateFunc
57+
Diagnostics DiagnosticsCounter
58+
Logger Logger
59+
ProjectRoot string
60+
HasTargets bool
61+
Force bool
62+
// IntegrateErrorPrefix is the per-source error prefix (Strategy pattern).
63+
IntegrateErrorPrefix string
64+
// IsLocal indicates whether the dep ref is local (for error key selection).
65+
IsLocal bool
66+
LocalPath string
67+
// PackageDeployedFiles is updated in place.
68+
PackageDeployedFiles map[string][]string
69+
}
70+
71+
// RunIntegrationTemplate runs the shared post-acquire integration flow.
72+
// Returns a counter-delta map, or nil if the materialization is nil (source declined).
73+
func RunIntegrationTemplate(m *Materialization, cfg *Config) Deltas {
74+
if m == nil {
75+
return nil
76+
}
77+
return integrateMaterilaization(m, cfg)
78+
}
79+
80+
func integrateMaterilaization(m *Materialization, cfg *Config) Deltas {
81+
deltas := m.Deltas
82+
if deltas == nil {
83+
deltas = Deltas{}
84+
}
85+
86+
// No-op when targets are empty or acquire decided to skip integration.
87+
if m.PackageInfo == nil || !cfg.HasTargets {
88+
cfg.PackageDeployedFiles[m.DepKey] = []string{}
89+
return deltas
90+
}
91+
92+
defer func() {
93+
// Verbose: inline skip / error count for this package.
94+
if cfg.Logger != nil && cfg.Logger.Verbose() {
95+
skipCount := cfg.Diagnostics.CountForPackage(m.DepKey, "collision")
96+
errCount := cfg.Diagnostics.CountForPackage(m.DepKey, "error")
97+
if skipCount > 0 {
98+
noun := "file"
99+
if skipCount != 1 {
100+
noun = "files"
101+
}
102+
cfg.Logger.PackageInlineWarning(
103+
" [!] " + itoa(skipCount) + " " + noun + " skipped (local files exist)",
104+
)
105+
}
106+
if errCount > 0 {
107+
noun := "error"
108+
if errCount != 1 {
109+
noun = "errors"
110+
}
111+
cfg.Logger.PackageInlineWarning(
112+
" [!] " + itoa(errCount) + " integration " + noun,
113+
)
114+
}
115+
}
116+
}()
117+
118+
// Pre-deploy security gate.
119+
if cfg.SecurityGate != nil {
120+
if !cfg.SecurityGate(m.InstallPath, m.DepKey, cfg.Force) {
121+
cfg.PackageDeployedFiles[m.DepKey] = []string{}
122+
return deltas
123+
}
124+
}
125+
126+
// Primitive integration.
127+
if cfg.Integrate != nil {
128+
result, err := cfg.Integrate(m.PackageInfo, cfg.ProjectRoot)
129+
if err != nil {
130+
packageKey := m.DepKey
131+
if cfg.IsLocal && cfg.LocalPath != "" {
132+
packageKey = cfg.LocalPath
133+
}
134+
cfg.Diagnostics.AddError(cfg.IntegrateErrorPrefix+": "+err.Error(), packageKey)
135+
} else if result != nil {
136+
deltas["prompts"] = result.Prompts
137+
deltas["agents"] = result.Agents
138+
deltas["skills"] = result.Skills
139+
deltas["sub_skills"] = result.SubSkills
140+
deltas["instructions"] = result.Instructions
141+
deltas["commands"] = result.Commands
142+
deltas["hooks"] = result.Hooks
143+
deltas["links_resolved"] = result.LinksResolved
144+
cfg.PackageDeployedFiles[m.DepKey] = result.DeployedFiles
145+
}
146+
}
147+
148+
return deltas
149+
}
150+
151+
// itoa converts an int to a string without importing strconv at call sites.
152+
func itoa(n int) string {
153+
if n == 0 {
154+
return "0"
155+
}
156+
neg := n < 0
157+
if neg {
158+
n = -n
159+
}
160+
buf := make([]byte, 20)
161+
i := len(buf)
162+
for n >= 10 {
163+
i--
164+
buf[i] = byte('0' + n%10)
165+
n /= 10
166+
}
167+
i--
168+
buf[i] = byte('0' + n)
169+
if neg {
170+
i--
171+
buf[i] = '-'
172+
}
173+
return string(buf[i:])
174+
}

0 commit comments

Comments
 (0)