latest
This commit is contained in:
		
							parent
							
								
									0dd9505fb3
								
							
						
					
					
						commit
						b168c1f7d2
					
				
							
								
								
									
										14
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								main.go
									
									
									
									
									
								
							| @ -33,9 +33,11 @@ func CLIEntry() { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Create sources.list.d directory if it doesn't exist
 | ||||
| 	if err := createSourcesListD(); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	oldMirrorURL, err := findMirrorURLInFile(sourcesFilePath) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		// redundant
 | ||||
| 		log.Fatalf("Failed to find mirror URL in file %s: %v", sourcesFilePath, err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Fetch and find the fastest mirror
 | ||||
| @ -48,8 +50,12 @@ func CLIEntry() { | ||||
| 	// Display latency statistics
 | ||||
| 	displayLatencyStatistics(latencies, fastestMirrorURL, fastestTime) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Failed to find mirror URL in file %s: %v", sourcesFilePath, err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Update sources file with the fastest mirror
 | ||||
| 	if err := updateSourcesFile(sourcesFilePath, fastestMirrorURL, suites); err != nil { | ||||
| 	if err := updateSourcesFile(sourcesFilePath, oldMirrorURL, fastestMirrorURL); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	log.Println("Fastmirror CLI finished successfully") | ||||
|  | ||||
| @ -8,7 +8,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/schollz/progressbar/v3" | ||||
| 	progressbar "github.com/schollz/progressbar/v3" | ||||
| ) | ||||
| 
 | ||||
| func findFastestMirror(suites []string) (string, time.Duration, []time.Duration, error) { | ||||
| @ -33,7 +33,6 @@ func findFastestMirror(suites []string) (string, time.Duration, []time.Duration, | ||||
| 	downCount := 0 | ||||
| 	noIndexCount := 0 | ||||
| 
 | ||||
| 	codename, err := getUbuntuCodename() | ||||
| 	if err != nil { | ||||
| 		return "", 0, nil, err | ||||
| 	} | ||||
| @ -52,7 +51,7 @@ func findFastestMirror(suites []string) (string, time.Duration, []time.Duration, | ||||
| 		if strings.HasPrefix(mirror, "https://") { | ||||
| 			mirror = strings.TrimSuffix(mirror, "/") | ||||
| 			startTime := time.Now() | ||||
| 			isValid := isValidMirror(httpClient, mirror, codename, suites) | ||||
| 			isValid := isValidMirror(httpClient, mirror, suites) | ||||
| 			elapsedTime := time.Since(startTime) | ||||
| 
 | ||||
| 			if isValid { | ||||
| @ -80,7 +79,7 @@ func findFastestMirror(suites []string) (string, time.Duration, []time.Duration, | ||||
| 	return fastestMirrorURL, fastestTime, latencies, nil | ||||
| } | ||||
| 
 | ||||
| func isValidMirror(httpClient http.Client, mirrorURL, codename string, suites []string) bool { | ||||
| func isValidMirror(httpClient http.Client, mirrorURL string, suites []string) bool { | ||||
| 	for _, suite := range suites { | ||||
| 		uri := fmt.Sprintf("%s/dists/%s/Release", mirrorURL, suite) | ||||
| 		resp, err := httpClient.Get(uri) | ||||
|  | ||||
							
								
								
									
										100
									
								
								sources.go
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								sources.go
									
									
									
									
									
								
							| @ -4,19 +4,13 @@ import ( | ||||
| 	"bufio" | ||||
| 	_ "embed" | ||||
| 	"fmt" | ||||
| 	"html/template" | ||||
| 	"log" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| //go:embed sources_list_legacy.tmpl
 | ||||
| var legacyTemplate string | ||||
| 
 | ||||
| //go:embed sources_list_modern.tmpl
 | ||||
| var modernTemplate string | ||||
| 
 | ||||
| func findSourcesFilePath() (string, error) { | ||||
| 	const sourcesListPath = "/etc/apt/sources.list" | ||||
| 	const sourcesListDPath = "/etc/apt/sources.list.d/" | ||||
| @ -24,6 +18,7 @@ func findSourcesFilePath() (string, error) { | ||||
| 		log.Printf("Found Ubuntu sources file: %s", sourcesListPath) | ||||
| 		return sourcesListPath, nil | ||||
| 	} | ||||
| 
 | ||||
| 	files, err := os.ReadDir(sourcesListDPath) | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("failed to read directory %s: %v", sourcesListDPath, err) | ||||
| @ -43,14 +38,28 @@ func findSourcesFilePath() (string, error) { | ||||
| 	return "", fmt.Errorf("no Ubuntu sources file found") | ||||
| } | ||||
| 
 | ||||
| func isUbuntuSourcesFile(filePath string) bool { | ||||
| 	content, err := os.ReadFile(filePath) | ||||
| var ubuntuMirrorURLRegex = regexp.MustCompile(`http://((?P<countrycode>[a-z]{2})\.)?(archive|ports)\.ubuntu\.com/(?P<path>.*)`) | ||||
| 
 | ||||
| func findMirrorURLInFile(filePath string) (string, error) { | ||||
| 	fileContent, err := os.ReadFile(filePath) | ||||
| 	if err != nil { | ||||
| 		log.Printf("Failed to read file %s: %v", filePath, err) | ||||
| 		return false | ||||
| 		return "", fmt.Errorf("failed to read file %s: %v", filePath, err) | ||||
| 	} | ||||
| 	match := ubuntuMirrorURLRegex.FindString(string(fileContent)) | ||||
| 	if match != "" { | ||||
| 		return match, nil | ||||
| 	} | ||||
| 	return "", fmt.Errorf("no URL found in file %s", filePath) | ||||
| } | ||||
| 
 | ||||
| 	return strings.Contains(strings.ToLower(string(content)), "ubuntu.com") | ||||
| func isUbuntuSourcesFile(filePath string) bool { | ||||
| 	match, err := findMirrorURLInFile(filePath) | ||||
| 	if err != nil { | ||||
| 		log.Printf("Failed to find OEM mirror URL in file %s: %v", filePath, err) | ||||
| 		return false | ||||
| 	} | ||||
| 	log.Printf("Found OEM mirror URL in file %s: %s", filePath, match) | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| func createBackup(filePath string) error { | ||||
| @ -65,17 +74,6 @@ func createBackup(filePath string) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func createSourcesListD() error { | ||||
| 	const sourcesListDPath = "/etc/apt/sources.list.d/" | ||||
| 	if _, err := os.Stat(sourcesListDPath); os.IsNotExist(err) { | ||||
| 		if err := os.Mkdir(sourcesListDPath, 0755); err != nil { | ||||
| 			return fmt.Errorf("failed to create directory %s: %v", sourcesListDPath, err) | ||||
| 		} | ||||
| 		log.Printf("Created directory: %s", sourcesListDPath) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func extractSuites(filePath string) ([]string, error) { | ||||
| 	content, err := os.ReadFile(filePath) | ||||
| 	if err != nil { | ||||
| @ -121,56 +119,24 @@ func extractSuites(filePath string) ([]string, error) { | ||||
| 	return suites, nil | ||||
| } | ||||
| 
 | ||||
| func updateSourcesFile(filePath, mirrorURL string, suites []string) error { | ||||
| 	codename, err := getUbuntuCodename() | ||||
| func updateSourcesFile(filePath, oldMirrorURL, newMirrorURL string) error { | ||||
| 	file, err := os.Open(filePath) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		return fmt.Errorf("failed to open sources file %s: %v", filePath, err) | ||||
| 	} | ||||
| 	majorVersion, minorVersion, err := getUbuntuVersion() | ||||
| 	file.Close() | ||||
| 	contentBytes, err := os.ReadFile(filePath) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		return fmt.Errorf("failed to read sources file %s: %v", filePath, err) | ||||
| 	} | ||||
| 
 | ||||
| 	suitesString := strings.Join(suites, " ") | ||||
| 	log.Printf("update: replacing %s with %s in %s", oldMirrorURL, newMirrorURL, filePath) | ||||
| 	// replace old mirror URL with new mirror URL
 | ||||
| 	content := string(contentBytes) | ||||
| 	content = strings.ReplaceAll(content, oldMirrorURL, newMirrorURL) | ||||
| 
 | ||||
| 	var content string | ||||
| 	data := struct { | ||||
| 		MirrorURL string | ||||
| 		Codename  string | ||||
| 		Suites    string | ||||
| 	}{ | ||||
| 		MirrorURL: mirrorURL, | ||||
| 		Codename:  codename, | ||||
| 		Suites:    suitesString, | ||||
| 	} | ||||
| 
 | ||||
| 	if majorVersion > 24 || (majorVersion == 24 && minorVersion >= 4) { | ||||
| 		tmpl, err := template.New("modern").Parse(modernTemplate) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("failed to parse modern template: %v", err) | ||||
| 		} | ||||
| 		var buf strings.Builder | ||||
| 		err = tmpl.Execute(&buf, data) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("failed to execute modern template: %v", err) | ||||
| 		} | ||||
| 		content = buf.String() | ||||
| 	} else { | ||||
| 		tmpl, err := template.New("legacy").Parse(legacyTemplate) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("failed to parse legacy template: %v", err) | ||||
| 		} | ||||
| 		var buf strings.Builder | ||||
| 		err = tmpl.Execute(&buf, data) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("failed to execute legacy template: %v", err) | ||||
| 		} | ||||
| 		content = buf.String() | ||||
| 	} | ||||
| 
 | ||||
| 	err = os.WriteFile(filePath, []byte(content), 0644) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to update sources file %s: %v", filePath, err) | ||||
| 	if err := os.WriteFile(filePath, []byte(content), 0644); err != nil { | ||||
| 		return fmt.Errorf("failed to write sources file %s: %v", filePath, err) | ||||
| 	} | ||||
| 	log.Printf("Updated sources file: %s", filePath) | ||||
| 	return nil | ||||
|  | ||||
| @ -1,5 +0,0 @@ | ||||
| deb {{.MirrorURL}} {{.Codename}} {{.Suites}} | ||||
| deb {{.MirrorURL}} {{.Codename}}-updates {{.Suites}} | ||||
| deb {{.MirrorURL}} {{.Codename}}-backports {{.Suites}} | ||||
| deb {{.MirrorURL}} {{.Codename}}-security {{.Suites}} | ||||
| 
 | ||||
| @ -1,14 +0,0 @@ | ||||
| Types: deb | ||||
| URIs: {{.MirrorURL}} | ||||
| Suites: {{.Codename}} {{.Codename}}-updates {{.Codename}}-backports | ||||
| Components: {{.Suites}} | ||||
| Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg | ||||
| 
 | ||||
| ## Ubuntu security updates. Aside from URIs and Suites, | ||||
| ## this should mirror your choices in the previous section. | ||||
| Types: deb | ||||
| URIs: {{.MirrorURL}} | ||||
| Suites: {{.Codename}}-security | ||||
| Components: {{.Suites}} | ||||
| Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg | ||||
| 
 | ||||
							
								
								
									
										32
									
								
								ubuntu.go
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								ubuntu.go
									
									
									
									
									
								
							| @ -3,41 +3,9 @@ package fastmirror | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os/exec" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| func getUbuntuCodename() (string, error) { | ||||
| 	cmd := exec.Command("lsb_release", "-cs") | ||||
| 	output, err := cmd.Output() | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("failed to run lsb_release: %v", err) | ||||
| 	} | ||||
| 	return strings.TrimSpace(string(output)), nil | ||||
| } | ||||
| 
 | ||||
| func getUbuntuVersion() (int, int, error) { | ||||
| 	cmd := exec.Command("lsb_release", "-rs") | ||||
| 	output, err := cmd.Output() | ||||
| 	if err != nil { | ||||
| 		return 0, 0, fmt.Errorf("failed to run lsb_release: %v", err) | ||||
| 	} | ||||
| 	version := strings.TrimSpace(string(output)) | ||||
| 	parts := strings.Split(version, ".") | ||||
| 	if len(parts) != 2 { | ||||
| 		return 0, 0, fmt.Errorf("unexpected version format: %s", version) | ||||
| 	} | ||||
| 	majorVersion, err := strconv.Atoi(parts[0]) | ||||
| 	if err != nil { | ||||
| 		return 0, 0, fmt.Errorf("failed to parse major version: %v", err) | ||||
| 	} | ||||
| 	minorVersion, err := strconv.Atoi(parts[1]) | ||||
| 	if err != nil { | ||||
| 		return 0, 0, fmt.Errorf("failed to parse minor version: %v", err) | ||||
| 	} | ||||
| 	return majorVersion, minorVersion, nil | ||||
| } | ||||
| 
 | ||||
| func isUbuntu() error { | ||||
| 	cmd := exec.Command("lsb_release", "-is") | ||||
| 	output, err := cmd.Output() | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user