错误处理
Go Pip SDK 提供了全面的错误处理机制,帮助您识别、诊断和处理各种操作中可能出现的错误。
错误类型
基本错误接口
所有 SDK 错误都实现了标准的 Go error
接口:
go
if err := manager.InstallPackage(pkg); err != nil {
fmt.Printf("操作失败: %v\n", err)
}
结构化错误
SDK 提供了丰富的错误信息:
go
if err := manager.InstallPackage(pkg); err != nil {
if pipErr, ok := err.(*pip.PipErrorDetails); ok {
fmt.Printf("错误类型: %s\n", pipErr.Type)
fmt.Printf("错误消息: %s\n", pipErr.Message)
fmt.Printf("失败命令: %s\n", pipErr.Command)
fmt.Printf("退出代码: %d\n", pipErr.ExitCode)
fmt.Printf("输出: %s\n", pipErr.Output)
if len(pipErr.Suggestions) > 0 {
fmt.Println("建议:")
for _, suggestion := range pipErr.Suggestions {
fmt.Printf("- %s\n", suggestion)
}
}
}
}
错误分类
系统错误
Python 未找到
go
_, err := manager.IsInstalled()
if err != nil {
if pip.IsErrorType(err, pip.ErrorTypePythonNotFound) {
fmt.Println("Python 未安装或未在 PATH 中")
// 建议解决方案
fmt.Println("解决方案:")
fmt.Println("1. 安装 Python")
fmt.Println("2. 将 Python 添加到 PATH")
fmt.Println("3. 在配置中指定 Python 路径")
// 使用自定义 Python 路径
config := &pip.Config{
PythonPath: "/usr/bin/python3",
}
manager = pip.NewManager(config)
}
}
Pip 未安装
go
installed, err := manager.IsInstalled()
if err != nil {
if pip.IsErrorType(err, pip.ErrorTypePipNotFound) {
fmt.Println("Pip 未安装")
// 自动安装 pip
if err := manager.Install(); err != nil {
fmt.Printf("自动安装 pip 失败: %v\n", err)
} else {
fmt.Println("Pip 安装成功")
}
}
}
网络错误
连接超时
go
err := manager.InstallPackage(pkg)
if err != nil {
if pip.IsErrorType(err, pip.ErrorTypeNetworkTimeout) {
fmt.Println("网络连接超时")
// 增加超时时间重试
config := &pip.Config{
Timeout: 300 * time.Second, // 5 分钟
}
retryManager := pip.NewManager(config)
if err := retryManager.InstallPackage(pkg); err != nil {
fmt.Printf("重试失败: %v\n", err)
}
}
}
网络连接错误
go
err := manager.InstallPackage(pkg)
if err != nil {
if pip.IsErrorType(err, pip.ErrorTypeNetworkError) {
fmt.Println("网络连接失败")
// 尝试使用镜像源
config := &pip.Config{
DefaultIndex: "https://pypi.tuna.tsinghua.edu.cn/simple/",
TrustedHosts: []string{"pypi.tuna.tsinghua.edu.cn"},
}
mirrorManager := pip.NewManager(config)
if err := mirrorManager.InstallPackage(pkg); err != nil {
fmt.Printf("使用镜像源仍然失败: %v\n", err)
}
}
}
包相关错误
包未找到
go
err := manager.InstallPackage(pkg)
if err != nil {
if pip.IsErrorType(err, pip.ErrorTypePackageNotFound) {
fmt.Printf("包 '%s' 未找到\n", pkg.Name)
// 搜索相似包名
results, searchErr := manager.SearchPackages(pkg.Name)
if searchErr == nil && len(results) > 0 {
fmt.Println("您是否想要安装以下包之一:")
for i, result := range results[:5] { // 显示前5个结果
fmt.Printf("%d. %s - %s\n", i+1, result.Name, result.Summary)
}
}
}
}
版本冲突
go
err := manager.InstallPackage(pkg)
if err != nil {
if pip.IsErrorType(err, pip.ErrorTypeVersionConflict) {
fmt.Printf("版本冲突: %s\n", err.Error())
// 显示当前已安装的版本
if info, showErr := manager.ShowPackage(pkg.Name); showErr == nil {
fmt.Printf("当前安装版本: %s\n", info.Version)
fmt.Printf("请求版本: %s\n", pkg.Version)
}
// 建议解决方案
fmt.Println("解决方案:")
fmt.Println("1. 更新版本约束")
fmt.Println("2. 使用虚拟环境")
fmt.Println("3. 强制重新安装")
}
}
权限错误
go
err := manager.InstallPackage(pkg)
if err != nil {
if pip.IsErrorType(err, pip.ErrorTypePermissionDenied) {
fmt.Println("权限被拒绝")
// 建议解决方案
fmt.Println("解决方案:")
fmt.Println("1. 使用虚拟环境 (推荐)")
fmt.Println("2. 使用 --user 标志")
fmt.Println("3. 以管理员身份运行")
// 尝试用户级安装
userPkg := &pip.PackageSpec{
Name: pkg.Name,
Options: map[string]string{
"user": "",
},
}
if err := manager.InstallPackage(userPkg); err != nil {
fmt.Printf("用户级安装也失败: %v\n", err)
}
}
}
错误处理模式
基本错误处理
go
func handleBasicError(err error) {
if err == nil {
return
}
fmt.Printf("操作失败: %v\n", err)
// 记录错误
log.Printf("Error: %v", err)
}
详细错误处理
go
func handleDetailedError(err error) {
if err == nil {
return
}
pipErr, ok := err.(*pip.PipErrorDetails)
if !ok {
fmt.Printf("未知错误: %v\n", err)
return
}
fmt.Printf("错误类型: %s\n", pipErr.Type)
fmt.Printf("消息: %s\n", pipErr.Message)
if pipErr.Command != "" {
fmt.Printf("失败的命令: %s\n", pipErr.Command)
}
if pipErr.ExitCode != 0 {
fmt.Printf("退出代码: %d\n", pipErr.ExitCode)
}
if len(pipErr.Suggestions) > 0 {
fmt.Println("建议:")
for _, suggestion := range pipErr.Suggestions {
fmt.Printf("- %s\n", suggestion)
}
}
if pipErr.Cause != nil {
fmt.Printf("根本原因: %v\n", pipErr.Cause)
}
}
重试机制
go
func installWithRetry(manager *pip.Manager, pkg *pip.PackageSpec, maxRetries int) error {
var lastErr error
for i := 0; i < maxRetries; i++ {
err := manager.InstallPackage(pkg)
if err == nil {
return nil // 成功
}
lastErr = err
// 检查是否为可重试的错误
if pip.IsErrorType(err, pip.ErrorTypeNetworkError) ||
pip.IsErrorType(err, pip.ErrorTypeNetworkTimeout) {
fmt.Printf("网络错误,重试 %d/%d...\n", i+1, maxRetries)
time.Sleep(time.Duration(i+1) * time.Second) // 指数退避
continue
}
// 非网络错误,不重试
return err
}
return fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr)
}
错误恢复
go
func installPackageWithRecovery(manager *pip.Manager, pkg *pip.PackageSpec) error {
err := manager.InstallPackage(pkg)
if err == nil {
return nil
}
switch pip.GetErrorType(err) {
case pip.ErrorTypePackageNotFound:
// 尝试搜索相似包名
return suggestAlternativePackages(manager, pkg.Name)
case pip.ErrorTypeVersionConflict:
// 尝试安装兼容版本
return installCompatibleVersion(manager, pkg)
case pip.ErrorTypePermissionDenied:
// 尝试用户级安装
return installAsUser(manager, pkg)
case pip.ErrorTypeNetworkError:
// 尝试使用镜像源
return installFromMirror(manager, pkg)
default:
return err
}
}
func suggestAlternativePackages(manager *pip.Manager, packageName string) error {
results, err := manager.SearchPackages(packageName)
if err != nil {
return fmt.Errorf("搜索替代包失败: %w", err)
}
if len(results) == 0 {
return fmt.Errorf("未找到包 '%s' 的替代方案", packageName)
}
fmt.Printf("未找到包 '%s',但找到以下相似包:\n", packageName)
for i, result := range results[:3] {
fmt.Printf("%d. %s - %s\n", i+1, result.Name, result.Summary)
}
return fmt.Errorf("请检查包名是否正确")
}
错误日志记录
基本日志记录
go
func logError(err error, operation string) {
if err == nil {
return
}
log.Printf("[ERROR] %s failed: %v", operation, err)
if pipErr, ok := err.(*pip.PipErrorDetails); ok {
log.Printf("[ERROR] Type: %s, Command: %s, ExitCode: %d",
pipErr.Type, pipErr.Command, pipErr.ExitCode)
}
}
结构化日志记录
go
import (
"encoding/json"
"log"
)
func logStructuredError(err error, operation string, context map[string]interface{}) {
if err == nil {
return
}
logEntry := map[string]interface{}{
"level": "error",
"operation": operation,
"error": err.Error(),
"timestamp": time.Now().UTC(),
"context": context,
}
if pipErr, ok := err.(*pip.PipErrorDetails); ok {
logEntry["error_type"] = pipErr.Type
logEntry["command"] = pipErr.Command
logEntry["exit_code"] = pipErr.ExitCode
logEntry["suggestions"] = pipErr.Suggestions
}
jsonLog, _ := json.Marshal(logEntry)
log.Println(string(jsonLog))
}
错误监控和报告
错误统计
go
type ErrorStats struct {
Total int
ByType map[pip.ErrorType]int
ByOperation map[string]int
mutex sync.RWMutex
}
func (s *ErrorStats) RecordError(err error, operation string) {
s.mutex.Lock()
defer s.mutex.Unlock()
s.Total++
s.ByOperation[operation]++
if pipErr, ok := err.(*pip.PipErrorDetails); ok {
s.ByType[pipErr.Type]++
}
}
func (s *ErrorStats) GetStats() map[string]interface{} {
s.mutex.RLock()
defer s.mutex.RUnlock()
return map[string]interface{}{
"total": s.Total,
"by_type": s.ByType,
"by_operation": s.ByOperation,
}
}
错误报告
go
func generateErrorReport(stats *ErrorStats) string {
data := stats.GetStats()
report := fmt.Sprintf("错误报告 (总计: %d)\n", data["total"])
report += "===================\n\n"
report += "按类型分组:\n"
for errorType, count := range data["by_type"].(map[pip.ErrorType]int) {
report += fmt.Sprintf("- %s: %d\n", errorType, count)
}
report += "\n按操作分组:\n"
for operation, count := range data["by_operation"].(map[string]int) {
report += fmt.Sprintf("- %s: %d\n", operation, count)
}
return report
}
最佳实践
1. 总是检查错误
go
// 好的做法
if err := manager.InstallPackage(pkg); err != nil {
handleError(err)
return
}
// 不好的做法
manager.InstallPackage(pkg) // 忽略错误
2. 提供有用的错误消息
go
func installPackage(manager *pip.Manager, packageName string) error {
pkg := &pip.PackageSpec{Name: packageName}
if err := manager.InstallPackage(pkg); err != nil {
return fmt.Errorf("安装包 '%s' 失败: %w", packageName, err)
}
return nil
}
3. 使用适当的错误处理策略
go
func robustInstallPackage(manager *pip.Manager, pkg *pip.PackageSpec) error {
// 1. 首先尝试正常安装
if err := manager.InstallPackage(pkg); err == nil {
return nil
}
// 2. 如果失败,尝试重试机制
if err := installWithRetry(manager, pkg, 3); err == nil {
return nil
}
// 3. 如果仍然失败,尝试错误恢复
return installPackageWithRecovery(manager, pkg)
}
4. 记录错误上下文
go
func installPackageWithContext(manager *pip.Manager, pkg *pip.PackageSpec) error {
context := map[string]interface{}{
"package_name": pkg.Name,
"version": pkg.Version,
"timestamp": time.Now(),
}
if err := manager.InstallPackage(pkg); err != nil {
logStructuredError(err, "install_package", context)
return err
}
return nil
}