// Main sends on up when it's running, and shuts down when it receives from down. func Main(up chan<- struct{}, down <-chan struct{}) { flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "camlistored version: %s\nGo version: %s (%s/%s)\n", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) return } if legalprint.MaybePrint(os.Stderr) { return } if env.OnGCE() { log.SetOutput(gce.LogWriter()) } if *flagReindex { index.SetImpendingReindex() } log.Printf("Starting camlistored version %s; Go %s (%s/%s)", buildinfo.Version(), runtime.Version(), runtime.GOOS, runtime.GOARCH) shutdownc := make(chan io.Closer, 1) // receives io.Closer to cleanly shut down go handleSignals(shutdownc) // In case we're running in a Docker container with no // filesytem from which to load the root CAs, this // conditionally installs a static set if necessary. We do // this before we load the config file, which might come from // an https URL. httputil.InstallCerts() config, isNewConfig, err := loadConfig(*flagConfigFile) if err != nil { exitf("Error loading config file: %v", err) } ws := webserver.New() listen, baseURL := listenAndBaseURL(config) hostname, err := certHostname(listen, baseURL) if err != nil { exitf("Bad baseURL or listen address: %v", err) } setupTLS(ws, config, hostname) err = ws.Listen(listen) if err != nil { exitf("Listen: %v", err) } if baseURL == "" { baseURL = ws.ListenURL() } shutdownCloser, err := config.InstallHandlers(ws, baseURL, *flagReindex, nil) if err != nil { exitf("Error parsing config: %v", err) } shutdownc <- shutdownCloser urlToOpen := baseURL if !isNewConfig { // user may like to configure the server at the initial startup, // open UI if this is not the first run with a new config file. urlToOpen += config.UIPath } if *flagOpenBrowser { go osutil.OpenURL(urlToOpen) } go ws.Serve() if flagPollParent { osutil.DieOnParentDeath() } if err := config.StartApps(); err != nil { exitf("StartApps: %v", err) } for appName, appURL := range config.AppURL() { addr, err := netutil.HostPort(appURL) if err != nil { log.Printf("Could not get app %v address: %v", appName, err) continue } if err := netutil.AwaitReachable(addr, 5*time.Second); err != nil { log.Printf("Could not reach app %v: %v", appName, err) } } log.Printf("Available on %s", urlToOpen) if env.OnGCE() && strings.HasPrefix(baseURL, "https://") { go redirectFromHTTP(baseURL) } // Block forever, except during tests. up <- struct{}{} <-down osExit(0) }
func main() { client.AddFlags() flag.Parse() if *flagVersion { fmt.Fprintf(os.Stderr, "camget version: %s\n", buildinfo.Version()) return } if legalprint.MaybePrint(os.Stderr) { return } if *flagGraph && flag.NArg() != 1 { log.Fatalf("The --graph option requires exactly one parameter.") } var cl *client.Client var items []blob.Ref if *flagShared != "" { if client.ExplicitServer() != "" { log.Fatal("Can't use --shared with an explicit blobserver; blobserver is implicit from the --shared URL.") } if flag.NArg() != 0 { log.Fatal("No arguments permitted when using --shared") } cl1, target, err := client.NewFromShareRoot(*flagShared, client.OptionInsecure(*flagInsecureTLS), client.OptionTrustedCert(*flagTrustedCert)) if err != nil { log.Fatal(err) } cl = cl1 items = append(items, target) } else { if *flagTrustedCert != "" { log.Fatal("Can't use --cert without --shared.") } cl = client.NewOrFail() for n := 0; n < flag.NArg(); n++ { arg := flag.Arg(n) br, ok := blob.Parse(arg) if !ok { log.Fatalf("Failed to parse argument %q as a blobref.", arg) } items = append(items, br) } } cl.InsecureTLS = *flagInsecureTLS tr := cl.TransportForConfig(&client.TransportConfig{ Verbose: *flagHTTP, }) httpStats, _ := tr.(*httputil.StatsTransport) cl.SetHTTPClient(&http.Client{Transport: tr}) diskCacheFetcher, err := cacher.NewDiskCache(cl) if err != nil { log.Fatalf("Error setting up local disk cache: %v", err) } defer diskCacheFetcher.Clean() if *flagVerbose { log.Printf("Using temp blob cache directory %s", diskCacheFetcher.Root) } for _, br := range items { if *flagGraph { printGraph(diskCacheFetcher, br) return } if *flagCheck { // TODO: do HEAD requests checking if the blobs exists. log.Fatal("not implemented") return } if *flagOutput == "-" { var rc io.ReadCloser var err error if *flagContents { rc, err = schema.NewFileReader(diskCacheFetcher, br) if err == nil { rc.(*schema.FileReader).LoadAllChunks() } } else { rc, err = fetch(diskCacheFetcher, br) } if err != nil { log.Fatal(err) } defer rc.Close() if _, err := io.Copy(os.Stdout, rc); err != nil { log.Fatalf("Failed reading %q: %v", br, err) } } else { if err := smartFetch(diskCacheFetcher, *flagOutput, br); err != nil { log.Fatal(err) } } } if *flagVerbose { log.Printf("HTTP requests: %d\n", httpStats.Requests()) } }
// Main is meant to be the core of a command that has // subcommands (modes), such as camput or camtool. func Main() { registerFlagOnce.Do(ExtraFlagRegistration) if setCommandLineOutput != nil { setCommandLineOutput(Stderr) } flag.Parse() CheckCwd() if err := CheckModtime(); err != nil { log.Print(err) Exit(1) } args := flag.Args() if *FlagVersion { fmt.Fprintf(Stderr, "%s version: %s\n", os.Args[0], buildinfo.Version()) return } if *FlagHelp { usage("") } if legalprint.MaybePrint(Stderr) { return } if len(args) == 0 { usage("No mode given.") } mode := args[0] cmd, ok := modeCommand[mode] if !ok { usage(fmt.Sprintf("Unknown mode %q", mode)) } cmdFlags := modeFlags[mode] cmdFlags.SetOutput(Stderr) err := cmdFlags.Parse(args[1:]) if err != nil { err = ErrUsage } else { if *wantHelp[mode] { help(mode) return } err = cmd.RunCommand(cmdFlags.Args()) } if ue, isUsage := err.(UsageError); isUsage { if isUsage { Errorf("%s\n", ue) } cmd.Usage() Errorf("\nGlobal options:\n") flag.PrintDefaults() if hasFlags(cmdFlags) { Errorf("\nMode-specific options for mode %q:\n", mode) cmdFlags.PrintDefaults() } Exit(1) } PreExit() if err != nil { if !ExitWithFailure { // because it was already logged if ExitWithFailure Errorf("Error: %v\n", err) } Exit(2) } }
func main() { var conn *fuse.Conn // Scans the arg list and sets up flags client.AddFlags() flag.Usage = usage flag.Parse() if legalprint.MaybePrint(os.Stderr) { return } 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, fuse.VolumeName(filepath.Base(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) // check if the mount process has an error to report <-conn.Ready if err := conn.MountError; err != nil { log.Printf("conn.MountError: %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.") }