cloudbuild/pkg/distros/debian_utils.go

209 lines
6.4 KiB
Go

package distros
import (
"fmt"
"net/url"
"strings"
"libguestfs.org/guestfs"
)
func debianCommandToUpdatePackageCache() []string {
return []string{"sudo", "apt", "update"}
}
func (mgr *TemplateManager) replaceDebianMirrorUrl(handle *guestfs.Guestfs, uri string) (string, error) {
parsedUrl, err := url.Parse(uri)
if err != nil {
return "", fmt.Errorf("Could not parse URL '%s': %w", uri, err)
}
// See https://manpages.debian.org/stable/apt/sources.list.5.en.html#URI_SPECIFICATION
// There are many more URI types, but these are the ones which I've seen so far in the
// official Debian cloud images
if parsedUrl.Scheme == "http" || parsedUrl.Scheme == "https" {
parsedUrl.Host = mgr.cfg.MirrorHost
return parsedUrl.String(), nil
} else if parsedUrl.Scheme == "mirror+file" {
// The file is a mirrorlist
filePath := uri[len("mirror+file://"):]
content, err := handle.Cat(filePath)
if err != nil {
return "", fmt.Errorf("Could not read %s: %w", filePath, err)
}
oldLines := strings.Split(content, "\n")
newLines := []string{}
for _, oldLine := range oldLines {
if oldLine == "" || strings.HasPrefix(oldLine, "#") {
newLines = append(newLines, oldLine)
continue
}
parsedUrl, err := url.Parse(oldLine)
if err != nil {
return "", fmt.Errorf("Could not parse URL in %s: '%s'", filePath, oldLine)
}
if parsedUrl.Scheme != "http" && parsedUrl.Scheme != "https" {
return "", fmt.Errorf("Unexpected URL scheme in %s: '%s'", filePath, oldLine)
}
parsedUrl.Host = mgr.cfg.MirrorHost
newLine := parsedUrl.String()
mgr.logger.Debug().
Str("file", filePath).
Str("oldURL", oldLine).
Str("newURL", newLine).
Msg("Replacing URL")
newLines = append(newLines, newLine)
}
newContent := strings.Join(newLines, "\n")
err = handle.Write(filePath, []byte(newContent))
if err != nil {
return "", fmt.Errorf("Error writing to %s: %w", filePath, err)
}
// Original URL (mirror+file://) does not change
return uri, nil
} else {
return "", fmt.Errorf("Unexpected scheme in URL: %s", uri)
}
}
// See https://manpages.debian.org/stable/apt/sources.list.5.en.html#ONE-LINE-STYLE_FORMAT
func (mgr *TemplateManager) replaceDebianMirrorUrls_OneLineStyle(handle *guestfs.Guestfs, filePath string) error {
log := mgr.logger
// Some Augeas nodes under /files/etc/apt/sources.list are comments,
// so we use /*/uri to make sure that we only get the actual entries
sourcesListEntries, err := handle.Aug_match("/files" + filePath + "/*/uri")
if err != nil {
return err
}
for _, uriPath := range sourcesListEntries {
var (
oldURL string
newURL string
typeValue string
distValue string
)
if oldURL, err = handle.Aug_get(uriPath); err != nil {
return err
}
newURL, err = mgr.replaceDebianMirrorUrl(handle, oldURL)
if err != nil {
return err
}
// strip off the "/uri" from the node path
entryPath := uriPath[:len(uriPath)-4]
typePath := entryPath + "/type"
if typeValue, err = handle.Aug_get(typePath); err != nil {
return err
}
distPath := entryPath + "/distribution"
if distValue, err = handle.Aug_get(distPath); err != nil {
return err
}
if typeValue == "deb-src" {
log.Debug().
Str("URL", oldURL).
Str("distribution", distValue).
Msg("Removing deb-src entry")
if _, err = handle.Aug_rm(entryPath); err != nil {
return err
}
continue
}
if oldURL == newURL {
continue
}
log.Debug().
Str("distribution", distValue).
Str("oldURL", oldURL).
Str("newURL", newURL).
Str("file", filePath).
Msg("Replacing URL")
if err = handle.Aug_set(uriPath, newURL); err != nil {
return err
}
}
return nil
}
// See https://manpages.debian.org/stable/apt/sources.list.5.en.html#DEB822-STYLE_FORMAT
func (mgr *TemplateManager) replaceDebianMirrorUrls_Deb822Style(handle *guestfs.Guestfs, filePath string) error {
// Augeas doesn't support this style unfortunately, so we're going to
// have to parse the file manually
content, err := handle.Cat(filePath)
if err != nil {
return fmt.Errorf("Could not read %s: %w", filePath, err)
}
oldLines := strings.Split(content, "\n")
newLines := []string{}
for _, oldLine := range oldLines {
if strings.HasPrefix(oldLine, "Types:") {
oldTypes := strings.Split(
strings.TrimLeft(oldLine[len("Types:"):], " "),
" ",
)
if len(oldTypes) == 0 || len(oldTypes) > 2 {
return fmt.Errorf(
"Could not determine Debian archive types from this line in %s: '%s'",
filePath, oldLine,
)
}
if oldTypes[0] == "deb-src" || (len(oldTypes) == 2 && oldTypes[1] == "deb-src") {
mgr.logger.Debug().Str("file", filePath).Msg("Removing deb-src type")
}
newLines = append(newLines, "Types: deb")
} else if strings.HasPrefix(oldLine, "URIs:") {
oldURL := strings.TrimLeft(oldLine[len("URIs:"):], " ")
newURL, err := mgr.replaceDebianMirrorUrl(handle, oldURL)
if err != nil {
return err
}
if oldURL != newURL {
mgr.logger.Debug().
Str("file", filePath).
Str("oldURL", oldURL).
Str("newURL", newURL).
Msg("Replacing URL")
}
newLines = append(newLines, "URIs: "+newURL)
} else {
newLines = append(newLines, oldLine)
}
}
newContent := strings.Join(newLines, "\n")
err = handle.Write(filePath, []byte(newContent))
if err != nil {
return fmt.Errorf("Error writing to %s: %w", filePath, err)
}
return nil
}
func (mgr *TemplateManager) replaceDebianMirrorUrls(handle *guestfs.Guestfs) error {
filePaths := []string{"/etc/apt/sources.list"}
extraSourceDirPath := "/etc/apt/sources.list.d"
extraSourceDirExists, err := handle.Is_dir(extraSourceDirPath, nil)
if err != nil {
return fmt.Errorf("Could not determine if %s is a directory: %w", extraSourceDirPath, err)
}
if extraSourceDirExists {
extraSourceFiles, err := handle.Ls(extraSourceDirPath)
if err != nil {
return fmt.Errorf("Could not list files in %s: %w", extraSourceDirPath, err)
}
for _, filename := range extraSourceFiles {
filePaths = append(filePaths, extraSourceDirPath+"/"+filename)
}
}
for _, filePath := range filePaths {
if strings.HasSuffix(filePath, ".list") {
err = mgr.replaceDebianMirrorUrls_OneLineStyle(handle, filePath)
} else if strings.HasSuffix(filePath, ".sources") {
err = mgr.replaceDebianMirrorUrls_Deb822Style(handle, filePath)
} else {
err = fmt.Errorf("Could not determine type of Debian source file %s", filePath)
}
if err != nil {
return err
}
}
return nil
}