github.com/jfrog/jfrog-cli-core/v2@v2.52.0/artifactory/utils/filetree.go (about) 1 package utils 2 3 import ( 4 "strings" 5 ) 6 7 var maxFilesInTree = 200 8 9 // FileTree is a UI components that displays a file-system tree view in the terminal. 10 type FileTree struct { 11 repos map[string]*dirNode 12 size int 13 exceedsMax bool 14 } 15 16 func NewFileTree() *FileTree { 17 return &FileTree{repos: map[string]*dirNode{}, size: 0} 18 } 19 20 func (ft *FileTree) AddFile(path string) { 21 if ft.size >= maxFilesInTree { 22 ft.exceedsMax = true 23 return 24 } 25 splitPath := strings.Split(path, "/") 26 if _, exist := ft.repos[splitPath[0]]; !exist { 27 ft.repos[splitPath[0]] = &dirNode{name: splitPath[0], prefix: "📦 ", subDirNodes: map[string]*dirNode{}, fileNames: map[string]bool{}} 28 } 29 if ft.repos[splitPath[0]].addArtifact(splitPath[1:]) { 30 ft.size++ 31 } 32 } 33 34 // Returns a string representation of the tree. If the number of files exceeded the maximum, an empty string will be returned. 35 func (ft *FileTree) String() string { 36 if ft.exceedsMax { 37 return "" 38 } 39 treeStr := "" 40 for _, repo := range ft.repos { 41 treeStr += strings.Join(repo.strings(), "\n") + "\n" 42 } 43 return treeStr 44 } 45 46 type dirNode struct { 47 name string 48 prefix string 49 subDirNodes map[string]*dirNode 50 fileNames map[string]bool 51 } 52 53 func (dn *dirNode) addArtifact(pathInDir []string) bool { 54 if len(pathInDir) == 1 { 55 if _, exist := dn.fileNames[pathInDir[0]]; exist { 56 return false 57 } 58 dn.fileNames[pathInDir[0]] = true 59 } else { 60 if _, exist := dn.subDirNodes[pathInDir[0]]; !exist { 61 dn.subDirNodes[pathInDir[0]] = &dirNode{name: pathInDir[0], prefix: "📁 ", subDirNodes: map[string]*dirNode{}, fileNames: map[string]bool{}} 62 } 63 return dn.subDirNodes[pathInDir[0]].addArtifact(pathInDir[1:]) 64 } 65 return true 66 } 67 68 func (dn *dirNode) strings() []string { 69 strs := []string{dn.prefix + dn.name} 70 subDirIndex := 0 71 for subDirName := range dn.subDirNodes { 72 var subDirPrefix string 73 var innerStrPrefix string 74 if subDirIndex == len(dn.subDirNodes)-1 && len(dn.fileNames) == 0 { 75 subDirPrefix = "└── " 76 innerStrPrefix = " " 77 } else { 78 subDirPrefix = "├── " 79 innerStrPrefix = "│ " 80 } 81 subDirStrs := dn.subDirNodes[subDirName].strings() 82 strs = append(strs, subDirPrefix+subDirStrs[0]) 83 for subDirStrIndex := 1; subDirStrIndex < len(subDirStrs); subDirStrIndex++ { 84 strs = append(strs, innerStrPrefix+subDirStrs[subDirStrIndex]) 85 } 86 subDirIndex++ 87 } 88 fileIndex := 0 89 for fileName := range dn.fileNames { 90 var filePrefix string 91 if fileIndex == len(dn.fileNames)-1 { 92 filePrefix = "└── 📄 " 93 } else { 94 filePrefix = "├── 📄 " 95 fileIndex++ 96 } 97 strs = append(strs, filePrefix+fileName) 98 } 99 return strs 100 }