package fs import ( "strings" cmap "github.com/orcaman/concurrent-map/v2" ) // FileNode represents a directory or a file. If IsDir is true, Children is used. type FileNode struct { Name string IsDir bool Children cmap.ConcurrentMap[string, *FileNode] } // NewFileNode creates a new FileNode, initializing the concurrent map if it is a directory. func NewFileNode(name string, isDir bool) *FileNode { node := &FileNode{ Name: name, IsDir: isDir, } if isDir { node.Children = cmap.New[*FileNode]() } return node } // AddChild adds a child node to a directory node. func (n *FileNode) AddChild(child *FileNode) { if n.IsDir { n.Children.Set(child.Name, child) } } // AddPath adds a path to the file system like mkdir -p. func (n *FileNode) MakeDirectoryWithPath(path string) { currentNode := n for _, part := range SplitPath(path) { child, ok := currentNode.Children.Get(part) if !ok { child = NewFileNode(part, true) currentNode.AddChild(child) } currentNode = child } } // AddChildToPath adds a child to a path in the file system. Path should be an existing directory. func (n *FileNode) AddChildToPath(path string, child *FileNode) { parent := n.GetFileNode(path) if parent != nil && parent.IsDir { parent.AddChild(child) } } // ListFiles returns a list of files in the file system. func (n *FileNode) ListFiles() []*FileNode { var files []*FileNode n.Children.IterCb(func(key string, value *FileNode) { files = append(files, value) }) return files } // GetFileNode returns the FileNode of the given path. func (n *FileNode) GetFileNode(path string) *FileNode { currentNode := n for _, part := range SplitPath(path) { child, ok := currentNode.Children.Get(part) if !ok { return nil } currentNode = child } return currentNode } // SplitPath splits a path into its parts. func SplitPath(path string) []string { var parts []string for _, part := range strings.Split(path, "/") { if part != "" { parts = append(parts, part) } } return parts }