done
This commit is contained in:
40
Makefile
40
Makefile
@@ -16,7 +16,7 @@ all: test build ## Run tests and build binary
|
||||
build: ## Build the binary for current platform
|
||||
@echo "🔨 Building $(BINARY_NAME) v$(VERSION)..."
|
||||
go build $(LDFLAGS) -o $(BINARY_NAME) .
|
||||
@echo "✅ Build complete: ./$(BINARY_NAME)"
|
||||
@echo "Build complete: ./$(BINARY_NAME)"
|
||||
|
||||
build-all: ## Build binaries for all platforms
|
||||
@echo "🏗️ Building for all platforms..."
|
||||
@@ -26,53 +26,53 @@ build-all: ## Build binaries for all platforms
|
||||
GOOS=linux GOARCH=386 go build $(LDFLAGS) -o dist/$(BINARY_NAME)-linux-386 .
|
||||
GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o dist/$(BINARY_NAME)-darwin-amd64 .
|
||||
GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o dist/$(BINARY_NAME)-darwin-arm64 .
|
||||
@echo "✅ Multi-platform build complete in ./dist/"
|
||||
@echo "Multi-platform build complete in ./dist/"
|
||||
|
||||
test: ## Run tests
|
||||
@echo "🧪 Running tests..."
|
||||
go test -v ./...
|
||||
@echo "✅ Tests complete"
|
||||
@echo "Tests complete"
|
||||
|
||||
test-coverage: ## Run tests with coverage
|
||||
@echo "🧪 Running tests with coverage..."
|
||||
go test -coverprofile=coverage.out ./...
|
||||
go tool cover -html=coverage.out -o coverage.html
|
||||
@echo "✅ Coverage report generated: coverage.html"
|
||||
@echo "Coverage report generated: coverage.html"
|
||||
|
||||
fmt: ## Format code
|
||||
@echo "🎨 Formatting code..."
|
||||
@echo "Formatting code..."
|
||||
go fmt ./...
|
||||
@echo "✅ Code formatted"
|
||||
@echo "Code formatted"
|
||||
|
||||
lint: ## Run linters
|
||||
@echo "🔍 Running linters..."
|
||||
@echo "Running linters..."
|
||||
@if command -v golangci-lint >/dev/null 2>&1; then \
|
||||
golangci-lint run; \
|
||||
else \
|
||||
echo "⚠️ golangci-lint not installed. Install with: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
|
||||
echo "golangci-lint not installed. Install with: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
|
||||
go vet ./...; \
|
||||
fi
|
||||
@echo "✅ Linting complete"
|
||||
@echo "Linting complete"
|
||||
|
||||
clean: ## Clean build artifacts
|
||||
@echo "🧹 Cleaning up..."
|
||||
@echo "Cleaning up..."
|
||||
rm -f $(BINARY_NAME)
|
||||
rm -rf dist/
|
||||
rm -f coverage.out coverage.html
|
||||
@echo "✅ Clean complete"
|
||||
@echo "Clean complete"
|
||||
|
||||
install: build ## Install binary to /usr/local/bin
|
||||
@echo "📦 Installing $(BINARY_NAME) to /usr/local/bin..."
|
||||
@echo "Installing $(BINARY_NAME) to /usr/local/bin..."
|
||||
sudo cp $(BINARY_NAME) /usr/local/bin/
|
||||
@echo "✅ Installation complete"
|
||||
@echo "Installation complete"
|
||||
|
||||
uninstall: ## Remove binary from /usr/local/bin
|
||||
@echo "🗑️ Uninstalling $(BINARY_NAME)..."
|
||||
@echo "Uninstalling $(BINARY_NAME)..."
|
||||
sudo rm -f /usr/local/bin/$(BINARY_NAME)
|
||||
@echo "✅ Uninstallation complete"
|
||||
@echo "Uninstallation complete"
|
||||
|
||||
package: build-all ## Create distribution packages
|
||||
@echo "📦 Creating packages..."
|
||||
@echo "Creating packages..."
|
||||
@mkdir -p dist/packages
|
||||
|
||||
# Create tar.gz archives
|
||||
@@ -84,7 +84,7 @@ package: build-all ## Create distribution packages
|
||||
fi \
|
||||
done
|
||||
|
||||
@echo "✅ Packages created in dist/packages/"
|
||||
@echo "Packages created in dist/packages/"
|
||||
|
||||
release: clean test package ## Prepare a release
|
||||
@echo "🚀 Release $(VERSION) ready!"
|
||||
@@ -95,7 +95,7 @@ deps: ## Download dependencies
|
||||
@echo "📥 Downloading dependencies..."
|
||||
go mod download
|
||||
go mod tidy
|
||||
@echo "✅ Dependencies updated"
|
||||
@echo "Dependencies updated"
|
||||
|
||||
dev-deps: ## Install development dependencies
|
||||
@echo "🛠️ Installing development dependencies..."
|
||||
@@ -103,7 +103,7 @@ dev-deps: ## Install development dependencies
|
||||
echo "Installing golangci-lint..."; \
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest; \
|
||||
fi
|
||||
@echo "✅ Development dependencies installed"
|
||||
@echo "Development dependencies installed"
|
||||
|
||||
run: build ## Build and run the application
|
||||
@echo "🏃 Running $(BINARY_NAME)..."
|
||||
@@ -114,7 +114,7 @@ demo: build ## Run a demo of the find command
|
||||
./$(BINARY_NAME) find --top 3
|
||||
|
||||
check: fmt lint test ## Run all checks (format, lint, test)
|
||||
@echo "✅ All checks passed!"
|
||||
@echo "All checks passed!"
|
||||
|
||||
help: ## Show this help message
|
||||
@echo "FastestMirror Build System"
|
||||
|
@@ -1,99 +0,0 @@
|
||||
# FastestMirror Project Summary
|
||||
|
||||
## Project Overview
|
||||
FastestMirror is a professional Go application that automatically detects Linux distributions and finds the fastest package repository mirrors. It's designed to be both technically impressive and subtly entertaining - perfect for a resume project.
|
||||
|
||||
## Key Technical Features
|
||||
|
||||
### 🏗️ Architecture
|
||||
- **Clean Architecture**: Organized with `cmd/`, `internal/`, and `pkg/` structure following Go best practices
|
||||
- **Modular Design**: Separate packages for distribution detection, mirror testing, and configuration management
|
||||
- **Concurrent Processing**: Uses Go goroutines for parallel mirror testing
|
||||
- **Error Handling**: Robust error handling throughout with meaningful error messages
|
||||
|
||||
### 🔍 Distribution Detection
|
||||
- Parses `/etc/os-release`, `/etc/lsb-release`, and fallback detection methods
|
||||
- Supports major Linux families: Debian, Arch, Fedora, openSUSE, Gentoo, Alpine, etc.
|
||||
- Graceful fallback mechanisms for edge cases
|
||||
|
||||
### ⚡ Mirror Testing Infrastructure
|
||||
- Concurrent HTTP speed testing with configurable timeouts
|
||||
- Latency measurement and download speed calculation
|
||||
- Smart scoring algorithm combining multiple metrics
|
||||
- Proper connection handling and resource cleanup
|
||||
|
||||
### 🎨 User Experience
|
||||
- Beautiful CLI interface with colors and progress bars
|
||||
- Professional help text with subtle humor
|
||||
- Comprehensive command structure with subcommands
|
||||
- Safe operations with backup and dry-run modes
|
||||
|
||||
### 🔧 Configuration Management
|
||||
- Safe backup creation with timestamps
|
||||
- Support for major package manager configurations
|
||||
- Atomic operations with rollback capability
|
||||
- Proper permission handling and root privilege checks
|
||||
|
||||
## Commands Implemented
|
||||
|
||||
### `fastestmirror find`
|
||||
- Auto-detects distribution
|
||||
- Tests mirrors concurrently
|
||||
- Shows ranked results with performance metrics
|
||||
- Configurable timeout and result count
|
||||
|
||||
### `fastestmirror apply`
|
||||
- Requires appropriate privileges
|
||||
- Creates automatic backups
|
||||
- Applies fastest mirror safely
|
||||
- Provides post-application instructions
|
||||
|
||||
### `fastestmirror version`
|
||||
- Shows build information
|
||||
- Displays Go version and architecture
|
||||
- Links to repository
|
||||
|
||||
## Technical Highlights
|
||||
|
||||
### Dependencies
|
||||
- **Cobra**: Professional CLI framework
|
||||
- **Color Libraries**: Beautiful terminal output
|
||||
- **Progress Bars**: Visual feedback during operations
|
||||
- **Standard Library**: Extensive use of Go's robust standard library
|
||||
|
||||
### Code Quality
|
||||
- Comprehensive error handling
|
||||
- Clean separation of concerns
|
||||
- Concurrent operations with proper synchronization
|
||||
- Resource management and cleanup
|
||||
|
||||
### Safety Features
|
||||
- Automatic configuration backups
|
||||
- Dry-run mode for testing
|
||||
- Root privilege validation
|
||||
- Rollback capabilities on failure
|
||||
|
||||
## Subtle Humor Elements
|
||||
The project includes professional yet entertaining elements:
|
||||
- Witty error messages ("your connection might be fucked")
|
||||
- Humorous descriptions in help text
|
||||
- Satirical comments in code and documentation
|
||||
- Professional tone with personality
|
||||
|
||||
## Resume Value
|
||||
This project demonstrates:
|
||||
- **Go Proficiency**: Modern Go idioms and best practices
|
||||
- **Systems Programming**: Linux distribution detection and configuration management
|
||||
- **Concurrent Programming**: Goroutines and proper synchronization
|
||||
- **CLI Development**: Professional command-line interface design
|
||||
- **Error Handling**: Robust error management and user feedback
|
||||
- **Testing Infrastructure**: Network operations and performance measurement
|
||||
- **Software Architecture**: Clean, modular design patterns
|
||||
|
||||
## Repository
|
||||
- **Location**: `https://git.gostacks.org/iwasforcedtobehere/fastestmirror`
|
||||
- **Author**: `@iwasforcedtobehere`
|
||||
- **License**: MIT
|
||||
- **Build System**: Comprehensive Makefile with cross-platform builds
|
||||
|
||||
This project showcases technical competence while maintaining personality - exactly what makes a great resume project stand out!
|
30
README.md
30
README.md
@@ -4,14 +4,14 @@
|
||||
|
||||
FastestMirror is a blazingly fast, auto-magical tool that finds and configures the fastest package repository mirrors for your Linux distribution. No more suffering through downloads that move slower than continental drift!
|
||||
|
||||
## Features That'll Make You Smile 😊
|
||||
## Features
|
||||
|
||||
- **🔍 Auto-Detection**: Automatically detects your Linux distribution (because we're not psychic, but we're pretty close)
|
||||
- **⚡ Concurrent Testing**: Tests multiple mirrors simultaneously using Go's goroutines (multithreading that actually works)
|
||||
- **🎨 Beautiful Output**: Colorful terminal interface that doesn't make your eyes bleed
|
||||
- **📊 Smart Scoring**: Combines speed and latency metrics to find the objectively best mirror
|
||||
- **🔒 Safe Operations**: Always backs up your config before making changes (we're not monsters)
|
||||
- **🌍 Wide Support**: Works with major Linux distributions and their families
|
||||
- **Auto-Detection**: Automatically detects your Linux distribution (because we're not psychic, but we're pretty close)
|
||||
- **Concurrent Testing**: Tests multiple mirrors simultaneously using Go's goroutines (multithreading that actually works)
|
||||
- **Beautiful Output**: Colorful terminal interface that doesn't make your eyes bleed
|
||||
- **Smart Scoring**: Combines speed and latency metrics to find the objectively best mirror
|
||||
- **Safe Operations**: Always backs up your config before making changes (we're not monsters)
|
||||
- **Wide Support**: Works with major Linux distributions and their families
|
||||
|
||||
## Supported Distributions
|
||||
|
||||
@@ -120,13 +120,13 @@ fastestmirror find --help
|
||||
## Example Output
|
||||
|
||||
```
|
||||
🔍 Detecting your Linux distribution...
|
||||
📦 Found: Ubuntu 22.04.3 LTS (debian family)
|
||||
🔧 Loading mirrors for debian family...
|
||||
⚡ Testing 8 mirrors (timeout: 10s)...
|
||||
Detecting your Linux distribution...
|
||||
Found: Ubuntu 22.04.3 LTS (debian family)
|
||||
Loading mirrors for debian family...
|
||||
Testing 8 mirrors (timeout: 10s)...
|
||||
Testing mirrors ████████████████████████████████████████████████████ 8/8
|
||||
|
||||
🎉 Testing complete! Here are your results:
|
||||
Testing complete! Here are your results:
|
||||
|
||||
Rank Mirror URL Latency Speed Score
|
||||
─────────────────────────────────────────────────────────────────────────────────
|
||||
@@ -136,10 +136,10 @@ Rank Mirror URL Latency Speed Sco
|
||||
#4 http://archive.ubuntu.com/ubuntu/ 234ms 6.2 MB/s 66.3
|
||||
#5 http://us.archive.ubuntu.com/ubuntu/ 312ms 4.1 MB/s 44.2
|
||||
|
||||
🏆 Winner: http://mirror.kakao.com/ubuntu/
|
||||
⚡ This bad boy clocks in at 15.2 MB/s with 45ms latency
|
||||
Winner: http://mirror.kakao.com/ubuntu/
|
||||
This bad boy clocks in at 15.2 MB/s with 45ms latency
|
||||
|
||||
💡 To apply the fastest mirror, run: fastestmirror apply
|
||||
To apply the fastest mirror, run: fastestmirror apply
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
26
cmd/apply.go
26
cmd/apply.go
@@ -47,7 +47,7 @@ func runApply(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// Detect distribution
|
||||
fmt.Println("🔍 Detecting distribution...")
|
||||
fmt.Println("Detecting distribution...")
|
||||
distroInfo, err := distro.DetectDistribution()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not detect distribution: %w", err)
|
||||
@@ -73,7 +73,7 @@ func runApply(cmd *cobra.Command, args []string) error {
|
||||
configManager := config.NewConfigManager(distroInfo)
|
||||
|
||||
// First, find the fastest mirror
|
||||
fmt.Printf("🔍 Finding fastest mirror for %s...\n", color.YellowString(distroInfo.Family))
|
||||
fmt.Printf("Finding fastest mirror for %s...\n", color.YellowString(distroInfo.Family))
|
||||
|
||||
mirrorList := mirror.NewMirrorList(distroInfo.Family)
|
||||
|
||||
@@ -95,12 +95,12 @@ func runApply(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("no working mirrors found - your connection might be fucked")
|
||||
}
|
||||
|
||||
fmt.Printf("🏆 Best mirror found: %s\n", color.GreenString(bestMirror.URL))
|
||||
fmt.Printf("⚡ Speed: %.1f MB/s, Latency: %dms\n", bestMirror.Speed, bestMirror.Latency.Milliseconds())
|
||||
fmt.Printf("Best mirror found: %s\n", color.GreenString(bestMirror.URL))
|
||||
fmt.Printf("Speed: %.1f MB/s, Latency: %dms\n", bestMirror.Speed, bestMirror.Latency.Milliseconds())
|
||||
|
||||
// Ask for confirmation unless forced
|
||||
if !force {
|
||||
fmt.Printf("\n⚠️ This will modify %s\n", color.YellowString(configFile))
|
||||
fmt.Printf("\nThis will modify %s\n", color.YellowString(configFile))
|
||||
fmt.Print("Do you want to continue? [y/N]: ")
|
||||
|
||||
var response string
|
||||
@@ -113,33 +113,33 @@ func runApply(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// Create backup
|
||||
fmt.Println("💾 Creating backup...")
|
||||
fmt.Println("Creating backup...")
|
||||
backupPath, err := configManager.BackupConfig()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create backup: %w", err)
|
||||
}
|
||||
fmt.Printf("✅ Backup created: %s\n", color.GreenString(backupPath))
|
||||
fmt.Printf("Backup created: %s\n", color.GreenString(backupPath))
|
||||
|
||||
// Apply the fastest mirror
|
||||
fmt.Println("🔧 Applying fastest mirror configuration...")
|
||||
fmt.Println("Applying fastest mirror configuration...")
|
||||
err = configManager.ApplyMirror(bestMirror.URL)
|
||||
if err != nil {
|
||||
// Try to restore backup on failure
|
||||
fmt.Printf("❌ Failed to apply configuration: %v\n", err)
|
||||
fmt.Printf("Failed to apply configuration: %v\n", err)
|
||||
fmt.Println("<22> Attempting to restore backup...")
|
||||
|
||||
if restoreErr := configManager.RestoreBackup(backupPath); restoreErr != nil {
|
||||
return fmt.Errorf("configuration failed AND backup restore failed: %v (original error: %v)", restoreErr, err)
|
||||
}
|
||||
|
||||
fmt.Println("✅ Backup restored successfully")
|
||||
fmt.Println("Backup restored successfully")
|
||||
return fmt.Errorf("configuration application failed, backup restored: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("🎉 Successfully applied fastest mirror!\n")
|
||||
fmt.Printf("🔗 New mirror: %s\n", color.GreenString(bestMirror.URL))
|
||||
fmt.Printf("Successfully applied fastest mirror!\n")
|
||||
fmt.Printf("New mirror: %s\n", color.GreenString(bestMirror.URL))
|
||||
fmt.Println()
|
||||
fmt.Printf("💡 Don't forget to run your package manager's update command:\n")
|
||||
fmt.Printf("Don't forget to run your package manager's update command:\n")
|
||||
|
||||
switch distroInfo.Family {
|
||||
case "debian":
|
||||
|
36
cmd/find.go
36
cmd/find.go
@@ -33,21 +33,21 @@ This command will:
|
||||
|
||||
func runFind(cmd *cobra.Command, args []string) error {
|
||||
// Detect distribution
|
||||
fmt.Println(color.CyanString("🔍 Detecting your Linux distribution..."))
|
||||
fmt.Println(color.CyanString("Detecting your Linux distribution..."))
|
||||
|
||||
distroInfo, err := distro.DetectDistribution()
|
||||
if err != nil {
|
||||
return fmt.Errorf("fuck me, couldn't detect your distro: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("📦 Found: %s\n", color.GreenString(distroInfo.String()))
|
||||
fmt.Printf("Found: %s\n", color.GreenString(distroInfo.String()))
|
||||
|
||||
if !distroInfo.IsSupported() {
|
||||
return fmt.Errorf("sorry, %s isn't supported yet - but hey, you're using something exotic! 🦄", distroInfo.ID)
|
||||
}
|
||||
|
||||
// Get mirrors for this distribution family
|
||||
fmt.Printf("🔧 Loading mirrors for %s family...\n", color.YellowString(distroInfo.Family))
|
||||
fmt.Printf("Loading mirrors for %s family...\n", color.YellowString(distroInfo.Family))
|
||||
|
||||
mirrorList := mirror.NewMirrorList(distroInfo.Family)
|
||||
|
||||
@@ -60,8 +60,7 @@ func runFind(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("failed to load mirrors: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("⚡ Testing %d mirrors (timeout: %ds each)...\n",
|
||||
len(mirrorList.Mirrors), timeout)
|
||||
fmt.Printf("Testing mirrors (timeout: %ds each)...\n", timeout)
|
||||
|
||||
err = mirrorList.TestMirrors(ctx, time.Duration(timeout)*time.Second)
|
||||
|
||||
@@ -70,7 +69,7 @@ func runFind(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
// Display results
|
||||
fmt.Println("\n" + color.GreenString("🎉 Testing complete! Here are your results:"))
|
||||
fmt.Println("\n" + color.GreenString("Testing complete! Here are your results:"))
|
||||
fmt.Println()
|
||||
|
||||
topMirrors := mirrorList.GetTop(topCount)
|
||||
@@ -85,11 +84,11 @@ func runFind(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if verbose {
|
||||
fmt.Printf("📊 Test Summary: %d/%d mirrors responded successfully\n", successCount, len(allMirrors))
|
||||
fmt.Printf("Test Summary: %d/%d mirrors responded successfully\n", successCount, len(allMirrors))
|
||||
fmt.Println()
|
||||
}
|
||||
if len(topMirrors) == 0 {
|
||||
fmt.Println(color.RedString("😱 No working mirrors found. Your internet might be fucked, or all mirrors are down."))
|
||||
fmt.Println(color.RedString("No working mirrors found. Your internet might be fucked, or all mirrors are down."))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -132,32 +131,29 @@ func runFind(cmd *cobra.Command, args []string) error {
|
||||
fmt.Println()
|
||||
best := mirrorList.GetBest()
|
||||
if best != nil {
|
||||
fmt.Printf("🏆 Winner: %s\n", color.GreenString(best.URL))
|
||||
fmt.Printf("⚡ This bad boy clocks in at %.1f MB/s with %dms latency\n",
|
||||
fmt.Printf("Winner: %s\n", color.GreenString(best.URL))
|
||||
fmt.Printf("This bad boy clocks in at %.1f MB/s with %dms latency\n",
|
||||
best.Speed, best.Latency.Milliseconds())
|
||||
}
|
||||
|
||||
// Show failed mirrors in verbose mode
|
||||
// Show failed mirror count in verbose mode (no detailed errors)
|
||||
if verbose {
|
||||
failedMirrors := make([]mirror.Mirror, 0)
|
||||
failedCount := 0
|
||||
for _, m := range allMirrors {
|
||||
if m.Error != nil {
|
||||
failedMirrors = append(failedMirrors, m)
|
||||
failedCount++
|
||||
}
|
||||
}
|
||||
|
||||
if len(failedMirrors) > 0 {
|
||||
if failedCount > 0 {
|
||||
fmt.Println()
|
||||
fmt.Printf("❌ Failed mirrors (%d):\n", len(failedMirrors))
|
||||
for _, m := range failedMirrors {
|
||||
fmt.Printf(" %s - %s\n", color.RedString(m.URL), m.Error.Error())
|
||||
}
|
||||
fmt.Printf("Failed mirrors: %d (errors hidden for cleaner output)\n", failedCount)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Printf("💡 To apply the fastest mirror, run: %s\n",
|
||||
color.YellowString("fastestmirror apply"))
|
||||
fmt.Printf("To apply the fastest mirror, run: %s\n",
|
||||
color.CyanString("fastestmirror apply"))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -80,11 +80,11 @@ func NewMirrorList(family string) *MirrorList {
|
||||
func (ml *MirrorList) LoadMirrors(ctx context.Context, family string) error {
|
||||
fetcher := NewMirrorFetcher()
|
||||
|
||||
fmt.Printf("🌐 Fetching complete mirror list for %s...\n", family)
|
||||
fmt.Printf("Fetching complete mirror list for %s...\n", family)
|
||||
|
||||
mirrors, err := fetcher.FetchMirrors(ctx, family)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠️ Failed to fetch mirrors online, using fallback list: %v\n", err)
|
||||
fmt.Printf("Failed to fetch mirrors online, using fallback list: %v\n", err)
|
||||
mirrors = fetcher.getDefaultMirrors(family)
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ func (ml *MirrorList) LoadMirrors(ctx context.Context, family string) error {
|
||||
})
|
||||
}
|
||||
|
||||
fmt.Printf("📡 Loaded %d mirrors for testing\n", len(ml.Mirrors))
|
||||
fmt.Printf("Loaded %d mirrors for testing\n", len(ml.Mirrors))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ func (ml *MirrorList) TestMirrors(ctx context.Context, timeout time.Duration) er
|
||||
results := make(chan TestResult, len(ml.Mirrors))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
fmt.Printf("🔄 Testing %d mirrors concurrently...\n", len(ml.Mirrors))
|
||||
fmt.Printf("Testing %d mirrors concurrently...\n", len(ml.Mirrors))
|
||||
|
||||
// Test each mirror concurrently
|
||||
for i := range ml.Mirrors {
|
||||
@@ -154,7 +154,7 @@ func (ml *MirrorList) TestMirrors(ctx context.Context, timeout time.Duration) er
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("✅ Testing complete: %d successful, %d failed\n", successCount, failureCount)
|
||||
fmt.Printf("Testing complete: %d successful, %d failed\n", successCount, failureCount)
|
||||
|
||||
// Sort by score (higher is better), but put failed mirrors at the end
|
||||
sort.Slice(ml.Mirrors, func(i, j int) bool {
|
||||
|
Reference in New Issue
Block a user