github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/cmd/cammount/cammount.go (about) 1 // +build linux darwin 2 3 /* 4 Copyright 2011 Google Inc. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package main 20 21 import ( 22 "flag" 23 "fmt" 24 "io/ioutil" 25 "log" 26 "net/http" 27 "os" 28 "os/exec" 29 "os/signal" 30 "runtime" 31 "strings" 32 "syscall" 33 "time" 34 35 "camlistore.org/pkg/blob" 36 "camlistore.org/pkg/cacher" 37 "camlistore.org/pkg/client" 38 "camlistore.org/pkg/fs" 39 "camlistore.org/pkg/osutil" 40 "camlistore.org/pkg/search" 41 "camlistore.org/third_party/bazil.org/fuse" 42 fusefs "camlistore.org/third_party/bazil.org/fuse/fs" 43 ) 44 45 var ( 46 debug = flag.Bool("debug", false, "print debugging messages.") 47 xterm = flag.Bool("xterm", false, "Run an xterm in the mounted directory. Shut down when xterm ends.") 48 term = flag.Bool("term", false, "Open a terminal window. Doesn't shut down when exited. Mostly for demos.") 49 open = flag.Bool("open", false, "Open a GUI window") 50 ) 51 52 func usage() { 53 fmt.Fprint(os.Stderr, "usage: cammount [opts] [<mountpoint> [<root-blobref>|<share URL>|<root-name>]]\n") 54 flag.PrintDefaults() 55 os.Exit(2) 56 } 57 58 func main() { 59 var conn *fuse.Conn 60 61 // Scans the arg list and sets up flags 62 client.AddFlags() 63 flag.Usage = usage 64 flag.Parse() 65 66 narg := flag.NArg() 67 if narg > 2 { 68 usage() 69 } 70 71 var mountPoint string 72 var err error 73 if narg > 0 { 74 mountPoint = flag.Arg(0) 75 } else { 76 mountPoint, err = ioutil.TempDir("", "cammount") 77 if err != nil { 78 log.Fatal(err) 79 } 80 log.Printf("No mount point given. Using: %s", mountPoint) 81 defer os.Remove(mountPoint) 82 } 83 84 errorf := func(msg string, args ...interface{}) { 85 fmt.Fprintf(os.Stderr, msg, args...) 86 fmt.Fprint(os.Stderr, "\n") 87 usage() 88 } 89 90 var ( 91 cl *client.Client 92 root blob.Ref // nil if only one arg 93 camfs *fs.CamliFileSystem 94 ) 95 if narg == 2 { 96 rootArg := flag.Arg(1) 97 // not trying very hard since NewFromShareRoot will do it better with a regex 98 if strings.HasPrefix(rootArg, "http://") || 99 strings.HasPrefix(rootArg, "https://") { 100 if client.ExplicitServer() != "" { 101 errorf("Can't use an explicit blobserver with a share URL; the blobserver is implicit from the share URL.") 102 } 103 var err error 104 cl, root, err = client.NewFromShareRoot(rootArg) 105 if err != nil { 106 log.Fatal(err) 107 } 108 } else { 109 cl = client.NewOrFail() // automatic from flags 110 cl.SetHTTPClient(&http.Client{Transport: cl.TransportForConfig(nil)}) 111 112 var ok bool 113 root, ok = blob.Parse(rootArg) 114 115 if !ok { 116 // not a blobref, check for root name instead 117 req := &search.WithAttrRequest{N: 1, Attr: "camliRoot", Value: rootArg} 118 wres, err := cl.GetPermanodesWithAttr(req) 119 120 if err != nil { 121 log.Fatal("could not query search") 122 } 123 124 if wres.WithAttr != nil { 125 root = wres.WithAttr[0].Permanode 126 } else { 127 log.Fatalf("root specified is not a blobref or name of a root: %q\n", rootArg) 128 } 129 } 130 } 131 } else { 132 cl = client.NewOrFail() // automatic from flags 133 cl.SetHTTPClient(&http.Client{Transport: cl.TransportForConfig(nil)}) 134 } 135 136 diskCacheFetcher, err := cacher.NewDiskCache(cl) 137 if err != nil { 138 log.Fatalf("Error setting up local disk cache: %v", err) 139 } 140 defer diskCacheFetcher.Clean() 141 if root.Valid() { 142 var err error 143 camfs, err = fs.NewRootedCamliFileSystem(cl, diskCacheFetcher, root) 144 if err != nil { 145 log.Fatalf("Error creating root with %v: %v", root, err) 146 } 147 } else { 148 camfs = fs.NewDefaultCamliFileSystem(cl, diskCacheFetcher) 149 } 150 151 if *debug { 152 fuse.Debug = func(msg interface{}) { log.Print(msg) } 153 // TODO: set fs's logger 154 } 155 156 // This doesn't appear to work on OS X: 157 sigc := make(chan os.Signal, 1) 158 159 conn, err = fuse.Mount(mountPoint) 160 if err != nil { 161 if err.Error() == "cannot find load_fusefs" && runtime.GOOS == "darwin" { 162 log.Fatal("FUSE not available; install from http://osxfuse.github.io/") 163 } 164 log.Fatalf("Mount: %v", err) 165 } 166 167 xtermDone := make(chan bool, 1) 168 if *xterm { 169 cmd := exec.Command("xterm") 170 cmd.Dir = mountPoint 171 if err := cmd.Start(); err != nil { 172 log.Printf("Error starting xterm: %v", err) 173 } else { 174 go func() { 175 cmd.Wait() 176 xtermDone <- true 177 }() 178 defer cmd.Process.Kill() 179 } 180 } 181 if *open { 182 if runtime.GOOS == "darwin" { 183 go exec.Command("open", mountPoint).Run() 184 } 185 } 186 if *term { 187 if runtime.GOOS == "darwin" { 188 if osutil.DirExists("/Applications/iTerm.app/") { 189 go exec.Command("open", "-a", "iTerm", mountPoint).Run() 190 } else { 191 log.Printf("TODO: iTerm not installed. Figure out how to open with Terminal.app instead.") 192 } 193 } 194 } 195 196 signal.Notify(sigc, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) 197 198 doneServe := make(chan error, 1) 199 go func() { 200 doneServe <- fusefs.Serve(conn, camfs) 201 }() 202 203 quitKey := make(chan bool, 1) 204 go awaitQuitKey(quitKey) 205 206 select { 207 case err := <-doneServe: 208 log.Printf("conn.Serve returned %v", err) 209 case sig := <-sigc: 210 log.Printf("Signal %s received, shutting down.", sig) 211 case <-quitKey: 212 log.Printf("Quit key pressed. Shutting down.") 213 case <-xtermDone: 214 log.Printf("xterm done") 215 } 216 217 time.AfterFunc(2*time.Second, func() { 218 os.Exit(1) 219 }) 220 log.Printf("Unmounting...") 221 err = fs.Unmount(mountPoint) 222 log.Printf("Unmount = %v", err) 223 224 log.Printf("cammount FUSE process ending.") 225 } 226 227 func awaitQuitKey(done chan<- bool) { 228 var buf [1]byte 229 for { 230 _, err := os.Stdin.Read(buf[:]) 231 if err != nil { 232 return 233 } 234 if buf[0] == 'q' { 235 done <- true 236 return 237 } 238 } 239 }