func srcRoot() string { for _, dir := range filepath.SplitList(os.Getenv("GOPATH")) { if d := filepath.Join(dir, "src", "camlistore.org"); osutil.DirExists(d) { return d } } return "" }
// NewDiskCache returns a new DiskCache from a Fetcher, which // is usually the pkg/client HTTP client (which typically has much // higher latency and lower bandwidth than local disk). func NewDiskCache(fetcher blob.Fetcher) (*DiskCache, error) { cacheDir := filepath.Join(osutil.CacheDir(), "blobs") if !osutil.DirExists(cacheDir) { if err := os.Mkdir(cacheDir, 0700); err != nil { log.Printf("Warning: failed to make %s: %v; using tempdir instead", cacheDir, err) cacheDir, err = ioutil.TempDir("", "camlicache") if err != nil { return nil, err } } } // TODO: max disk size, keep LRU of access, smarter cleaning, etc // TODO: use diskpacked instead? harder to clean, though. diskcache, err := localdisk.New(cacheDir) if err != nil { return nil, err } dc := &DiskCache{ CachingFetcher: NewCachingFetcher(diskcache, fetcher), Root: cacheDir, } return dc, nil }
// IsDir reports whether root is a localdisk (file-per-blob) storage directory. func IsDir(root string) (bool, error) { if osutil.DirExists(filepath.Join(root, blob.RefFromString("").HashName())) { return true, nil } return false, nil }
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.Debug = func(msg interface{}) { log.Print(msg) } // 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" { go exec.Command("open", mountPoint).Run() } } if *term { if runtime.GOOS == "darwin" { if osutil.DirExists("/Applications/iTerm.app/") { go exec.Command("open", "-a", "iTerm", mountPoint).Run() } else { log.Printf("TODO: iTerm not installed. Figure out how to open with Terminal.app instead.") } } } signal.Notify(sigc, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) doneServe := make(chan error, 1) go func() { doneServe <- fusefs.Serve(conn, 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.") }