go-hep.org/x/hep@v0.38.1/xrootd/cmd/xrd-ls/main.go (about) 1 // Copyright ©2018 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Command xrd-ls lists directory contents on a remote xrootd server. 6 // 7 // Usage: 8 // 9 // $> xrd-ls [OPTIONS] <dir-1> [<dir-2> [...]] 10 // 11 // Example: 12 // 13 // $> xrd-ls root://server.example.com/some/dir 14 // $> xrd-ls -l root://server.example.com/some/dir 15 // $> xrd-ls -R root://server.example.com/some/dir 16 // $> xrd-ls -l -R root://server.example.com/some/dir 17 // 18 // Options: 19 // 20 // -R list subdirectories recursively 21 // -l use a long listing format 22 package main 23 24 import ( 25 "context" 26 "flag" 27 "fmt" 28 "io" 29 "log" 30 "os" 31 "path" 32 "text/tabwriter" 33 34 "go-hep.org/x/hep/xrootd" 35 "go-hep.org/x/hep/xrootd/xrdfs" 36 "go-hep.org/x/hep/xrootd/xrdio" 37 ) 38 39 func init() { 40 flag.Usage = func() { 41 fmt.Fprintf(os.Stderr, `xrd-ls lists directory contents on a remote xrootd server. 42 43 Usage: 44 45 $> xrd-ls [OPTIONS] <dir-1> [<dir-2> [...]] 46 47 Example: 48 49 $> xrd-ls root://server.example.com/some/dir 50 $> xrd-ls -l root://server.example.com/some/dir 51 $> xrd-ls -R root://server.example.com/some/dir 52 $> xrd-ls -l -R root://server.example.com/some/dir 53 54 Options: 55 `) 56 flag.PrintDefaults() 57 } 58 } 59 60 func main() { 61 log.SetPrefix("xrd-ls: ") 62 log.SetFlags(0) 63 64 var ( 65 recFlag = flag.Bool("R", false, "list subdirectories recursively") 66 longFlag = flag.Bool("l", false, "use a long listing format") 67 ) 68 69 flag.Parse() 70 71 if flag.NArg() == 0 { 72 flag.Usage() 73 log.Fatalf("missing directory operand") 74 } 75 76 for i, dir := range flag.Args() { 77 if i > 0 { 78 // separate consecutive files by an empty line 79 fmt.Printf("\n") 80 } 81 err := xrdls(dir, *longFlag, *recFlag) 82 if err != nil { 83 log.Fatalf("could not list %q content: %+v", dir, err) 84 } 85 } 86 } 87 88 func xrdls(name string, long, recursive bool) error { 89 url, err := xrdio.Parse(name) 90 if err != nil { 91 return fmt.Errorf("could not parse %q: %w", name, err) 92 } 93 94 ctx := context.Background() 95 96 c, err := xrootd.NewClient(ctx, url.Addr, url.User) 97 if err != nil { 98 return fmt.Errorf("could not create client: %w", err) 99 } 100 defer c.Close() 101 102 fs := c.FS() 103 104 fi, err := fs.Stat(ctx, url.Path) 105 // TODO fi.Name() here is an empty string (see handling in format() below) 106 if err != nil { 107 return fmt.Errorf("could not stat %q: %w", url.Path, err) 108 } 109 err = display(ctx, fs, url.Path, fi, long, recursive) 110 if err != nil { 111 return err 112 } 113 114 return nil 115 } 116 117 func display(ctx context.Context, fs xrdfs.FileSystem, root string, fi os.FileInfo, long, recursive bool) error { 118 if !fi.IsDir() { 119 // TODO fi.Name() here is an empty string (see handling in format() below) 120 format(os.Stdout, root, fi, long) 121 return nil 122 } 123 124 end := "" 125 if recursive { 126 end = ":" 127 } 128 129 dir := path.Join(root, fi.Name()) 130 fmt.Printf("%s%s\n", dir, end) 131 if long { 132 fmt.Printf("total %d\n", fi.Size()) 133 } 134 ents, err := fs.Dirlist(ctx, dir) 135 if err != nil { 136 return fmt.Errorf("could not list dir %q: %w", dir, err) 137 } 138 o := tabwriter.NewWriter(os.Stdout, 8, 4, 0, ' ', tabwriter.AlignRight) 139 for _, e := range ents { 140 format(o, dir, e, long) 141 } 142 o.Flush() 143 if recursive { 144 for _, e := range ents { 145 if !e.IsDir() { 146 continue 147 } 148 // make an empty line before going into a subdirectory. 149 fmt.Printf("\n") 150 err := display(ctx, fs, dir, e, long, recursive) 151 if err != nil { 152 return err 153 } 154 } 155 } 156 157 return nil 158 } 159 160 func format(o io.Writer, root string, fi os.FileInfo, long bool) { 161 if !long { 162 fmt.Fprintf(o, "%s\n", path.Join(root, fi.Name())) 163 return 164 } 165 166 name := fi.Name() 167 if name == "" { 168 name = root 169 } 170 fmt.Fprintf(o, "%v\t %d\t %s\t %s\n", fi.Mode(), fi.Size(), fi.ModTime().Format("Jan 02 15:04"), name) 171 }