126 lines
3.5 KiB
Go
126 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
type PruneCmd struct {
|
|
MaxAge time.Duration `help:"Delete releases older than."`
|
|
MaxReleases int `help:"Maximum number of releases to keep."`
|
|
DryRun bool `help:"Just log the result without actually pruning."`
|
|
}
|
|
|
|
// Extra help to explain you can't set 2 prune stratages.
|
|
func (a *PruneCmd) Help() string {
|
|
return "You cannot use both max-age and max-releases, only set one."
|
|
}
|
|
|
|
// Verify the options provided to the command.
|
|
func (a *PruneCmd) AfterApply() error {
|
|
// If both stratages are defined, we don't allow that.
|
|
if a.MaxAge > time.Duration(0) && a.MaxReleases > 0 {
|
|
return errors.New("must only provide one prune argument")
|
|
}
|
|
// If no stratages are defined, we don't allow that.
|
|
if a.MaxAge <= time.Duration(0) && a.MaxReleases <= 0 {
|
|
return errors.New("must provide one prune argument")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Adds a release to a repo.
|
|
func (a *PruneCmd) Run() error {
|
|
// Read existing manifest for repo.
|
|
manifestFile := filepath.Join(app.flags.Repo, "manifest.yaml")
|
|
manifest, err := readManifestFile(manifestFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Keep reference of number of pruned releases.
|
|
releasesPruned := 0
|
|
n := len(manifest.Releases)
|
|
|
|
// If max releases defined and is less than number of releases, look for items to prune.
|
|
if a.MaxReleases > 0 && n > a.MaxReleases {
|
|
// Loop starting at max releases.
|
|
for i := a.MaxReleases; i < n; i++ {
|
|
// Get the current release.
|
|
// We want pull from the top of the stack downward to keep newer releases.
|
|
version := manifest.Releases[n-(i+1)].TagName
|
|
log.Println("Removing release:", version)
|
|
|
|
// If this isn't a dry run, remove the version directory.
|
|
if !a.DryRun {
|
|
err = os.RemoveAll(filepath.Join(app.flags.Repo, version))
|
|
if err != nil {
|
|
return fmt.Errorf("untable to remove release files: %s", err)
|
|
}
|
|
}
|
|
|
|
// Count the number pruned.
|
|
releasesPruned++
|
|
}
|
|
|
|
// Remove releases from the slice.
|
|
manifest.Releases = manifest.Releases[n-a.MaxReleases:]
|
|
}
|
|
|
|
// If we are pruning based on duration, do so.
|
|
if a.MaxAge > time.Duration(0) {
|
|
// Loop through the releases, and find old releases.
|
|
for i := 0; i < n; i++ {
|
|
// If n is 1, we removed too many entries and need to stop.
|
|
if n == 1 {
|
|
log.Println("The repo has only 1 release remaining, ending the prune here to keep 1 release.")
|
|
break
|
|
}
|
|
|
|
// Get the current release, and confirm its age.
|
|
release := manifest.Releases[i]
|
|
if app.now.Sub(release.PublishedAt) >= a.MaxAge {
|
|
// This release is too old, so we need to remove it.
|
|
version := release.TagName
|
|
log.Println("Removing release:", version)
|
|
|
|
// If this isn't a dry run, remove the version files.
|
|
if !a.DryRun {
|
|
err = os.RemoveAll(filepath.Join(app.flags.Repo, version))
|
|
if err != nil {
|
|
return fmt.Errorf("untable to remove release files: %s", err)
|
|
}
|
|
}
|
|
|
|
// Remove the release from the slice.
|
|
manifest.Releases = append(manifest.Releases[:i], manifest.Releases[i+1:]...)
|
|
|
|
// Back up one on the index and number of releases as one release was deleted.
|
|
i--
|
|
n--
|
|
|
|
// Count number of releases pruned.
|
|
releasesPruned++
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write the manifest if this isn't a dry run.
|
|
if !a.DryRun {
|
|
err = writeManifestFile(manifestFile, manifest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Provide details on what's been pruned.
|
|
log.Println("Pruned", releasesPruned, "release from the repo.")
|
|
|
|
return nil
|
|
}
|