/
update_stemcell.go
122 lines (95 loc) · 3.69 KB
/
update_stemcell.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package commands
import (
"fmt"
"log"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/go-git/go-billy/v5"
"github.com/pivotal-cf/jhanda"
"github.com/pivotal-cf/kiln/internal/commands/flags"
"github.com/pivotal-cf/kiln/internal/component"
)
type UpdateStemcell struct {
Options struct {
flags.Standard
Version string `short:"v" long:"version" required:"true" description:"desired version of stemcell"`
ReleasesDir string `short:"rd" long:"releases-directory" default:"releases" description:"path to a directory to download releases into"`
}
FS billy.Filesystem
MultiReleaseSourceProvider MultiReleaseSourceProvider
Logger *log.Logger
}
func (update UpdateStemcell) Execute(args []string) error {
_, err := flags.LoadWithDefaultFilePaths(&update.Options, args, update.FS.Stat)
if err != nil {
return err
}
kilnfile, kilnfileLock, err := update.Options.Standard.LoadKilnfiles(update.FS, nil)
if err != nil {
return fmt.Errorf("error loading Kilnfiles: %w", err)
}
var releaseVersionConstraint *semver.Constraints
trimmedInputVersion := strings.TrimSpace(update.Options.Version)
latestStemcellVersion, err := semver.NewVersion(trimmedInputVersion)
if err != nil {
return fmt.Errorf("invalid stemcell version (please enter a valid version): %w", err)
}
kilnStemcellVersion := kilnfile.Stemcell.Version
releaseVersionConstraint, err = semver.NewConstraint(kilnStemcellVersion)
if err != nil {
return fmt.Errorf("invalid stemcell constraint in kilnfile: %w", err)
}
if !releaseVersionConstraint.Check(latestStemcellVersion) {
update.Logger.Println("Latest version does not satisfy the stemcell version constraint in kilnfile. Nothing to update.")
return nil
}
currentStemcellVersion, _ := semver.NewVersion(kilnfileLock.Stemcell.Version)
if currentStemcellVersion.Equal(latestStemcellVersion) {
update.Logger.Println("Stemcell is up-to-date. Nothing to update for product")
return nil
}
releaseSource := update.MultiReleaseSourceProvider(kilnfile, false)
for i, rel := range kilnfileLock.Releases {
update.Logger.Printf("Updating release %q with stemcell %s %s...", rel.Name, kilnfileLock.Stemcell.OS, trimmedInputVersion)
spec, err := kilnfile.BOSHReleaseTarballSpecification(rel.Name)
if err != nil {
return err
}
spec.StemcellOS = kilnfileLock.Stemcell.OS
spec.StemcellVersion = trimmedInputVersion
spec.Version = rel.Version
remote, err := releaseSource.GetMatchedRelease(spec)
if err != nil {
return fmt.Errorf("while finding release %q, encountered error: %w", rel.Name, err)
}
if component.IsErrNotFound(err) {
return fmt.Errorf("couldn't find release %q", rel.Name)
}
if remote.RemotePath == rel.RemotePath && remote.RemoteSource == rel.RemoteSource {
update.Logger.Printf("No change for release %q\n", rel.Name)
continue
}
local, err := releaseSource.DownloadRelease(update.Options.ReleasesDir, remote)
if err != nil {
return fmt.Errorf("while downloading release %q, encountered error: %w", rel.Name, err)
}
lock := &kilnfileLock.Releases[i]
lock.SHA1 = local.Lock.SHA1
lock.RemotePath = remote.RemotePath
lock.RemoteSource = remote.RemoteSource
}
kilnfileLock.Stemcell.Version = trimmedInputVersion
err = update.Options.Standard.SaveKilnfileLock(update.FS, kilnfileLock)
if err != nil {
return err
}
update.Logger.Println("Finished updating Kilnfile.lock")
return nil
}
func (update UpdateStemcell) Usage() jhanda.Usage {
return jhanda.Usage{
Description: "Updates stemcell and release information in Kilnfile.lock",
ShortDescription: "updates stemcell and release information in Kilnfile.lock",
Flags: update.Options,
}
}