func main() { var conn *fuse.Conn // Scans the arg list and sets up flags client.AddFlags() flag.Usage = usage flag.Parse() narg := flag.NArg() if narg > 2 { usage() } var mountPoint string var err error if narg > 0 { mountPoint = flag.Arg(0) } else { mountPoint, err = ioutil.TempDir("", "cammount") if err != nil { log.Fatal(err) } log.Printf("No mount point given. Using: %s", mountPoint) defer os.Remove(mountPoint) } errorf := func(msg string, args ...interface{}) { fmt.Fprintf(os.Stderr, msg, args...) fmt.Fprint(os.Stderr, "\n") usage() } var ( cl *client.Client root blob.Ref // nil if only one arg camfs *fs.CamliFileSystem ) if narg == 2 { rootArg := flag.Arg(1) // not trying very hard since NewFromShareRoot will do it better with a regex if strings.HasPrefix(rootArg, "http://") || strings.HasPrefix(rootArg, "https://") { if client.ExplicitServer() != "" { errorf("Can't use an explicit blobserver with a share URL; the blobserver is implicit from the share URL.") } var err error cl, root, err = client.NewFromShareRoot(rootArg) if err != nil { log.Fatal(err) } } else { cl = client.NewOrFail() // automatic from flags cl.SetHTTPClient(&http.Client{Transport: cl.TransportForConfig(nil)}) var ok bool root, ok = blob.Parse(rootArg) if !ok { // not a blobref, check for root name instead req := &search.WithAttrRequest{N: 1, Attr: "camliRoot", Value: rootArg} wres, err := cl.GetPermanodesWithAttr(req) if err != nil { log.Fatal("could not query search") } if wres.WithAttr != nil { root = wres.WithAttr[0].Permanode } else { log.Fatalf("root specified is not a blobref or name of a root: %q\n", rootArg) } } } } else { cl = client.NewOrFail() // automatic from flags cl.SetHTTPClient(&http.Client{Transport: cl.TransportForConfig(nil)}) } diskCacheFetcher, err := cacher.NewDiskCache(cl) if err != nil { log.Fatalf("Error setting up local disk cache: %v", err) } defer diskCacheFetcher.Clean() if root.Valid() { var err error camfs, err = fs.NewRootedCamliFileSystem(cl, diskCacheFetcher, root) if err != nil { log.Fatalf("Error creating root with %v: %v", root, err) } } else { camfs = fs.NewDefaultCamliFileSystem(cl, diskCacheFetcher) } if *debug { fuse.Debugf = log.Printf // TODO: set fs's logger } // This doesn't appear to work on OS X: sigc := make(chan os.Signal, 1) conn, err = fuse.Mount(mountPoint) if err != nil { if err.Error() == "cannot find load_fusefs" && runtime.GOOS == "darwin" { log.Fatal("FUSE not available; install from http://osxfuse.github.io/") } log.Fatalf("Mount: %v", err) } xtermDone := make(chan bool, 1) if *xterm { cmd := exec.Command("xterm") cmd.Dir = mountPoint if err := cmd.Start(); err != nil { log.Printf("Error starting xterm: %v", err) } else { go func() { cmd.Wait() xtermDone <- true }() defer cmd.Process.Kill() } } if *open { if runtime.GOOS == "darwin" { cmd := exec.Command("open", mountPoint) go cmd.Run() } } signal.Notify(sigc, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) doneServe := make(chan error, 1) go func() { doneServe <- conn.Serve(camfs) }() quitKey := make(chan bool, 1) go awaitQuitKey(quitKey) select { case err := <-doneServe: log.Printf("conn.Serve returned %v", err) case sig := <-sigc: log.Printf("Signal %s received, shutting down.", sig) case <-quitKey: log.Printf("Quit key pressed. Shutting down.") case <-xtermDone: log.Printf("xterm done") } time.AfterFunc(2*time.Second, func() { os.Exit(1) }) log.Printf("Unmounting...") err = fs.Unmount(mountPoint) log.Printf("Unmount = %v", err) log.Printf("cammount FUSE process ending.") }