1+ package com.dengzii.plugin.auc
2+
3+ import com.dengzii.plugin.auc.template.AucTemplate
4+ import com.dengzii.plugin.auc.template.Placeholder
5+ import com.dengzii.plugin.auc.template.replacePlaceholder
6+ import java.io.File
7+
8+ /* *
9+ * <pre>
10+ * author : dengzi
11+ * e-mail : denua@foxmail.com
12+ * github : https://github.com/dengzii
13+ * time : 2019/1/1
14+ * desc :
15+ </pre> */
16+ open class FileTreeNode private constructor() {
17+
18+ var name: String
19+ get() = realName.replacePlaceholder(placeHolderMap)
20+ set(value) {
21+ realName = value
22+ }
23+
24+ var isDir = true
25+ val children by lazy { mutableListOf<FileTreeNode >() }
26+ var placeHolderMap: MutableMap <Placeholder , String >? = null
27+ get() = field ? : parent?.placeHolderMap
28+
29+ // the origin name with original placeholder
30+ private var realName: String = " "
31+ private var parent: FileTreeNode ? = null
32+
33+
34+ companion object {
35+ private val TAG = FileTreeNode ::class .java.simpleName
36+
37+ fun root (path : String ): FileTreeNode {
38+ val root = File (path)
39+ if (! root.isDirectory) {
40+ throw RuntimeException (" The root must be a directory." )
41+ }
42+ return with (FileTreeNode (null , path, true )) {
43+ this .parent = this
44+ this
45+ }
46+ }
47+ }
48+
49+ constructor (block: FileTreeNode .() -> Unit ) : this () {
50+ invoke(block)
51+ }
52+
53+ constructor (parent: FileTreeNode ? , name: String , isDir: Boolean ) : this () {
54+ this .name = name
55+ this .parent = parent
56+ this .isDir = isDir
57+ }
58+
59+ operator fun invoke (block : FileTreeNode .() -> Unit ): FileTreeNode {
60+ this .block()
61+ return this
62+ }
63+
64+ /* *
65+ * set current node as root.
66+ * the file of specified path must be a directory and exist.
67+ * the root's 'name' is the root path of entire file tree.
68+ *
69+ * @param path: The root directory path of whole file tree
70+ */
71+ fun setRoot (path : String ): FileTreeNode {
72+ if (! File (path).isDirectory) {
73+ throw RuntimeException (" The root must be a directory." )
74+ }
75+ parent = this
76+ name = path
77+ return this
78+ }
79+
80+ /* *
81+ * traversal and create file tree, must be called from the root node.
82+ * the existing files will be skipped
83+ */
84+ fun create () {
85+ if (! isRoot()) {
86+ throw RuntimeException (" Must create structure from root node." )
87+ }
88+ createChild()
89+ }
90+
91+ /* *
92+ * traverse and call back each node of the entire file tree.
93+ */
94+ fun traversal (block : (it: FileTreeNode , depth: Int ) -> Unit , depth : Int = 0) {
95+ if (! isDir) return
96+
97+ children.forEach {
98+ block(it, depth)
99+ it.traversal(block, depth + 1 )
100+ }
101+ }
102+
103+ /* *
104+ * merge all children of another node to 'this.children'.
105+ */
106+ fun include (other : FileTreeNode ) {
107+ if (! isDir) return
108+ children.addAll(other.children)
109+ }
110+
111+ fun dir (name : String , block : FileTreeNode .() -> Unit = {}) {
112+ if (! isDir) return
113+ val dir = FileTreeNode (this , name, true )
114+ children.add(dir)
115+ dir(block)
116+ }
117+
118+ fun file (name : String ) {
119+ if (! isDir) return
120+ children.add(FileTreeNode (this , name, false ))
121+ }
122+
123+ /* *
124+ * get path of current node.
125+ * if the current node is the root node, it will return absolute path,
126+ * otherwise return relative path.
127+ */
128+ fun getPath (): String {
129+ if (isRoot() || parent == null || parent!! .name == " " ) {
130+ return name
131+ }
132+ return parent!! .getPath() + " /" + name
133+ }
134+
135+
136+ fun isRoot (): Boolean {
137+ return this == parent
138+ }
139+
140+ fun getTreeGraph (): String {
141+ val strBuilder = StringBuilder ()
142+ traversal({ i, dep ->
143+ val head = if (i.isRoot()) " ┌" else if (children.last() == i) " └" else " ├"
144+ strBuilder.append(" │ " .repeat(dep) + " $head ─" + i.name)
145+ })
146+ return strBuilder.toString()
147+ }
148+
149+ private fun createChild () {
150+ children.forEach {
151+ val file = File (it.getPath())
152+ if (file.exists()) {
153+ Logger .d(TAG , " ${file.absolutePath} already exists." )
154+ } else {
155+ Logger .d(TAG , " create ${file.absolutePath} " )
156+ if (it.isDir) {
157+ file.mkdir()
158+ } else {
159+ file.createNewFile()
160+ }
161+ }
162+ if (it.isDir) {
163+ it.createChild()
164+ }
165+ }
166+ }
167+
168+ override fun toString (): String {
169+ return " FileTreeNode(path='${getPath()} ')"
170+ }
171+ }
0 commit comments