| 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 |
| } |