mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 20:14:50 +00:00
pip >= 23.0 added the PEP 668 --break-system-packages flag. On older pip builds (e.g. macOS Command Line Tools Python) and on the pip `list` subcommand of every version, the flag is rejected with "no such option: --break-system-packages", breaking skill dependency install/check paths entirely. - dep_installer: route pip installs through pipRunInstall, which retries once without the flag when pip rejects it (issue #956) - pip_update_executor: same retry for the upgrade path - pip_update_checker: drop the flag from `pip3 list --outdated` - list is read-only, PEP 668 never applies, and no pip accepts the flag there - add pip_flags.go helpers + unit tests, and legacy-pip integration tests reproducing the original failure Fixes #956
50 lines
1.8 KiB
Go
50 lines
1.8 KiB
Go
package skills
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"os/exec"
|
|
)
|
|
|
|
// pipBreakSystemPackagesFlag is the PEP 668 opt-out flag accepted by pip >= 23.0.
|
|
// Older pip builds (and the `list` subcommand on every pip) reject it with
|
|
// "no such option: --break-system-packages", which breaks skill dependency
|
|
// installs on macOS Command Line Tools Python and other legacy environments.
|
|
const pipBreakSystemPackagesFlag = "--break-system-packages"
|
|
|
|
// pipRejectsBSPFlag reports whether pip's combined output indicates the
|
|
// --break-system-packages flag was rejected as an unknown option. pip < 23.0
|
|
// predates PEP 668 and emits exactly this error (see issue #956).
|
|
func pipRejectsBSPFlag(combinedOut []byte) bool {
|
|
return bytes.Contains(combinedOut, []byte("no such option: "+pipBreakSystemPackagesFlag))
|
|
}
|
|
|
|
// dropPipBSPFlag returns args with every --break-system-packages occurrence
|
|
// removed, preserving order of the remaining tokens. Used to retry an install
|
|
// on pip builds that do not support the flag.
|
|
func dropPipBSPFlag(args []string) []string {
|
|
out := make([]string, 0, len(args))
|
|
for _, a := range args {
|
|
if a == pipBreakSystemPackagesFlag {
|
|
continue
|
|
}
|
|
out = append(out, a)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// pipRunInstall runs `pip3 <args...>` where args includes the PEP 668
|
|
// --break-system-packages flag. If pip rejects the flag as an unknown option
|
|
// (pip < 23.0, issue #956), the command is retried once without it. Returns
|
|
// the combined output of the final attempt. Success-path overhead is zero
|
|
// extra subprocesses.
|
|
func pipRunInstall(ctx context.Context, args []string) ([]byte, error) {
|
|
cmd := exec.CommandContext(ctx, pipBinary, args...)
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil && pipRejectsBSPFlag(out) {
|
|
cmd = exec.CommandContext(ctx, pipBinary, dropPipBSPFlag(args)...)
|
|
out, err = cmd.CombinedOutput()
|
|
}
|
|
return out, err
|
|
}
|