Skip to content

Commit

Permalink
feat(client): autoclean old downloaded releases
Browse files Browse the repository at this point in the history
- add autoclean option to the update command (default true)
- track release recent use time with metafiles
- clean releases after repo update procedure
  - keep actual releases
  - keep recently used releases

Signed-off-by: Alexey Igrychev <alexey.igrychev@flant.com>
  • Loading branch information
alexey-igrychev committed Mar 3, 2022
1 parent 605dc22 commit a2ea508
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 22 deletions.
6 changes: 4 additions & 2 deletions client/cmd/trdl/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

func updateCmd() *cobra.Command {
var noSelfUpdate bool
var autoclean bool
var inBackground bool
var backgroundStdoutFile string
var backgroundStderrFile string
Expand Down Expand Up @@ -70,12 +71,12 @@ func updateCmd() *cobra.Command {
}

if !noSelfUpdate {
if err := c.DoSelfUpdate(); err != nil {
if err := c.DoSelfUpdate(autoclean); err != nil {
_, _ = fmt.Fprintf(os.Stderr, "WARNING: Self-update failed: %s\n", err)
}
}

if err := c.UpdateRepoChannel(repoName, group, optionalChannel); err != nil {
if err := c.UpdateRepoChannel(repoName, group, optionalChannel, autoclean); err != nil {
return err
}

Expand All @@ -84,6 +85,7 @@ func updateCmd() *cobra.Command {
}

SetupNoSelfUpdate(cmd, &noSelfUpdate)
cmd.Flags().BoolVar(&autoclean, "autoclean", true, "Erase old downloaded releases")
cmd.Flags().BoolVar(&inBackground, "in-background", false, "Perform update in background")
cmd.Flags().StringVarP(&backgroundStdoutFile, "background-stdout-file", "", "", "Redirect the stdout of the background update to a file")
cmd.Flags().StringVarP(&backgroundStderrFile, "background-stderr-file", "", "", "Redirect the stderr of the background update to a file")
Expand Down
38 changes: 32 additions & 6 deletions client/pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (c Client) SetRepoDefaultChannel(repoName, channel string) error {
})
}

func (c Client) DoSelfUpdate() error {
func (c Client) DoSelfUpdate(autocleanReleases bool) error {
acquired, lock, err := c.locker.Acquire(selfUpdateLockFilename, lockgate.AcquireOptions{Shared: false, NonBlocking: true})
if err != nil {
return fmt.Errorf("unable to acquire lock: %s", err)
Expand All @@ -179,7 +179,7 @@ func (c Client) DoSelfUpdate() error {
}
}

if err := c.doSelfUpdate(); err != nil {
if err := c.doSelfUpdate(autocleanReleases); err != nil {
return err
}

Expand All @@ -194,7 +194,7 @@ func (c Client) DoSelfUpdate() error {
return nil
}

func (c Client) doSelfUpdate() error {
func (c Client) doSelfUpdate(autocleanReleases bool) error {
channel, err := c.processRepoOptionalChannel(trdl.SelfUpdateDefaultRepo, "")
if err != nil {
if _, ok := err.(*RepositoryNotInitializedErr); !ok {
Expand Down Expand Up @@ -249,10 +249,16 @@ func (c Client) doSelfUpdate() error {
return err
}

if autocleanReleases {
if err := repoClient.CleanReleases(); err != nil {
return fmt.Errorf("unable to clean old releases: %s", err)
}
}

return nil
}

func (c Client) UpdateRepoChannel(repoName, group, optionalChannel string) error {
func (c Client) UpdateRepoChannel(repoName, group, optionalChannel string, autocleanReleases bool) error {
channel, err := c.processRepoOptionalChannel(repoName, optionalChannel)
if err != nil {
return err
Expand All @@ -263,7 +269,17 @@ func (c Client) UpdateRepoChannel(repoName, group, optionalChannel string) error
return err
}

return repoClient.UpdateChannel(group, channel)
if err := repoClient.UpdateChannel(group, channel); err != nil {
return err
}

if autocleanReleases {
if err := repoClient.CleanReleases(); err != nil {
return fmt.Errorf("unable to clean old releases: %s", err)
}
}

return nil
}

func (c Client) UseRepoChannelReleaseBinDir(repoName, group, optionalChannel, shell string, opts repo.UseSourceOptions) (string, error) {
Expand Down Expand Up @@ -411,7 +427,13 @@ func (c Client) repoClient(repoName string) (RepoInterface, error) {
return nil, err
}

return repo.NewClient(repoName, repoDir, repoUrl, c.repoLocksDir(repoName), c.repoTmpDir(repoName), c.repoLogsDir(repoName))
return repo.NewClient(
repoName, repoDir, repoUrl,
c.repoLocksDir(repoName),
c.repoTmpDir(repoName),
c.repoLogsDir(repoName),
c.repoMetafileDir(repoName),
)
}

func (c *Client) repoDir(repoName string) string {
Expand Down Expand Up @@ -466,6 +488,10 @@ func (c *Client) repoLocksDir(repoName string) string {
return filepath.Join(c.locksDir(), "repositories", repoName)
}

func (c *Client) repoMetafileDir(repoName string) string {
return filepath.Join(c.metafileDir(), "repositories", repoName)
}

func (c *Client) repoTmpDir(repoName string) string {
return filepath.Join(c.tmpDir(), "repositories", repoName)
}
Expand Down
5 changes: 3 additions & 2 deletions client/pkg/client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ type Interface interface {
AddRepo(repoName, repoUrl string, rootVersion int64, rootSha512 string) error
RemoveRepo(repoName string) error
SetRepoDefaultChannel(repoName, channel string) error
DoSelfUpdate() error
UpdateRepoChannel(repoName, group, optionalChannel string) error
DoSelfUpdate(autocleanReleases bool) error
UpdateRepoChannel(repoName, group, optionalChannel string, autocleanReleases bool) error
UseRepoChannelReleaseBinDir(repoName, group, optionalChannel, shell string, opts repo.UseSourceOptions) (string, error)
ExecRepoChannelReleaseBin(repoName, group, optionalChannel string, optionalBinName string, args []string) error
GetRepoChannelReleaseDir(repoName, group, optionalChannel string) (string, error)
Expand All @@ -25,6 +25,7 @@ type RepoInterface interface {
GetChannelReleaseDir(group, channel string) (string, error)
GetChannelReleaseBinDir(group, channel string) (string, error)
GetChannelReleaseBinPath(group, channel, optionalBinName string) (string, error)
CleanReleases() error
}

type configurationInterface interface {
Expand Down
87 changes: 87 additions & 0 deletions client/pkg/repo/clean_releases.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package repo

import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/werf/trdl/client/pkg/util"
)

var releaseMetafileExpirationPeriod = time.Hour * 24

func (c Client) CleanReleases() error {
actualLocalReleases, err := c.getActualLocalReleases()
if err != nil {
return fmt.Errorf("unable to get actual local releases: %s", err)
}

allReleasesGlob := filepath.Join(c.dir, releasesDir, "*")
releaseDirList, err := filepath.Glob(allReleasesGlob)
if err != nil {
return fmt.Errorf("unable to glob files: %s", err)
}

for _, releaseDir := range releaseDirList {
_, releaseName := filepath.Split(releaseDir)

// skip actual channel release
if actualLocalReleases[releaseName] {
continue
}

// skip recently used release
{
metafile := c.releaseMetafile(releaseName)
isRecentlyUsed, err := metafile.HasBeenModifiedWithinPeriod(c.locker, releaseMetafileExpirationPeriod)
if err != nil {
return err
}

if isRecentlyUsed {
continue
}

if err := metafile.Delete(c.locker); err != nil {
return fmt.Errorf("unable to remove release %q metafile: %s", releaseName, err)
}
}

if err := os.RemoveAll(releaseDir); err != nil {
return fmt.Errorf("unable to remove %q: %s", releaseDir, err)
}
}

return nil
}

func (c Client) getActualLocalReleases() (map[string]bool, error) {
actualLocalReleases := map[string]bool{}

allChannelsGlob := filepath.Join(c.dir, channelsDir, "*", "*")
filePathList, err := filepath.Glob(allChannelsGlob)
if err != nil {
return nil, fmt.Errorf("unable to glob files: %s", err)
}

for _, filePath := range filePathList {
exist, err := util.IsRegularFileExist(filePath)
if err != nil {
return nil, fmt.Errorf("unable to check existence of file %q: %s", filePath, err)
}

if !exist {
continue
}

release, err := readChannelRelease(filePath)
if err != nil {
return nil, fmt.Errorf("unable to get channel release: %s", err)
}

actualLocalReleases[release] = true
}

return actualLocalReleases, nil
}
40 changes: 28 additions & 12 deletions client/pkg/repo/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,22 @@ const (
)

type Client struct {
repoName string
dir string
tmpDir string
logsDir string
tufClient TufInterface
locker lockgate.Locker
repoName string
dir string
tmpDir string
logsDir string
metafileDir string
tufClient TufInterface
locker lockgate.Locker
}

func NewClient(repoName, dir, repoUrl, locksPath, tmpDir, logsDir string) (Client, error) {
func NewClient(repoName, dir, repoUrl, locksPath, tmpDir, logsDir, metafileDir string) (Client, error) {
c := Client{
repoName: repoName,
dir: dir,
tmpDir: tmpDir,
logsDir: logsDir,
repoName: repoName,
dir: dir,
tmpDir: tmpDir,
logsDir: logsDir,
metafileDir: metafileDir,
}

if err := c.init(repoUrl, locksPath); err != nil {
Expand Down Expand Up @@ -206,7 +208,16 @@ func (c Client) GetChannelRelease(group, channel string) (string, error) {
return "", NewChannelNotFoundLocallyErr(c.repoName, group, channel)
}

return readChannelRelease(channelFilePath)
release, err := readChannelRelease(channelFilePath)
if err != nil {
return "", err
}

if err := c.releaseMetafile(release).Reset(c.locker); err != nil {
return "", fmt.Errorf("unable to reset release metafile: %s", err)
}

return release, nil
}

func readChannelRelease(path string) (string, error) {
Expand Down Expand Up @@ -234,3 +245,8 @@ func (c Client) updateChannelLockName(group, channel string) string {
func (c Client) updateReleaseLockName(release string) string {
return fmt.Sprintf("update-release-%s", release)
}

func (c Client) releaseMetafile(release string) util.Metafile {
filePath := filepath.Join(c.metafileDir, "releases", release)
return util.NewMetafile(filePath)
}
2 changes: 2 additions & 0 deletions docs/_includes/reference/cli/trdl_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ trdl update REPO GROUP [CHANNEL] [options]
## Options

```shell
--autoclean=true
Erase old downloaded releases
--background-stderr-file=''
Redirect the stderr of the background update to a file
--background-stdout-file=''
Expand Down

0 comments on commit a2ea508

Please sign in to comment.