Prepare recovery tools for the host target
This commit is contained in:
@@ -57,8 +57,8 @@ func TestVendoredAPIOnlyPublicationRecovery(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
launcher := exec.Command(goBinary, append(launcherArgs, "publish", "--repo", repo, "v1.2.3")...)
|
||||
launcher.Dir = t.TempDir()
|
||||
launcher := exec.Command(goBinary, append(launcherArgs.Args, "publish", "--repo", repo, "v1.2.3")...)
|
||||
launcher.Dir = launcherArgs.Directory
|
||||
publicationOutput, err := launcher.CombinedOutput()
|
||||
var exitError *exec.ExitError
|
||||
if !errors.As(err, &exitError) || exitError.ExitCode() != 1 {
|
||||
@@ -98,12 +98,29 @@ func TestRecoveryToolPreservesVersionedReplacement(t *testing.T) {
|
||||
if err := os.WriteFile(filepath.Join(module, "go.mod"), []byte(data), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shimDir := t.TempDir()
|
||||
logPath := filepath.Join(t.TempDir(), "target")
|
||||
realGo := filepath.Join(runtime.GOROOT(), "bin", "go")
|
||||
shim := "#!/bin/sh\ncase \" $* \" in *\" -deps \"*) printf '%s/%s\\n' \"$GOOS\" \"$GOARCH\" > \"$RECOVERY_TARGET_LOG\" ;; esac\nexec \"$RECOVERY_REAL_GO\" \"$@\"\n"
|
||||
if err := os.WriteFile(filepath.Join(shimDir, "go"), []byte(shim), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("RECOVERY_TARGET_LOG", logPath)
|
||||
t.Setenv("RECOVERY_REAL_GO", realGo)
|
||||
t.Setenv("PATH", shimDir+string(os.PathListSeparator)+os.Getenv("PATH"))
|
||||
foreignOS, foreignArch := foreignTarget()
|
||||
t.Setenv("GOOS", foreignOS)
|
||||
t.Setenv("GOARCH", foreignArch)
|
||||
args, err := gotool.RecoveryTool(t.Context(), module, t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
command := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), args...)
|
||||
command.Dir = t.TempDir()
|
||||
if target, err := os.ReadFile(logPath); err != nil || strings.TrimSpace(string(target)) != runtime.GOOS+"/"+runtime.GOARCH {
|
||||
t.Fatalf("recovery preparation target = %q, %v", target, err)
|
||||
}
|
||||
command := exec.Command(realGo, args.Args...)
|
||||
command.Dir = args.Directory
|
||||
command.Env = setEnvironment(setEnvironment(os.Environ(), "GOOS", runtime.GOOS), "GOARCH", runtime.GOARCH)
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil || !strings.Contains(string(output), "tool-version=v0.2.198 helper=tool-only dependency") {
|
||||
t.Fatalf("versioned recovery selection: %v: %s", err, output)
|
||||
@@ -119,8 +136,8 @@ func TestRecoveryToolSupportsReleaseKitSourceModule(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
command := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), append(args, "version")...)
|
||||
command.Dir = t.TempDir()
|
||||
command := exec.Command(filepath.Join(runtime.GOROOT(), "bin", "go"), append(args.Args, "version")...)
|
||||
command.Dir = args.Directory
|
||||
output, err := command.CombinedOutput()
|
||||
if err != nil || !strings.HasPrefix(string(output), "releasekit ") {
|
||||
t.Fatalf("source module recovery entry point: %v: %s", err, output)
|
||||
|
||||
@@ -96,6 +96,8 @@ checks in Stage 6.
|
||||
|
||||
## Stage 4: Normalize module-based recovery preparation
|
||||
|
||||
**Completed.** The CLI adapter and assembled handoff tests follow in the next stage.
|
||||
|
||||
1. In [the Go recovery implementation](../../internal/gotool/recovery.go),
|
||||
keep the existing registered-tool, API-only, and no-dependency selections.
|
||||
Have `RecoveryTool` return `(*RecoveryInvocation, error)` within the
|
||||
|
||||
@@ -43,10 +43,16 @@ func TemporaryExecutable(path string) bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// RecoveryTool returns module-selected Go arguments for a later invocation.
|
||||
// An empty result means this module does not select ReleaseKit. API-only modules
|
||||
// RecoveryInvocation describes a module-selected Go tool invocation.
|
||||
type RecoveryInvocation struct {
|
||||
Directory string
|
||||
Args []string
|
||||
}
|
||||
|
||||
// RecoveryTool returns a module-selected Go invocation for later use.
|
||||
// A nil result means this module does not select ReleaseKit. API-only modules
|
||||
// receive a private module root that outlives launcher-owned bootstraps.
|
||||
func RecoveryTool(ctx context.Context, moduleDir, recordDir string) ([]string, error) {
|
||||
func RecoveryTool(ctx context.Context, moduleDir, recordDir string) (*RecoveryInvocation, error) {
|
||||
path := filepath.Join(moduleDir, "go.mod")
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -58,7 +64,7 @@ func RecoveryTool(ctx context.Context, moduleDir, recordDir string) ([]string, e
|
||||
}
|
||||
for _, tool := range module.Tool {
|
||||
if tool.Path == releaseKitCommand {
|
||||
return []string{"-C", moduleDir, "tool", "-modfile=", releaseKitCommand}, nil
|
||||
return &RecoveryInvocation{Directory: moduleDir, Args: []string{"tool", "-modfile=", releaseKitCommand}}, nil
|
||||
}
|
||||
}
|
||||
// Ask Go about the selected module graph, including transitive dependencies.
|
||||
@@ -140,15 +146,31 @@ func RecoveryTool(ctx context.Context, moduleDir, recordDir string) ([]string, e
|
||||
return nil, err
|
||||
}
|
||||
// Prepare the private graph and sums before the later tool invocation.
|
||||
environment := map[string]string{"GOWORK": "off", "GOTOOLCHAIN": "local"}
|
||||
hostJSON, err := discover(ctx, directory, environment, "go", "env", "-json", "GOHOSTOS", "GOHOSTARCH")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("prepare recovery tool: %w", err)
|
||||
}
|
||||
var host struct {
|
||||
GOHOSTOS string
|
||||
GOHOSTARCH string
|
||||
}
|
||||
if err := json.Unmarshal(hostJSON, &host); err != nil {
|
||||
return nil, fmt.Errorf("prepare recovery tool: decode host target: %w", err)
|
||||
}
|
||||
if host.GOHOSTOS == "" || host.GOHOSTARCH == "" {
|
||||
return nil, fmt.Errorf("prepare recovery tool: missing host target")
|
||||
}
|
||||
environment["GOOS"], environment["GOARCH"] = host.GOHOSTOS, host.GOHOSTARCH
|
||||
captured := &combinedWriter{mode: captureStatus}
|
||||
err = process.Run(ctx, process.Invocation{
|
||||
Args: []string{"go", "list", "-mod=mod", "-modfile=", "-deps", releaseKitCommand},
|
||||
Dir: directory, Env: map[string]string{"GOWORK": "off", "GOTOOLCHAIN": "local"},
|
||||
Dir: directory, Env: environment,
|
||||
Stdout: captured, Stderr: captured,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("prepare recovery tool: %w: %s", err, diagnosticText(captured.take(), captured.omitted()))
|
||||
}
|
||||
complete = true
|
||||
return []string{"-C", directory, "tool", "-modfile=", releaseKitCommand}, nil
|
||||
return &RecoveryInvocation{Directory: directory, Args: []string{"tool", "-modfile=", releaseKitCommand}}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user