Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use api override and merging utils to get flatterned devfile #48

Merged
merged 14 commits into from
Dec 22, 2020
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/devfile/library
go 1.13

require (
github.com/devfile/api v0.0.0-20201126204309-ec222215253e
github.com/devfile/api v0.0.0-20201211221100-a68230324c7e
github.com/fatih/color v1.7.0
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
github.com/gobwas/glob v0.2.3
Expand Down
7 changes: 5 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/devfile/api v0.0.0-20201126204309-ec222215253e h1:NO6mS8ktVFjkVIKZKF2JjfL3ZxXw4VAtKIZWyp9e2kQ=
github.com/devfile/api v0.0.0-20201126204309-ec222215253e/go.mod h1:/aDiwWjDEW/fY1/Ig8umVtmneAXKZImnLvWqzMlcfrY=
github.com/devfile/api v0.0.0-20201211221100-a68230324c7e h1:Jy3C3ul05YvL4bJpAVhFwPZD8neOJUBZy7GuCcjc8nc=
github.com/devfile/api v0.0.0-20201211221100-a68230324c7e/go.mod h1:/aDiwWjDEW/fY1/Ig8umVtmneAXKZImnLvWqzMlcfrY=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
Expand Down Expand Up @@ -182,7 +182,9 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:Fecb
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
Expand Down Expand Up @@ -235,6 +237,7 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func main() {
devfile, err := ParseDevfile("devfile.yaml")
devfile, err := ParseDevfile("./devfile.yaml")
if err != nil {
fmt.Println(err)
} else {
Expand Down
1 change: 0 additions & 1 deletion pkg/devfile/parser/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ func (d *DevfileCtx) Populate() (err error) {
return err
}
klog.V(4).Infof("absolute devfile path: '%s'", d.absPath)

// Read and save devfile content
if err := d.SetDevfileContent(); err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions pkg/devfile/parser/data/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ type DevfileData interface {
DeleteVolume(name string) error
GetVolumeMountPath(name string) (string, error)

GetDevfileWorkspace() *v1.DevWorkspaceTemplateSpecContent
SetDevfileWorkspace(content v1.DevWorkspaceTemplateSpecContent)
//utils
GetDevfileContainerComponents(common.DevfileOptions) ([]v1.Component, error)
GetDevfileVolumeComponents(common.DevfileOptions) ([]v1.Component, error)
Expand Down
4 changes: 3 additions & 1 deletion pkg/devfile/parser/data/v2/common/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"reflect"

"github.com/devfile/api/pkg/attributes"
attriutespkg "github.com/devfile/api/pkg/attributes"
)

// DevfileOptions provides options for Devfile operations
Expand All @@ -19,7 +20,8 @@ func FilterDevfileObject(attributes attributes.Attributes, options DevfileOption
for key, value := range options.Filter {
currentFilterIn := false
attrValue := attributes.Get(key, &err)
if err != nil {
var keynotfound = &attriutespkg.KeyNotFoundError{Key: key}
if err != nil && err.Error() != keynotfound.Error() {
return false, err
} else if reflect.DeepEqual(attrValue, value) {
currentFilterIn = true
Expand Down
12 changes: 12 additions & 0 deletions pkg/devfile/parser/data/v2/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func (d *DevfileV2) AddComponents(components []v1.Component) error {
// can exist in devfile
containerMap := make(map[string]bool)
volumeMap := make(map[string]bool)
pluginMap := make(map[string]bool)

for _, component := range d.Components {
if component.Volume != nil {
Expand All @@ -72,6 +73,9 @@ func (d *DevfileV2) AddComponents(components []v1.Component) error {
if component.Container != nil {
containerMap[component.Name] = true
}
if component.Plugin != nil {
pluginMap[component.Name] = true
}
}

for _, component := range components {
Expand All @@ -91,6 +95,14 @@ func (d *DevfileV2) AddComponents(components []v1.Component) error {
return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"}
}
}

if component.Plugin != nil {
if _, ok := pluginMap[component.Name]; !ok {
d.Components = append(d.Components, component)
} else {
return &common.FieldAlreadyExistError{Name: component.Name, Field: "component"}
}
}
}
return nil
}
Expand Down
11 changes: 11 additions & 0 deletions pkg/devfile/parser/data/v2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,14 @@ import (
type DevfileV2 struct {
v1.Devfile
}

// GetDevfileWorkspace returns the workspace content for the devfile
func (d *DevfileV2) GetDevfileWorkspace() *v1.DevWorkspaceTemplateSpecContent {

return &d.DevWorkspaceTemplateSpecContent
}

// SetDevfileWorkspace sets the workspace content
func (d *DevfileV2) SetDevfileWorkspace(content v1.DevWorkspaceTemplateSpecContent) {
d.DevWorkspaceTemplateSpecContent = content
}
226 changes: 0 additions & 226 deletions pkg/devfile/parser/devfileobj.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
package parser

import (
"encoding/json"
"fmt"
"strings"

v1 "github.com/devfile/api/pkg/apis/workspaces/v1alpha2"
devfileCtx "github.com/devfile/library/pkg/devfile/parser/context"
"github.com/devfile/library/pkg/devfile/parser/data"
"github.com/devfile/library/pkg/devfile/parser/data/v2/common"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/strategicpatch"
)

// Default filenames for create devfile
Expand All @@ -28,221 +20,3 @@ type DevfileObj struct {
// Data has the devfile data
Data data.DevfileData
}

// OverrideComponents overrides the components of the parent devfile
// overridePatch contains the patches to be applied to the parent's components
func (d DevfileObj) OverrideComponents(overridePatch []v1.ComponentParentOverride) error {
// func (d DevfileObj) OverrideComponents(overridePatch interface{}) error {
for _, patchComponent := range overridePatch {
found := false
originalComponents, err := d.Data.GetComponents(common.DevfileOptions{})
if err != nil {
return err
}
for _, originalComponent := range originalComponents {
if strings.ToLower(patchComponent.Name) == originalComponent.Name {
found = true

var updatedComponent v1.ContainerComponent

merged, err := handleMerge(originalComponent.Container, patchComponent.Container, v1.ContainerComponent{})
if err != nil {
return err
}
err = json.Unmarshal(merged, &updatedComponent)
if err != nil {
return errors.Wrap(err, "failed to unmarshal override components")
}

d.Data.UpdateComponent(v1.Component{
Name: patchComponent.Name,
ComponentUnion: v1.ComponentUnion{
Container: &updatedComponent,
},
})
}
}
if !found {
return fmt.Errorf("the component to override is not found in the parent")
}
}
return nil
}

// OverrideCommands overrides the commands of the parent devfile
// overridePatch contains the patches to be applied to the parent's commands
func (d DevfileObj) OverrideCommands(overridePatch []v1.CommandParentOverride) (err error) {
for _, patchCommand := range overridePatch {
found := false
originalCommands, err := d.Data.GetCommands(common.DevfileOptions{})
if err != nil {
return err
}
for _, originalCommand := range originalCommands {

if strings.ToLower(patchCommand.Id) == originalCommand.Id {
found = true

var devfileCommand v1.Command

if patchCommand.Exec != nil && originalCommand.Exec != nil {
devfileCommand, err = overrideExecCommand(patchCommand, originalCommand)
if err != nil {
return err
}

} else if patchCommand.Composite != nil && originalCommand.Composite != nil {
devfileCommand, err = overrideCompositeCommand(patchCommand, originalCommand)
if err != nil {
return err
}
// TODO: add other command types
} else {
// If the original command and patch command are different types, then we can't patch, so throw an error
return fmt.Errorf("cannot overide command %q with a different type of command", originalCommand.Id)
}

d.Data.UpdateCommand(devfileCommand)
}
}
if !found {
return fmt.Errorf("the command to override is not found in the parent")
}
}
return nil
}

// overrideCompositeCommand overrides the given parent composite commmand
// patchCommand contains the patches to be applied to the parent's command
func overrideCompositeCommand(patchCommand v1.CommandParentOverride, originalCommand v1.Command) (v1.Command, error) {
var updatedComposite v1.CompositeCommand

merged, err := handleMerge(originalCommand.Composite, patchCommand.Composite, v1.CompositeCommand{})
if err != nil {
return v1.Command{}, err
}

err = json.Unmarshal(merged, &updatedComposite)
if err != nil {
return v1.Command{}, errors.Wrap(err, "failed to unmarshal override commands")
}
return v1.Command{
Id: patchCommand.Id,
CommandUnion: v1.CommandUnion{
Composite: &updatedComposite,
},
}, nil
}

// overrideExecCommand overrides the given parent Exec commmand
// patchCommand contains the patches to be applied to the parent's command
func overrideExecCommand(patchCommand v1.CommandParentOverride, originalCommand v1.Command) (v1.Command, error) {
var updatedExec v1.ExecCommand
merged, err := handleMerge(originalCommand.Exec, patchCommand.Exec, v1.ExecCommand{})
if err != nil {
return v1.Command{}, err
}

err = json.Unmarshal(merged, &updatedExec)
if err != nil {
return v1.Command{}, errors.Wrap(err, "failed to unmarshal override commands")
}
return v1.Command{
Id: patchCommand.Id,
CommandUnion: v1.CommandUnion{
Exec: &updatedExec,
},
}, nil
}

// OverrideProjects overrides the projects of the parent devfile
// overridePatch contains the patches to be applied to the parent's projects
func (d DevfileObj) OverrideProjects(overridePatch []v1.ProjectParentOverride) error {
for _, patchProject := range overridePatch {
found := false
originalProjects, err := d.Data.GetProjects(common.DevfileOptions{})
if err != nil {
return err
}
for _, originalProject := range originalProjects {
if strings.ToLower(patchProject.Name) == originalProject.Name {
found = true
var updatedProject v1.Project

merged, err := handleMerge(originalProject, patchProject, v1.Project{})
if err != nil {
return err
}

err = json.Unmarshal(merged, &updatedProject)
if err != nil {
return errors.Wrap(err, "failed to unmarshal override projects")
}

d.Data.UpdateProject(updatedProject)
}
}
if !found {
return fmt.Errorf("the command to override is not found in the parent")
}
}
return nil
}

// OverrideStarterProjects overrides the starter projects of the parent devfile
// overridePatch contains the patches to be applied to the parent's starter projects
func (d DevfileObj) OverrideStarterProjects(overridePatch []v1.StarterProjectParentOverride) error {
for _, patchProject := range overridePatch {
found := false

originalProjects, err := d.Data.GetStarterProjects(common.DevfileOptions{})
if err != nil {
return err
}
for _, originalProject := range originalProjects {
if strings.ToLower(patchProject.Name) == originalProject.Name {
found = true
var updatedProject v1.StarterProject

merged, err := handleMerge(originalProject, patchProject, v1.StarterProject{})
if err != nil {
return err
}

err = json.Unmarshal(merged, &updatedProject)
if err != nil {
return errors.Wrap(err, "failed to unmarshal override starter projects")
}
d.Data.UpdateStarterProject(updatedProject)
}
}
if !found {
return fmt.Errorf("the starterProject to override is not found in the parent")
}
}
return nil
}

// handleMerge merges the patch to the original data
// dataStruct is the type of the original and the patch data
func handleMerge(original, patch, dataStruct interface{}) ([]byte, error) {
// if reflect.TypeOf(original) != reflect.TypeOf(patch) {
// return nil, fmt.Errorf("type of original and patch doesn't match")
// }

originalJson, err := json.Marshal(original)
if err != nil {
return nil, err
}

patchJson, err := json.Marshal(patch)
if err != nil {
return nil, err
}

merged, err := strategicpatch.StrategicMergePatch(originalJson, patchJson, dataStruct)
if err != nil {
return nil, err
}
return merged, nil
}
Loading