1package main 2 3import ( 4 "errors" 5 "flag" 6 "fmt" 7 "os" 8 9 "github.com/a8m/tree" 10 "github.com/a8m/tree/ostree" 11) 12 13var ( 14 // List 15 a = flag.Bool("a", false, "") 16 d = flag.Bool("d", false, "") 17 f = flag.Bool("f", false, "") 18 ignorecase = flag.Bool("ignore-case", false, "") 19 noreport = flag.Bool("noreport", false, "") 20 l = flag.Bool("l", false, "") 21 L = flag.Int("L", 3, "") 22 P = flag.String("P", "", "") 23 I = flag.String("I", "", "") 24 o = flag.String("o", "", "") 25 // Files 26 s = flag.Bool("s", false, "") 27 h = flag.Bool("h", false, "") 28 p = flag.Bool("p", false, "") 29 u = flag.Bool("u", false, "") 30 g = flag.Bool("g", false, "") 31 Q = flag.Bool("Q", false, "") 32 D = flag.Bool("D", false, "") 33 inodes = flag.Bool("inodes", false, "") 34 device = flag.Bool("device", false, "") 35 // Sort 36 U = flag.Bool("U", false, "") 37 v = flag.Bool("v", false, "") 38 t = flag.Bool("t", false, "") 39 c = flag.Bool("c", false, "") 40 r = flag.Bool("r", false, "") 41 dirsfirst = flag.Bool("dirsfirst", false, "") 42 sort = flag.String("sort", "", "") 43 // Graphics 44 i = flag.Bool("i", false, "") 45 C = flag.Bool("C", false, "") 46) 47 48var usage = `Usage: tree [options...] [paths...] 49 50Options: 51 ------- Listing options ------- 52 -a All files are listed. 53 -d List directories only. 54 -l Follow symbolic links like directories. 55 -f Print the full path prefix for each file. 56 -L Descend only level directories deep. 57 -P List only those files that match the pattern given. 58 -I Do not list files that match the given pattern. 59 --ignore-case Ignore case when pattern matching. 60 --noreport Turn off file/directory count at end of tree listing. 61 -o filename Output to file instead of stdout. 62 -------- File options --------- 63 -Q Quote filenames with double quotes. 64 -p Print the protections for each file. 65 -u Displays file owner or UID number. 66 -g Displays file group owner or GID number. 67 -s Print the size in bytes of each file. 68 -h Print the size in a more human readable way. 69 -D Print the date of last modification or (-c) status change. 70 --inodes Print inode number of each file. 71 --device Print device ID number to which each file belongs. 72 ------- Sorting options ------- 73 -v Sort files alphanumerically by version. 74 -t Sort files by last modification time. 75 -c Sort files by last status change time. 76 -U Leave files unsorted. 77 -r Reverse the order of the sort. 78 --dirsfirst List directories before files (-U disables). 79 --sort X Select sort: name,version,size,mtime,ctime. 80 ------- Graphics options ------ 81 -i Don't print indentation lines. 82 -C Turn colorization on always. 83` 84 85func main() { 86 flag.Usage = func() { fmt.Fprint(os.Stderr, usage) } 87 var nd, nf int 88 var dirs = []string{"."} 89 flag.Parse() 90 // Make it work with leading dirs 91 if args := flag.Args(); len(args) > 0 { 92 dirs = args 93 } 94 // Output file 95 var outFile = os.Stdout 96 var err error 97 if *o != "" { 98 outFile, err = os.Create(*o) 99 if err != nil { 100 errAndExit(err) 101 } 102 } 103 defer outFile.Close() 104 // Check sort-type 105 if *sort != "" { 106 switch *sort { 107 case "version", "mtime", "ctime", "name", "size": 108 default: 109 msg := fmt.Sprintf("sort type '%s' not valid, should be one of: "+ 110 "name,version,size,mtime,ctime", *sort) 111 errAndExit(errors.New(msg)) 112 } 113 } 114 // Set options 115 opts := &tree.Options{ 116 // Required 117 Fs: new(ostree.FS), 118 OutFile: outFile, 119 // List 120 All: *a, 121 DirsOnly: *d, 122 FullPath: *f, 123 DeepLevel: *L, 124 FollowLink: *l, 125 Pattern: *P, 126 IPattern: *I, 127 IgnoreCase: *ignorecase, 128 // Files 129 ByteSize: *s, 130 UnitSize: *h, 131 FileMode: *p, 132 ShowUid: *u, 133 ShowGid: *g, 134 LastMod: *D, 135 Quotes: *Q, 136 Inodes: *inodes, 137 Device: *device, 138 // Sort 139 NoSort: *U, 140 ReverSort: *r, 141 DirSort: *dirsfirst, 142 VerSort: *v || *sort == "version", 143 ModSort: *t || *sort == "mtime", 144 CTimeSort: *c || *sort == "ctime", 145 NameSort: *sort == "name", 146 SizeSort: *sort == "size", 147 // Graphics 148 NoIndent: *i, 149 Colorize: *C, 150 } 151 for _, dir := range dirs { 152 inf := tree.New(dir) 153 d, f := inf.Visit(opts) 154 nd, nf = nd+d, nf+f 155 inf.Print(opts) 156 } 157 // Print footer report 158 if !*noreport { 159 footer := fmt.Sprintf("\n%d directories", nd) 160 if !opts.DirsOnly { 161 footer += fmt.Sprintf(", %d files", nf) 162 } 163 fmt.Fprintln(outFile, footer) 164 } 165} 166 167func usageAndExit(msg string) { 168 if msg != "" { 169 fmt.Fprintf(os.Stderr, msg) 170 fmt.Fprintf(os.Stderr, "\n\n") 171 } 172 flag.Usage() 173 fmt.Fprintf(os.Stderr, "\n") 174 os.Exit(1) 175} 176 177func errAndExit(err error) { 178 fmt.Fprintf(os.Stderr, "tree: \"%s\"\n", err) 179 os.Exit(1) 180} 181