airshipctl/pkg/document/tree.go

187 lines
4.8 KiB
Go

/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package document
import (
"fmt"
"io"
"path/filepath"
"sigs.k8s.io/kustomize/api/types"
"opendev.org/airship/airshipctl/pkg/fs"
)
// KustomNode is used to create name and data to display tree structure
type KustomNode struct {
Name string // name used for display purposes (cli)
Data string // this could be a Kustomization object, or a string containing a file path
Children []KustomNode
Writer io.Writer
}
// BuildKustomTree creates a tree based on entrypoint
func BuildKustomTree(entrypoint string, writer io.Writer, manifestsDir string) (KustomNode, error) {
fs := fs.NewDocumentFs()
name, err := filepath.Rel(manifestsDir, entrypoint)
if err != nil {
name = entrypoint
}
root := KustomNode{
Name: name,
Data: entrypoint,
Children: []KustomNode{},
Writer: writer,
}
resMap, err := MakeResMap(fs, entrypoint)
if err != nil {
return KustomNode{}, err
}
for sourceType, sources := range resMap {
n := KustomNode{
Name: sourceType,
Writer: writer,
}
for _, s := range sources {
if !fs.IsDir(s) {
name, err := filepath.Rel(manifestsDir, s)
if err != nil {
name = s
}
n.Children = append(n.Children, KustomNode{
Name: name,
Data: s,
})
} else {
s = filepath.Join(s, KustomizationFile)
child, err := BuildKustomTree(s, writer, "")
if err != nil {
return KustomNode{}, err
}
n.Children = append(n.Children, child)
}
}
root.Children = append(root.Children, n)
}
return root, nil
}
//MakeResMap creates resmap based of kustomize types
func MakeResMap(fs fs.FileSystem, kfile string) (map[string][]string, error) {
if fs == nil {
return nil, fmt.Errorf("received nil filesystem")
}
bytes, err := fs.ReadFile(kfile)
if err != nil {
return nil, err
}
k := types.Kustomization{}
err = k.Unmarshal(bytes)
if err != nil {
return nil, err
}
basedir := filepath.Dir(kfile)
var resMap = make(map[string][]string)
for _, p := range k.Resources {
path := filepath.Join(basedir, p)
resMap["Resources"] = append(resMap["Resources"], path)
}
for _, p := range k.Crds {
path := filepath.Join(basedir, p)
resMap["Crds"] = append(resMap["Crds"], path)
}
buildConfigMapAndSecretGenerator(k, basedir, resMap)
for _, p := range k.Generators {
path := filepath.Join(basedir, p)
resMap["Generators"] = append(resMap["Generators"], path)
}
for _, p := range k.Transformers {
path := filepath.Join(basedir, p)
resMap["Transformers"] = append(resMap["Transformers"], path)
}
return resMap, nil
}
func buildConfigMapAndSecretGenerator(k types.Kustomization, basedir string, resMap map[string][]string) {
for _, p := range k.SecretGenerator {
for _, s := range p.FileSources {
path := filepath.Join(basedir, s)
resMap["SecretGenerator"] = append(resMap["SecretGenerator"], path)
}
}
for _, p := range k.ConfigMapGenerator {
for _, s := range p.FileSources {
path := filepath.Join(basedir, s)
resMap["ConfigMapGenerator"] = append(resMap["ConfigMapGenerator"], path)
}
}
}
// PrintTree prints tree view of phase
func (k KustomNode) PrintTree(prefix string) {
if prefix == "" {
basedir := filepath.Dir(k.Name)
dir := filepath.Base(basedir)
fmt.Fprintf(k.Writer, "%s [%s]\n", dir, basedir)
}
for i, child := range k.Children {
var subprefix string
knodes := GetKustomChildren(child)
if len(knodes) > 0 {
// we found a kustomize file, so print the subtree name first
if i == len(k.Children)-1 {
fmt.Fprintf(k.Writer, "%s└── %s\n", prefix, child.Name)
subprefix = " "
} else {
fmt.Fprintf(k.Writer, "%s├── %s\n", prefix, child.Name)
subprefix = "│ "
}
}
for j, c := range knodes {
bd := filepath.Dir(c.Name)
d := filepath.Base(bd)
name := fmt.Sprintf("%s [%s]", d, bd)
if j == len(knodes)-1 {
fmt.Printf("%s%s└── %s\n", prefix, subprefix, name)
c.PrintTree(fmt.Sprintf("%s%s ", prefix, subprefix))
} else {
fmt.Printf("%s%s├── %s\n", prefix, subprefix, name)
c.PrintTree(fmt.Sprintf("%s%s│ ", prefix, subprefix))
}
}
}
}
// GetKustomChildren returns children nodes of kustomnode
func GetKustomChildren(k KustomNode) []KustomNode {
nodes := []KustomNode{}
for _, c := range k.Children {
if len(c.Children) > 0 {
nodes = append(nodes, c)
}
}
return nodes
}