Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions pkg/commands/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ limitations under the License.
package build

import (
"io"

"github.com/pkg/errors"
"github.com/spf13/cobra"
"io"
"path"
"sigs.k8s.io/kustomize/pkg/fs"
"sigs.k8s.io/kustomize/pkg/ifc/transformer"
"sigs.k8s.io/kustomize/pkg/loader"
Expand All @@ -33,6 +33,7 @@ import (
type Options struct {
kustomizationPath string
outputPath string
outputDirPath string
}

// NewOptions creates a Options object
Expand Down Expand Up @@ -82,6 +83,10 @@ func NewCmdBuild(
&o.outputPath,
"output", "o", "",
"If specified, write the build output to this path.")
cmd.Flags().StringVarP(
&o.outputDirPath,
"outputDir", "d", "",
"If specified, write the build output to this directory.")
return cmd
}

Expand Down Expand Up @@ -124,6 +129,26 @@ func (o *Options) RunBuild(
if o.outputPath != "" {
return fSys.WriteFile(o.outputPath, res)
}
if o.outputDirPath != "" {
if !fSys.Exists(o.outputDirPath) {
err = fSys.MkdirAll(o.outputDirPath)
if err != nil {
return err
}
}
allResourcesByFileName := allResources.SplitByFileName()
for fileName, resources := range allResourcesByFileName {
res, err := resources.EncodeAsYaml()
if err != nil {
return err
}
err = fSys.WriteFile(path.Join(o.outputDirPath, fileName), res)
if err != nil {
return err
}
}
return nil
}
_, err = out.Write(res)
return err
}
6 changes: 3 additions & 3 deletions pkg/resmap/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (rmF *Factory) FromFiles(
if err != nil {
return nil, errors.Wrap(err, "Load from path "+path+" failed")
}
res, err := rmF.NewResMapFromBytes(content)
res, err := rmF.NewResMapFromBytes(content, path)
if err != nil {
return nil, internal.Handler(err, path)
}
Expand All @@ -60,8 +60,8 @@ func (rmF *Factory) FromFiles(
}

// newResMapFromBytes decodes a list of objects in byte array format.
func (rmF *Factory) NewResMapFromBytes(b []byte) (ResMap, error) {
resources, err := rmF.resF.SliceFromBytes(b)
func (rmF *Factory) NewResMapFromBytes(b []byte, fileName string) (ResMap, error) {
resources, err := rmF.resF.SliceFromBytes(b, fileName)
if err != nil {
return nil, err
}
Expand Down
38 changes: 19 additions & 19 deletions pkg/resmap/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,31 +58,31 @@ metadata:
if ferr := l.AddFile("/whatever/project/deployment.yaml", []byte(resourceStr)); ferr != nil {
t.Fatalf("Error adding fake file: %v\n", ferr)
}
expected := ResMap{resid.NewResId(deploy, "dply1"): rf.FromMap(
expected := ResMap{resid.NewResId(deploy, "dply1"): rf.FromMapAndFileName(
map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "dply1",
},
}),
resid.NewResId(deploy, "dply2"): rf.FromMap(
}, "deployment.yaml"),
resid.NewResId(deploy, "dply2"): rf.FromMapAndFileName(
map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "dply2",
},
}),
resid.NewResIdWithPrefixNamespace(deploy, "dply2", "", "test"): rf.FromMap(
}, "deployment.yaml"),
resid.NewResIdWithPrefixNamespace(deploy, "dply2", "", "test"): rf.FromMapAndFileName(
map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "dply2",
"namespace": "test",
},
}),
}, "deployment.yaml"),
}

