Skip to content

Commit f44bf6f

Browse files
authored
feat(GROW-2487): v1 component commands (#1428)
1 parent 32ce177 commit f44bf6f

File tree

11 files changed

+251
-58
lines changed

11 files changed

+251
-58
lines changed

api/components.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type LatestComponentVersion struct {
2222
Version string `json:"version"`
2323
Size int64 `json:"size"`
2424
ComponentType string `json:"type"`
25+
Deprecated bool `json:"deprecated"`
2526
}
2627

2728
func (svc *ComponentsService) ListComponents(os string, arch string) (response ListComponentsResponse, err error) {
@@ -41,6 +42,7 @@ type ComponentVersions struct {
4142
Name string `json:"name"`
4243
Description string `json:"description"`
4344
Component_type string `json:"type"`
45+
Deprecated bool `json:"deprecated"`
4446
Versions []string `json:"versions"`
4547
}
4648

cli/cmd/component.go

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ func init() {
122122
componentsCmd.AddCommand(componentsDevModeCmd)
123123

124124
// load components dynamically
125+
cli.PrototypeLoadComponents()
126+
127+
// v1 components
125128
cli.LoadComponents()
126129
}
127130

@@ -158,9 +161,96 @@ func (c *cliState) IsComponentInstalled(name string) bool {
158161
return false
159162
}
160163

164+
// Load v1 components
165+
func (c *cliState) LoadComponents() {
166+
components, err := lwcomponent.LocalComponents()
167+
if err != nil {
168+
c.Log.Debugw("unable to load components", "error", err)
169+
return
170+
}
171+
172+
// @jon-stewart: TODO: load from cached API info
173+
174+
for _, component := range components {
175+
exists := false
176+
177+
for _, cmd := range rootCmd.Commands() {
178+
if cmd.Use == component.Name {
179+
exists = true
180+
break
181+
}
182+
}
183+
184+
// Skip components that were added by the prototype code
185+
if exists {
186+
continue
187+
}
188+
189+
version := component.InstalledVersion()
190+
if version != nil && component.Exec.Executable() {
191+
componentCmd := &cobra.Command{
192+
Use: component.Name,
193+
Short: component.Description,
194+
Annotations: map[string]string{"type": componentTypeAnnotation},
195+
Version: version.String(),
196+
SilenceUsage: true,
197+
DisableFlagParsing: true,
198+
DisableFlagsInUseLine: true,
199+
RunE: func(cmd *cobra.Command, args []string) error {
200+
return v1ComponentCommand(c, cmd, args)
201+
},
202+
}
203+
204+
rootCmd.AddCommand(componentCmd)
205+
}
206+
}
207+
}
208+
209+
// Grpc server used for components to communicate back to the CLI
210+
func startGrpcServer(c *cliState) {
211+
if err := c.Serve(); err != nil {
212+
c.Log.Errorw("couldn't serve gRPC server", "error", err)
213+
}
214+
}
215+
216+
func v1ComponentCommand(c *cliState, cmd *cobra.Command, args []string) error {
217+
// Parse component -v/--version flag
218+
versionVal, _ := cmd.Flags().GetBool("version")
219+
if versionVal {
220+
cmd.Printf("%s version %s\n", cmd.Use, cmd.Version)
221+
return nil
222+
}
223+
224+
go startGrpcServer(c)
225+
226+
c.Log.Debugw("running component", "component", cmd.Use,
227+
"args", c.componentParser.componentArgs,
228+
"cli_flags", c.componentParser.cliArgs)
229+
230+
catalog, err := lwcomponent.NewCatalog(cli.LwApi, lwcomponent.NewStageTarGz)
231+
if err != nil {
232+
return errors.Wrap(err, "unable to load component Catalog")
233+
}
234+
235+
component, err := catalog.GetComponent(cmd.Use)
236+
if err != nil {
237+
return err
238+
}
239+
240+
// @jon-stewart: TODO: v1 dailyComponentUpdateAvailable
241+
242+
envs := []string{
243+
fmt.Sprintf("LW_COMPONENT_NAME=%s", cmd.Use),
244+
}
245+
246+
envs = append(envs, c.envs()...)
247+
248+
return component.Exec.ExecuteInline(c.componentParser.componentArgs, envs...)
249+
}
250+
161251
// LoadComponents reads the local components state and loads all installed components
162252
// of type `CLI_COMMAND` dynamically into the root command of the CLI (`rootCmd`)
163-
func (c *cliState) LoadComponents() {
253+
func (c *cliState) PrototypeLoadComponents() {
164254
c.Log.Debugw("loading local components")
165255
state, err := lwcomponent.LocalState()
166256
if err != nil || state == nil {
@@ -421,14 +511,7 @@ func showComponent(args []string) error {
421511

422512
printComponent(component.PrintSummary())
423513

424-
version := component.InstalledVersion()
425-
426-
availableVersions, err := catalog.ListComponentVersions(component)
427-
if err != nil {
428-
return err
429-
}
430-
431-
printAvailableVersions(version, availableVersions)
514+
printAvailableVersions(component.InstalledVersion(), catalog.ListComponentVersions(component))
432515

433516
return nil
434517
}

lwcomponent/api_info.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ type ApiInfo interface {
1010
LatestVersion() *semver.Version
1111

1212
AllVersions() []*semver.Version
13+
14+
Deprecated() bool
1315
}
1416

1517
type apiInfo struct {
@@ -19,6 +21,7 @@ type apiInfo struct {
1921
allVersions []*semver.Version
2022
desc string
2123
sizeKB int64
24+
deprecated bool
2225
}
2326

2427
func NewAPIInfo(
@@ -28,6 +31,7 @@ func NewAPIInfo(
2831
allVersions []*semver.Version,
2932
desc string,
3033
size int64,
34+
deprecated bool,
3135
) ApiInfo {
3236
return &apiInfo{
3337
id: id,
@@ -36,17 +40,25 @@ func NewAPIInfo(
3640
allVersions: allVersions,
3741
desc: desc,
3842
sizeKB: size,
43+
deprecated: deprecated,
3944
}
4045
}
4146

4247
func (a *apiInfo) Id() int32 {
4348
return a.id
4449
}
4550

51+
// AllVersions implements ApiInfo.
52+
func (a *apiInfo) AllVersions() []*semver.Version {
53+
return a.allVersions
54+
}
55+
56+
// LatestVersion implements ApiInfo.
4657
func (a *apiInfo) LatestVersion() *semver.Version {
4758
return &a.version
4859
}
4960

50-
func (a *apiInfo) AllVersions() []*semver.Version {
51-
return a.allVersions
61+
// Deprecated implements ApiInfo.
62+
func (a *apiInfo) Deprecated() bool {
63+
return a.deprecated
5264
}

lwcomponent/api_info_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestApiInfoId(t *testing.T) {
1717

1818
var id int32 = 23
1919

20-
info := lwcomponent.NewAPIInfo(id, "test", version, allVersions, "", 0)
20+
info := lwcomponent.NewAPIInfo(id, "test", version, allVersions, "", 0, false)
2121

2222
result := info.Id()
2323
assert.Equal(t, id, result)
@@ -32,7 +32,7 @@ func TestApiInfoLatestVersion(t *testing.T) {
3232
panic(err)
3333
}
3434

35-
info := lwcomponent.NewAPIInfo(1, "test", version, allVersions, "", 0)
35+
info := lwcomponent.NewAPIInfo(1, "test", version, allVersions, "", 0, false)
3636

3737
result := info.LatestVersion()
3838
assert.Equal(t, expectedVer, result.String())

lwcomponent/catalog.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,14 @@ func (c *Catalog) GetComponent(name string) (*CDKComponent, error) {
7272
return &component, nil
7373
}
7474

75-
func (c *Catalog) ListComponentVersions(component *CDKComponent) (versions []*semver.Version, err error) {
75+
func (c *Catalog) ListComponentVersions(component *CDKComponent) (versions []*semver.Version) {
7676
if component.apiInfo == nil {
7777
return
7878
}
7979

80-
return listComponentVersions(c.client, component.apiInfo.Id())
80+
versions = component.apiInfo.AllVersions()
81+
82+
return
8183
}
8284

8385
func (c *Catalog) PrintComponents() [][]string {
@@ -253,7 +255,7 @@ func NewCatalog(client *api.Client, stageConstructor StageConstructor) (*Catalog
253255
return nil, errors.Wrap(err, fmt.Sprintf("unable to fetch component '%s' versions", c.Name))
254256
}
255257

256-
api := NewAPIInfo(c.Id, c.Name, ver, allVersions, c.Description, c.Size)
258+
api := NewAPIInfo(c.Id, c.Name, ver, allVersions, c.Description, c.Size, c.Deprecated)
257259

258260
host, found := localComponents[c.Name]
259261
if found {
@@ -273,6 +275,20 @@ func NewCatalog(client *api.Client, stageConstructor StageConstructor) (*Catalog
273275
return &Catalog{client, cdkComponents, stageConstructor}, nil
274276
}
275277

278+
func LocalComponents() (components []CDKComponent, err error) {
279+
280+
localHostInfo, err := loadLocalComponents()
281+
if err != nil {
282+
return
283+
}
284+
285+
for _, l := range localHostInfo {
286+
components = append(components, NewCDKComponent(l.Name(), BinaryType, nil, l))
287+
}
288+
289+
return
290+
}
291+
276292
func loadLocalComponents() (local map[string]HostInfo, err error) {
277293
cacheDir, err := CatalogCacheDir()
278294
if err != nil {
@@ -303,9 +319,14 @@ func listComponentVersions(client *api.Client, componentId int32) (versions []*s
303319
return nil, err
304320
}
305321

306-
rawVersions := response.Data[0].Versions
322+
var rawVersions []string
323+
324+
if len(response.Data) > 0 {
325+
rawVersions = response.Data[0].Versions
326+
}
307327

308328
versions = make([]*semver.Version, len(rawVersions))
329+
309330
for idx, v := range rawVersions {
310331
ver, err := semver.NewVersion(v)
311332
if err != nil {
@@ -318,10 +339,6 @@ func listComponentVersions(client *api.Client, componentId int32) (versions []*s
318339
return versions, nil
319340
}
320341

321-
// func isDevelopmentComponent(path string, name string) bool {
322-
// return file.FileExists(filepath.Join(path, name, DevelopmentFile))
323-
// }
324-
325342
// Returns the directory that the component executable and configuration is stored in.
326343
func componentDirectory(componentName string) (string, error) {
327344
dir, err := CatalogCacheDir()

lwcomponent/catalog_test.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -348,9 +348,9 @@ func TestCatalogGetComponent(t *testing.T) {
348348
assert.Equal(t, version, ver.String())
349349
})
350350

351-
t.Run("deprecated", func(t *testing.T) {
351+
t.Run("installed deprecated", func(t *testing.T) {
352352
var (
353-
name = "deprecated"
353+
name = "installed deprecated"
354354
version = "1.1.0"
355355
)
356356

@@ -365,7 +365,7 @@ func TestCatalogGetComponent(t *testing.T) {
365365
component, err := catalog.GetComponent(name)
366366
assert.NotNil(t, component)
367367
assert.Nil(t, err)
368-
assert.Equal(t, lwcomponent.Deprecated, component.Status)
368+
assert.Equal(t, lwcomponent.InstalledDeprecated, component.Status)
369369

370370
ver := component.InstalledVersion()
371371
assert.Equal(t, version, ver.String())
@@ -408,8 +408,7 @@ func TestCatalogListComponentVersions(t *testing.T) {
408408
assert.NotNil(t, component)
409409
assert.Nil(t, err)
410410

411-
vers, err := catalog.ListComponentVersions(component)
412-
assert.Nil(t, err)
411+
vers := catalog.ListComponentVersions(component)
413412

414413
for idx, v := range versions {
415414
assert.Equal(t, v, vers[idx].String())
@@ -810,10 +809,11 @@ func generateComponentsResponse(prefix string, count int) string {
810809

811810
for idx = 0; idx < int32(count); idx++ {
812811
component := api.LatestComponentVersion{
813-
Id: idx,
814-
Name: fmt.Sprintf("%s-%d", prefix, idx),
815-
Version: fmt.Sprintf("%d.0.0", idx),
816-
Size: 512,
812+
Id: idx,
813+
Name: fmt.Sprintf("%s-%d", prefix, idx),
814+
Version: fmt.Sprintf("%d.0.0", idx),
815+
Size: 512,
816+
Deprecated: false,
817817
}
818818

819819
components = append(components, component)
@@ -847,9 +847,10 @@ func generateInvalidComponentsResponse() string {
847847
func generateComponentVersionsResponse(name string, versions []string) string {
848848
response := api.ListComponentVersionsResponse{
849849
Data: []api.ComponentVersions{{
850-
Id: 1,
851-
Name: name,
852-
Versions: versions,
850+
Id: 1,
851+
Name: name,
852+
Deprecated: false,
853+
Versions: versions,
853854
}},
854855
}
855856

lwcomponent/cdk_component.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func NewCDKComponent(name string, componentType Type, apiInfo ApiInfo, hostInfo
3131
status := status(apiInfo, hostInfo)
3232

3333
switch status {
34-
case Installed, UpdateAvailable, Deprecated, Development:
34+
case Installed, UpdateAvailable, InstalledDeprecated, Development:
3535
{
3636
dir := hostInfo.Dir()
3737

@@ -84,7 +84,7 @@ func (c *CDKComponent) PrintSummary() []string {
8484
)
8585

8686
switch c.Status {
87-
case Installed, Deprecated, Development, UpdateAvailable, Tainted:
87+
case Installed, InstalledDeprecated, NotInstalledDeprecated, Development, UpdateAvailable, Tainted:
8888
version, err = c.hostInfo.Version()
8989
if err != nil {
9090
panic(err)
@@ -123,6 +123,10 @@ func status(apiInfo ApiInfo, hostInfo HostInfo) Status {
123123
return Tainted
124124
}
125125

126+
if apiInfo.Deprecated() {
127+
return InstalledDeprecated
128+
}
129+
126130
latestVer := apiInfo.LatestVersion()
127131
if latestVer.GreaterThan(installedVer) {
128132
return UpdateAvailable
@@ -133,12 +137,16 @@ func status(apiInfo ApiInfo, hostInfo HostInfo) Status {
133137
if hostInfo.Development() {
134138
return Development
135139
} else {
136-
return Deprecated
140+
return InstalledDeprecated
137141
}
138142
}
139143
}
140144

141145
if apiInfo != nil && hostInfo == nil {
146+
if apiInfo.Deprecated() {
147+
return NotInstalledDeprecated
148+
}
149+
142150
return NotInstalled
143151
}
144152

0 commit comments

Comments
 (0)