validatePythonPackagesWithPip is a generic helper that validates Python packages using pip index. It accepts a package list, package type name for error messaging, and pip command to use.
(packages []string, packageType string, pipCmd string)
| 50 | // validatePythonPackagesWithPip is a generic helper that validates Python packages using pip index. |
| 51 | // It accepts a package list, package type name for error messaging, and pip command to use. |
| 52 | func (c *Compiler) validatePythonPackagesWithPip(packages []string, packageType string, pipCmd string) { |
| 53 | pipValidationLog.Printf("Validating %d %s packages using %s", len(packages), packageType, pipCmd) |
| 54 | |
| 55 | for _, pkg := range packages { |
| 56 | // Extract package name without version specifier |
| 57 | pkgName := pkg |
| 58 | if eqIndex := strings.Index(pkg, "=="); eqIndex > 0 { |
| 59 | pkgName = pkg[:eqIndex] |
| 60 | } |
| 61 | |
| 62 | // Reject names starting with '-' to prevent argument injection |
| 63 | if strings.HasPrefix(pkgName, "-") { |
| 64 | fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("%s package name '%s' is invalid: names must not start with '-'", packageType, pkg))) |
| 65 | continue |
| 66 | } |
| 67 | |
| 68 | // Validate the package name against PyPI naming rules (PEP 508). |
| 69 | // pip does not universally honour '--', so we validate upfront. |
| 70 | if err := validatePipPackageName(pkgName); err != nil { |
| 71 | fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("%s package name '%s' is invalid: %v", packageType, pkg, err))) |
| 72 | continue |
| 73 | } |
| 74 | |
| 75 | pipValidationLog.Printf("Validating %s package: %s", packageType, pkgName) |
| 76 | |
| 77 | // Use pip index to check if package exists on PyPI |
| 78 | // Include --pre flag to check for pre-release versions (alpha, beta, rc) |
| 79 | cmd := exec.Command(pipCmd, "index", "versions", pkgName, "--pre") |
| 80 | output, err := cmd.CombinedOutput() |
| 81 | |
| 82 | if err != nil { |
| 83 | outputStr := strings.TrimSpace(string(output)) |
| 84 | pipValidationLog.Printf("Package validation failed for %s: %v", pkg, err) |
| 85 | // Treat all pip validation errors as warnings, not compilation failures |
| 86 | // The package may be experimental, not yet published, or will be installed at runtime |
| 87 | fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("%s package '%s' validation failed - skipping verification. Package may or may not exist on PyPI.", packageType, pkg))) |
| 88 | if c.verbose { |
| 89 | fmt.Fprintln(os.Stderr, console.FormatWarningMessage(" Details: "+outputStr)) |
| 90 | } |
| 91 | } else { |
| 92 | pipValidationLog.Printf("Package validated successfully: %s", pkg) |
| 93 | if c.verbose { |
| 94 | fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("✓ %s package validated: %s", packageType, pkg))) |
| 95 | } |
| 96 | } |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | // validatePipPackages validates that pip packages are available on PyPI |
| 101 | func (c *Compiler) validatePipPackages(workflowData *WorkflowData) error { |
no test coverage detected