m, _ := rmF.FromFiles(
Expand All @@ -108,24 +108,24 @@ metadata:
name: cm2
`)
expected := ResMap{
resid.NewResId(cmap, "cm1"): rf.FromMap(
resid.NewResId(cmap, "cm1"): rf.FromMapAndFileName(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "cm1",
},
}),
resid.NewResId(cmap, "cm2"): rf.FromMap(
}, "cm12.yaml"),
resid.NewResId(cmap, "cm2"): rf.FromMapAndFileName(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "cm2",
},
}),
}, "cm12.yaml"),
}
m, err := rmF.NewResMapFromBytes(encoded)
m, err := rmF.NewResMapFromBytes(encoded, "cm12.yaml")
fmt.Printf("%v\n", m)
if err != nil {
t.Fatalf("unexpected error: %v", err)
Expand Down Expand Up @@ -163,7 +163,7 @@ func TestNewFromConfigMaps(t *testing.T) {
filepath: "/whatever/project/app.env",
content: "DB_USERNAME=admin\nDB_PASSWORD=somepw",
expected: ResMap{
resid.NewResId(cmap, "envConfigMap"): rf.FromMapAndOption(
resid.NewResId(cmap, "envConfigMap"): rf.FromMapAndOptionAndFileName(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
Expand All @@ -174,7 +174,7 @@ func TestNewFromConfigMaps(t *testing.T) {
"DB_USERNAME": "admin",
"DB_PASSWORD": "somepw",
},
}, &types.GeneratorArgs{}, nil),
}, &types.GeneratorArgs{}, nil, "envConfigMap.yaml"),
},
},
{
Expand All @@ -191,7 +191,7 @@ func TestNewFromConfigMaps(t *testing.T) {
filepath: "/whatever/project/app-init.ini",
content: "FOO=bar\nBAR=baz\n",
expected: ResMap{
resid.NewResId(cmap, "fileConfigMap"): rf.FromMapAndOption(
resid.NewResId(cmap, "fileConfigMap"): rf.FromMapAndOptionAndFileName(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
Expand All @@ -203,7 +203,7 @@ func TestNewFromConfigMaps(t *testing.T) {
BAR=baz
`,
},
}, &types.GeneratorArgs{}, nil),
}, &types.GeneratorArgs{}, nil, "fileConfigMap.yaml"),
},
},
{
Expand All @@ -219,7 +219,7 @@ BAR=baz
},
},
expected: ResMap{
resid.NewResId(cmap, "literalConfigMap"): rf.FromMapAndOption(
resid.NewResId(cmap, "literalConfigMap"): rf.FromMapAndOptionAndFileName(
map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
Expand All @@ -232,7 +232,7 @@ BAR=baz
"c": "Good Morning",
"d": "false",
},
}, &types.GeneratorArgs{}, nil),
}, &types.GeneratorArgs{}, nil, "literalConfigMap.yaml"),
},
},
// TODO: add testcase for data coming from multiple sources like
Expand Down Expand Up @@ -278,7 +278,7 @@ func TestNewResMapFromSecretArgs(t *testing.T) {
}

expected := ResMap{
resid.NewResId(secret, "apple"): rf.FromMapAndOption(
resid.NewResId(secret, "apple"): rf.FromMapAndOptionAndFileName(
map[string]interface{}{
"apiVersion": "v1",
"kind": "Secret",
Expand All @@ -290,7 +290,7 @@ func TestNewResMapFromSecretArgs(t *testing.T) {
"DB_USERNAME": base64.StdEncoding.EncodeToString([]byte("admin")),
"DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")),
},
}, &types.GeneratorArgs{}, nil),
}, &types.GeneratorArgs{}, nil, "apple.yaml"),
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("%#v\ndoesn't match expected:\n%#v", actual, expected)
Expand Down
11 changes: 11 additions & 0 deletions pkg/resmap/resmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@ func (m ResMap) FilterBy(inputId resid.ResId) ResMap {
return result
}

func (m ResMap) SplitByFileName() map[string]ResMap {
resByFileName := make(map[string]ResMap)
for k, v := range m {
if _, ok := resByFileName[v.FileName()]; !ok {
resByFileName[v.FileName()] = ResMap{}
}
resByFileName[v.FileName()][k] = v
}
return resByFileName
}

// MergeWithErrorOnIdCollision combines multiple ResMap instances, failing on
// key collision and skipping nil maps.
// If all of the maps are nil, an empty ResMap is returned.
Expand Down
39 changes: 29 additions & 10 deletions pkg/resource/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ func (rf *Factory) FromMap(m map[string]interface{}) *Resource {
return &Resource{
Kunstructured: rf.kf.FromMap(m),
options: types.NewGenArgs(nil, nil),
fileName: "",
}
}

