package cmd import ( "fmt" "os" "path/filepath" "sort" "time" "github.com/zemenawi/zutils/pkg/colors" "github.com/zemenawi/zutils/pkg/formatter" ) type FileItem struct { Path string Size int64 } type DirStats struct { TotalSize int64 FileCount int DirCount int LargestFiles []FileItem LargestDirs []FileItem LastModified time.Time FileExtensions map[string]int } func DirInfoCommand(args []string) error { if len(args) < 1 { return fmt.Errorf("please specify a directory path") } dirPath := args[0] stats, err := analyzeDirectory(dirPath) if err != nil { return fmt.Errorf("error analyzing directory: %w", err) } size := formatter.FormatSize(stats.TotalSize) modTime := stats.LastModified.Format(time.RFC1123) PrintBoxHeader("DIRECTORY INFORMATION", colors.Purple) fmt.Printf("%s%s📁 Path:%s %s\n", colors.Blue, colors.Bold, colors.Reset, dirPath) fmt.Printf("%s%s📏 Total Size:%s %s\n", colors.Blue, colors.Bold, colors.Reset, size) fmt.Printf("%s%s📊 Files:%s %d\n", colors.Blue, colors.Bold, colors.Reset, stats.FileCount) fmt.Printf("%s%s📂 Directories:%s %d\n", colors.Blue, colors.Bold, colors.Reset, stats.DirCount) fmt.Println() // Print largest files table if len(stats.LargestFiles) > 0 { PrintSectionHeader("LARGEST FILES") headers := []string{"#", "File Name", "Size"} data := make([][]string, 0, len(stats.LargestFiles)) for i, file := range stats.LargestFiles { name := filepath.Base(file.Path) row := []string{ fmt.Sprintf("%d", i+1), name, formatter.FormatSize(file.Size), } data = append(data, row) } printSimpleTable(headers, data) } // Print largest directories table if len(stats.LargestDirs) > 0 { PrintSectionHeader("LARGEST DIRS") headers := []string{"#", "Directory Name", "Size"} data := make([][]string, 0, len(stats.LargestDirs)) for i, dir := range stats.LargestDirs { name := filepath.Base(dir.Path) row := []string{ fmt.Sprintf("%d", i+1), name, formatter.FormatSize(dir.Size), } data = append(data, row) } printSimpleTable(headers, data) } // Print file type distribution table if len(stats.FileExtensions) > 0 { PrintSectionHeader("FILE TYPE DISTRIBUTION") type extCount struct { ext string count int } var sortedExts []extCount for ext, count := range stats.FileExtensions { sortedExts = append(sortedExts, extCount{ext, count}) } sort.Slice(sortedExts, func(i, j int) bool { return sortedExts[i].count > sortedExts[j].count }) maxShow := 10 if len(sortedExts) < maxShow { maxShow = len(sortedExts) } headers := []string{"#", "Extension", "File Count", "Percentage"} data := make([][]string, 0, maxShow) for i := 0; i < maxShow; i++ { ext := sortedExts[i].ext if ext == "" { ext = "(no extension)" } percentage := float64(sortedExts[i].count) / float64(stats.FileCount) * 100 row := []string{ fmt.Sprintf("%d", i+1), ext, fmt.Sprintf("%d", sortedExts[i].count), fmt.Sprintf("%.1f%%", percentage), } data = append(data, row) } printSimpleTable(headers, data) } PrintSectionHeader("DIRECTORY DETAILS") fmt.Printf("%s%s📅 Last Modified:%s %s\n", colors.Yellow, colors.Bold, colors.Reset, modTime) fmt.Println() return nil } func printSimpleTable(headers []string, data [][]string) { formatter.PrintTable(headers, data, colors.Cyan) fmt.Println() } func analyzeDirectory(path string) (*DirStats, error) { stats := &DirStats{ LargestFiles: make([]FileItem, 0), LargestDirs: make([]FileItem, 0), FileExtensions: make(map[string]int), } err := filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error { if err != nil { return err } if filePath == path { return nil } if info.IsDir() { stats.DirCount++ stats.LargestDirs = appendSorted(stats.LargestDirs, FileItem{ Path: filePath, Size: info.Size(), }, 5) } else { stats.FileCount++ stats.TotalSize += info.Size() ext := filepath.Ext(filePath) stats.FileExtensions[ext]++ stats.LargestFiles = appendSorted(stats.LargestFiles, FileItem{ Path: filePath, Size: info.Size(), }, 5) if info.ModTime().After(stats.LastModified) { stats.LastModified = info.ModTime() } } return nil }) return stats, err } func appendSorted(items []FileItem, newItem FileItem, maxSize int) []FileItem { items = append(items, newItem) sort.Slice(items, func(i, j int) bool { return items[i].Size > items[j].Size }) if len(items) > maxSize { items = items[:maxSize] } return items }