blob: 2188a5792257d4869d8933d7e44d16a8bda1f438 [file] [log] [blame]
package dkms
import (
"context"
"fmt"
"os"
"path/filepath"
"cos.googlesource.com/cos/tools.git/src/pkg/fs"
"cos.googlesource.com/cos/tools.git/src/pkg/gcs"
"cos.googlesource.com/cos/tools.git/src/pkg/utils"
"github.com/golang/glog"
)
// Add adds a package to the DKMS source tree.
//
// This checks the user source tree (by default, /usr/src/)
// for the package source files. If the sources don't exist there,
// this will check the local ${package-name}-${package-version} path
// and try to copy sources from there to the user source tree, then
// add the copied sources to the DKMS tree.
//
// If the DKMS tree does not already exist, this will create it.
// If the package has already been added, this does nothing.
func Add(pkg *Package, options *Options) error {
if IsAdded(pkg) {
glog.Info("package already added; skipping add step")
return nil
}
glog.Infof("adding package %s-%s", pkg.Name, pkg.Version)
// We have to use the absolute path to the package sources since
// the symlink will be used from the DKMS tree, not the directory
// from which we're making the symlink.
sourceTreeSourceDir, err := filepath.Abs(pkg.SourceTreeDir())
if err != nil {
return err
}
// Try to copy the source files from a local directory to the
// source tree if they're not already there.
if !fs.IsDir(sourceTreeSourceDir) {
localSourceDir := fmt.Sprintf("%s-%s", pkg.Name, pkg.Version)
if !fs.IsDir(localSourceDir) {
return fmt.Errorf("could not find package sources in source tree at %s or in local directory %s", sourceTreeSourceDir, localSourceDir)
}
err := fs.CopyDir(localSourceDir, sourceTreeSourceDir, 0777)
if err != nil {
return fmt.Errorf("could not copy local package sources from %s to source tree at %s: %v", localSourceDir, sourceTreeSourceDir, err)
}
}
dkmsTreeSourceDir := pkg.SourceDir()
err = os.MkdirAll(filepath.Dir(dkmsTreeSourceDir), 0777)
if err != nil {
return err
}
glog.Infof("symlinking package sources from %s to %s", sourceTreeSourceDir, dkmsTreeSourceDir)
if err := os.Symlink(sourceTreeSourceDir, dkmsTreeSourceDir); err != nil {
return err
}
config, err := LoadConfig(pkg)
if err != nil {
return err
}
if config.PostAdd != "" {
if err := utils.RunCommandString(dkmsTreeSourceDir, config.PostAdd); err != nil {
return err
}
}
return nil
}
// CachedAdd adds a package to the DKMS source tree, downloading
// sources from the cache if they are not available locally.
//
// If options.Upload is specified, this will upload the sources to
// the DKMS tree in the cache after they have been added to the
// local DKMS tree.
//
// See Add for more details on how sources are added locally.
func CachedAdd(ctx context.Context, pkg *Package, cache *gcs.GCSBucket, options *Options) error {
// First, try to add the package from only local sources.
if err := Add(pkg, options); err != nil {
// If the local Add failed for any reason, try to download the sources to
// the local user source tree. It should be safe to ignore the Add error
// since we'll call it later and report an error there if it fails again.
glog.Info(err)
glog.Info("package sources not found locally; checking cache")
dkmsTreeSourceDir := pkg.SourceDir()
sourceTreeSourceDir := pkg.SourceTreeDir()
if err := cache.DownloadDir(ctx, dkmsTreeSourceDir, sourceTreeSourceDir); err != nil {
return fmt.Errorf("failed to download package sources: %v", err)
}
if err := Add(pkg, options); err != nil {
return err
}
}
if options.Upload && !IsAddedInCache(ctx, pkg, cache) {
glog.Info("uploading package sources to cache")
dkmsTreeSourceDir := pkg.SourceDir()
if err := cache.UploadDir(ctx, dkmsTreeSourceDir, dkmsTreeSourceDir); err != nil {
return fmt.Errorf("failed to upload package sources: %v", err)
}
}
return nil
}
// IsAdded checks if a package has been added to the DKMS tree and if it
// has a valid dkms.conf file.
// Note that an empty or absent dkms.conf is considered valid, since default
// values can be used for all settings.
func IsAdded(pkg *Package) bool {
configPath := pkg.ConfigPath()
if !fs.IsFile(configPath) {
return fs.IsDir(pkg.SourceDir())
}
// make sure the config parses without error, but ignore the contents
if _, err := LoadConfig(pkg); err != nil {
glog.Warningf("dkms.conf found, but invalid: %v")
return false
}
return true
}
// IsAddedInCache checks if a package has been added to the DKMS tree in the
// cache and if it has a valid dkms.conf file.
// Note that an empty or absent dkms.conf is considered valid, since default
// values can be used for all settings.
func IsAddedInCache(ctx context.Context, pkg *Package, cache *gcs.GCSBucket) bool {
configExists, err := cache.Exists(ctx, pkg.ConfigPath())
if err != nil {
glog.Errorf("error reading dkms.conf file from cache: %v", err)
return false
}
if !configExists {
sourceExists, err := cache.Exists(ctx, pkg.SourceDir())
if err != nil {
glog.Errorf("error reading package source directory from cache: %v", err)
return false
}
return sourceExists
}
// make sure the config parses without error, but ignore the contents
if _, err := LoadConfig(pkg); err != nil {
glog.Warningf("dkms.conf found, but invalid: %v")
return false
}
return true
}