// FromMapAndFileName returns a new instance of Resource with given filename.
func (rf *Factory) FromMapAndFileName(m map[string]interface{}, filename string) *Resource {
return &Resource{
Kunstructured: rf.kf.FromMap(m),
options: types.NewGenArgs(nil, nil),
fileName: filename,
}
}

Expand All @@ -51,18 +61,29 @@ func (rf *Factory) FromMapAndOption(m map[string]interface{}, args *types.Genera
return &Resource{
Kunstructured: rf.kf.FromMap(m),
options: types.NewGenArgs(args, option),
fileName: "",
}
}

// FromMapAndOptionAndFileName returns a new instance of Resource with given options and filename.
func (rf *Factory) FromMapAndOptionAndFileName(m map[string]interface{}, args *types.GeneratorArgs, option *types.GeneratorOptions, filename string) *Resource {
return &Resource{
Kunstructured: rf.kf.FromMap(m),
options: types.NewGenArgs(args, option),
fileName: filename,
}
}

// FromKunstructured returns a new instance of Resource.
func (rf *Factory) FromKunstructured(
u ifc.Kunstructured) *Resource {
u ifc.Kunstructured, filename string) *Resource {
if u == nil {
log.Fatal("unstruct ifc must not be null")
}
return &Resource{
Kunstructured: u,
options: types.NewGenArgs(nil, nil),
fileName: filename,
}
}

Expand All @@ -76,7 +97,7 @@ func (rf *Factory) SliceFromPatches(
if err != nil {
return nil, err
}
res, err := rf.SliceFromBytes(content)
res, err := rf.SliceFromBytes(content, "")
if err != nil {
return nil, internal.Handler(err, string(path))
}
Expand All @@ -86,7 +107,7 @@ func (rf *Factory) SliceFromPatches(
}

// SliceFromBytes unmarshalls bytes into a Resource slice.
func (rf *Factory) SliceFromBytes(in []byte) ([]*Resource, error) {
func (rf *Factory) SliceFromBytes(in []byte, filename string) ([]*Resource, error) {
kunStructs, err := rf.kf.SliceFromBytes(in)
if err != nil {
return nil, err
Expand Down Expand Up @@ -118,7 +139,7 @@ func (rf *Factory) SliceFromBytes(in []byte) ([]*Resource, error) {
kunStructs = append(kunStructs, innerU...)
}
} else {
result = append(result, rf.FromKunstructured(u))
result = append(result, rf.FromKunstructured(u, filename))
}
}
return result, nil
Expand All @@ -135,9 +156,8 @@ func (rf *Factory) MakeConfigMap(
}
return &Resource{
Kunstructured: u,
options: types.NewGenArgs(
&types.GeneratorArgs{Behavior: args.Behavior},
options),
options: types.NewGenArgs(&types.GeneratorArgs{Behavior: args.Behavior}, options),
fileName: args.Name + ".yaml",
}, nil
}

Expand All @@ -152,8 +172,7 @@ func (rf *Factory) MakeSecret(
}
return &Resource{
Kunstructured: u,
options: types.NewGenArgs(
&types.GeneratorArgs{Behavior: args.Behavior},
options),
options: types.NewGenArgs(&types.GeneratorArgs{Behavior: args.Behavior}, options),
fileName: args.Name + ".yaml",
}, nil
}
17 changes: 16 additions & 1 deletion pkg/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ limitations under the License.
package resource

import (
"github.com/ghodss/yaml"
"strings"

"sigs.k8s.io/kustomize/pkg/ifc"
Expand All @@ -29,7 +30,8 @@ import (
// paired with a GenerationBehavior.
type Resource struct {
ifc.Kunstructured
options *types.GenArgs
options *types.GenArgs
fileName string
}

// String returns resource as JSON.
Expand All @@ -41,11 +43,24 @@ func (r *Resource) String() string {
return strings.TrimSpace(string(bs)) + r.options.String()
}

func (r *Resource) Yaml() []byte {
out, err := yaml.Marshal(r.Map())
if err != nil {
return nil
}
return out
}

func (r *Resource) FileName() string {
return r.fileName
}

// DeepCopy returns a new copy of resource
func (r *Resource) DeepCopy() *Resource {
return &Resource{
Kunstructured: r.Kunstructured.Copy(),
options: r.options,
fileName: r.fileName,
}
}

Expand Down
Loading