diff --git a/cmd/bench.go b/cmd/bench.go index 96329ac55d1e..479034947ff0 100644 --- a/cmd/bench.go +++ b/cmd/bench.go @@ -298,15 +298,11 @@ func (bm *benchmark) printResult(result [][3]string) { } func bench(ctx *cli.Context) error { - setLoggerLevel(ctx) - + setup(ctx, 1) /* --- Pre-check --- */ if ctx.Uint("block-size") == 0 || ctx.Uint("threads") == 0 { return os.ErrInvalid } - if ctx.NArg() < 1 { - logger.Fatalln("PATH must be provided") - } tmpdir, err := filepath.Abs(ctx.Args().First()) if err != nil { logger.Fatalf("Failed to get absolute path of %s: %s", ctx.Args().First(), err) diff --git a/cmd/config.go b/cmd/config.go index 1f94739aaaf1..c16c84ab2909 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -108,10 +108,7 @@ func userConfirmed() bool { } func config(ctx *cli.Context) error { - setLoggerLevel(ctx) - if ctx.Args().Len() < 1 { - return fmt.Errorf("META-URL is needed") - } + setup(ctx, 1) removePassword(ctx.Args().Get(0)) m := meta.NewClient(ctx.Args().Get(0), &meta.Config{Retries: 10, Strict: true}) diff --git a/cmd/destroy.go b/cmd/destroy.go index 42efa0841bff..cf3ce4a63fbe 100644 --- a/cmd/destroy.go +++ b/cmd/destroy.go @@ -103,10 +103,7 @@ func printSessions(ss [][3]string) string { } func destroy(ctx *cli.Context) error { - setLoggerLevel(ctx) - if ctx.Args().Len() < 2 { - return fmt.Errorf("META-URL and UUID are required") - } + setup(ctx, 2) uri := ctx.Args().Get(0) if !strings.Contains(uri, "://") { uri = "redis://" + uri diff --git a/cmd/dump.go b/cmd/dump.go index 02194f1ad74f..69ba6253b95a 100644 --- a/cmd/dump.go +++ b/cmd/dump.go @@ -17,7 +17,6 @@ package main import ( - "fmt" "io" "os" @@ -54,10 +53,7 @@ Details: https://juicefs.com/docs/community/metadata_dump_load`, } func dump(ctx *cli.Context) error { - setLoggerLevel(ctx) - if ctx.Args().Len() < 1 { - return fmt.Errorf("META-URL is needed") - } + setup(ctx, 1) var fp io.WriteCloser if ctx.Args().Len() == 1 { fp = os.Stdout diff --git a/cmd/format.go b/cmd/format.go index d08bdf837b04..a29b43ebe068 100644 --- a/cmd/format.go +++ b/cmd/format.go @@ -271,16 +271,9 @@ func test(store object.ObjectStorage) error { } func format(c *cli.Context) error { - setLoggerLevel(c) - if c.Args().Len() < 1 { - logger.Fatalf("Meta URL and name are required") - } + setup(c, 2) removePassword(c.Args().Get(0)) m := meta.NewClient(c.Args().Get(0), &meta.Config{Retries: 2}) - - if c.Args().Len() < 2 { - logger.Fatalf("Please give it a name") - } name := c.Args().Get(1) validName := regexp.MustCompile(`^[a-z0-9][a-z0-9\-]{1,61}[a-z0-9]$`) if !validName.MatchString(name) { diff --git a/cmd/fsck.go b/cmd/fsck.go index fbde8d4a8382..903018e3cc54 100644 --- a/cmd/fsck.go +++ b/cmd/fsck.go @@ -48,10 +48,7 @@ $ juicefs fsck redis://localhost`, } func fsck(ctx *cli.Context) error { - setLoggerLevel(ctx) - if ctx.Args().Len() < 1 { - return fmt.Errorf("META-URL is needed") - } + setup(ctx, 1) removePassword(ctx.Args().Get(0)) m := meta.NewClient(ctx.Args().Get(0), &meta.Config{Retries: 10, Strict: true}) format, err := m.Load(true) diff --git a/cmd/gateway.go b/cmd/gateway.go index a40f2bb85805..1e0e7d00dd06 100644 --- a/cmd/gateway.go +++ b/cmd/gateway.go @@ -85,12 +85,7 @@ Details: https://juicefs.com/docs/community/s3_gateway`, } func gateway(c *cli.Context) error { - setLoggerLevel(c) - - if c.Args().Len() < 2 { - logger.Fatalf("Meta URL and listen address are required") - } - + setup(c, 2) ak := os.Getenv("MINIO_ROOT_USER") if ak == "" { ak = os.Getenv("MINIO_ACCESS_KEY") diff --git a/cmd/gc.go b/cmd/gc.go index b5c9ec549a1f..228be256f386 100644 --- a/cmd/gc.go +++ b/cmd/gc.go @@ -17,7 +17,6 @@ package main import ( - "fmt" "os" "strconv" "strings" @@ -80,10 +79,7 @@ type dChunk struct { } func gc(ctx *cli.Context) error { - setLoggerLevel(ctx) - if ctx.Args().Len() < 1 { - return fmt.Errorf("META-URL is needed") - } + setup(ctx, 1) removePassword(ctx.Args().Get(0)) m := meta.NewClient(ctx.Args().Get(0), &meta.Config{ Retries: 10, diff --git a/cmd/info.go b/cmd/info.go index 13a33a62d5f9..d92cadc98aa9 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -62,14 +62,11 @@ $ juicefs info -i 100`, } func info(ctx *cli.Context) error { + setup(ctx, 1) if runtime.GOOS == "windows" { logger.Infof("Windows is not supported") return nil } - if ctx.Args().Len() < 1 { - logger.Infof("DIR or FILE is needed") - return nil - } var recursive uint8 if ctx.Bool("recursive") { recursive = 1 diff --git a/cmd/load.go b/cmd/load.go index 3038e47fcb32..a989fe09fdaa 100644 --- a/cmd/load.go +++ b/cmd/load.go @@ -17,7 +17,6 @@ package main import ( - "fmt" "io" "os" @@ -45,10 +44,7 @@ Details: https://juicefs.com/docs/community/metadata_dump_load`, } func load(ctx *cli.Context) error { - setLoggerLevel(ctx) - if ctx.Args().Len() < 1 { - return fmt.Errorf("META-URL is needed") - } + setup(ctx, 1) var fp io.ReadCloser if ctx.Args().Len() == 1 { fp = os.Stdin diff --git a/cmd/main.go b/cmd/main.go index fda35ac5c9a2..87c1cfc4743f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -236,22 +236,14 @@ func reorderOptions(app *cli.App, args []string) []string { return append(newArgs, others...) } -func setupAgent(c *cli.Context) { - if !c.Bool("no-agent") { - go func() { - for port := 6060; port < 6100; port++ { - _ = http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", port), nil) - } - }() - go func() { - for port := 6070; port < 6100; port++ { - _ = agent.Listen(agent.Options{Addr: fmt.Sprintf("127.0.0.1:%d", port)}) - } - }() +// Check number of positional arguments, set logger level and setup agent if needed +func setup(c *cli.Context, n int) { + if c.NArg() < n { + logger.Errorf("This command requires at lease %d arguments", n) + fmt.Printf("USAGE:\n juicefs %s [command options] %s\n", c.Command.Name, c.Command.ArgsUsage) + os.Exit(1) } -} -func setLoggerLevel(c *cli.Context) { if c.Bool("trace") { utils.SetLogLevel(logrus.TraceLevel) } else if c.Bool("verbose") { @@ -264,7 +256,19 @@ func setLoggerLevel(c *cli.Context) { if c.Bool("no-color") { utils.DisableLogColor() } - setupAgent(c) + + if !c.Bool("no-agent") { + go func() { + for port := 6060; port < 6100; port++ { + _ = http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", port), nil) + } + }() + go func() { + for port := 6070; port < 6100; port++ { + _ = agent.Listen(agent.Options{Addr: fmt.Sprintf("127.0.0.1:%d", port)}) + } + }() + } } func removePassword(uri string) { diff --git a/cmd/mount.go b/cmd/mount.go index 0850644cacc4..1e51f5596271 100644 --- a/cmd/mount.go +++ b/cmd/mount.go @@ -317,14 +317,8 @@ func initBackgroundTasks(c *cli.Context, vfsConf *vfs.Config, metaConf *meta.Con } func mount(c *cli.Context) error { - setLoggerLevel(c) - if c.Args().Len() < 1 { - logger.Fatalf("Meta URL and mountpoint are required") - } + setup(c, 2) addr := c.Args().Get(0) - if c.Args().Len() < 2 { - logger.Fatalf("MOUNTPOINT is required") - } mp := c.Args().Get(1) prepareMp(mp) diff --git a/cmd/profile.go b/cmd/profile.go index bc76bafd9d92..51f5c4a2e542 100644 --- a/cmd/profile.go +++ b/cmd/profile.go @@ -331,10 +331,7 @@ func (p *profiler) flusher() { } func profile(ctx *cli.Context) error { - setLoggerLevel(ctx) - if ctx.Args().Len() < 1 { - logger.Fatalln("Mount point or log file must be provided!") - } + setup(ctx, 1) logPath := ctx.Args().First() st, err := os.Stat(logPath) if err != nil { diff --git a/cmd/rmr.go b/cmd/rmr.go index ad48f243655b..04952cdb8095 100644 --- a/cmd/rmr.go +++ b/cmd/rmr.go @@ -57,14 +57,11 @@ func openController(path string) *os.File { } func rmr(ctx *cli.Context) error { + setup(ctx, 1) if runtime.GOOS == "windows" { logger.Infof("Windows is not supported") return nil } - if ctx.Args().Len() < 1 { - logger.Infof("PATH is needed") - return nil - } for i := 0; i < ctx.Args().Len(); i++ { path := ctx.Args().Get(i) p, err := filepath.Abs(path) diff --git a/cmd/stats.go b/cmd/stats.go index 200961ecb0d6..7631bf440499 100644 --- a/cmd/stats.go +++ b/cmd/stats.go @@ -366,10 +366,7 @@ func readStats(path string) map[string]float64 { } func stats(ctx *cli.Context) error { - setLoggerLevel(ctx) - if ctx.Args().Len() < 1 { - logger.Fatalln("mount point must be provided") - } + setup(ctx, 1) mp := ctx.Args().First() inode, err := utils.GetFileInode(mp) if err != nil { diff --git a/cmd/status.go b/cmd/status.go index 249baef80095..b87e06410f3c 100644 --- a/cmd/status.go +++ b/cmd/status.go @@ -62,10 +62,7 @@ func printJson(v interface{}) { } func status(ctx *cli.Context) error { - setLoggerLevel(ctx) - if ctx.Args().Len() < 1 { - return fmt.Errorf("META-URL is needed") - } + setup(ctx, 1) removePassword(ctx.Args().Get(0)) m := meta.NewClient(ctx.Args().Get(0), &meta.Config{Retries: 10, Strict: true}) format, err := m.Load(true) diff --git a/cmd/sync.go b/cmd/sync.go index 1dca9069f67f..17df631618be 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -44,6 +44,7 @@ func cmdSync() *cli.Command { ArgsUsage: "SRC DST", Description: ` This tool spawns multiple threads to concurrently syncs objects of two data storages. +SRC and DST should be [NAME://][ACCESS_KEY:SECRET_KEY@]BUCKET[.ENDPOINT][/PREFIX]. Examples: # Sync object from OSS to S3 @@ -278,16 +279,8 @@ func isS3PathType(endpoint string) bool { return regexp.MustCompile(pattern).MatchString(endpoint) } -const USAGE = `juicefs [options] sync [options] SRC DST -SRC and DST should be [NAME://][ACCESS_KEY:SECRET_KEY@]BUCKET[.ENDPOINT][/PREFIX]` - func doSync(c *cli.Context) error { - setLoggerLevel(c) - - if c.Args().Len() != 2 { - logger.Errorf(USAGE) - return nil - } + setup(c, 2) config := sync.NewConfigFromCli(c) go func() { _ = http.ListenAndServe(fmt.Sprintf("127.0.0.1:%d", config.HTTPPort), nil) }() diff --git a/cmd/umount.go b/cmd/umount.go index e3ae9c3b89c5..9893b30ae0ea 100644 --- a/cmd/umount.go +++ b/cmd/umount.go @@ -88,9 +88,7 @@ func doUmount(mp string, force bool) error { } func umount(ctx *cli.Context) error { - if ctx.Args().Len() < 1 { - return fmt.Errorf("MOUNTPOINT is needed") - } + setup(ctx, 1) mp := ctx.Args().Get(0) force := ctx.Bool("force") return doUmount(mp, force) diff --git a/cmd/warmup.go b/cmd/warmup.go index 0689af2b52f7..8d345f4c0619 100644 --- a/cmd/warmup.go +++ b/cmd/warmup.go @@ -102,6 +102,7 @@ func sendCommand(cf *os.File, batch []string, count int, threads uint, backgroun } func warmup(ctx *cli.Context) error { + setup(ctx, 0) fname := ctx.String("file") paths := ctx.Args().Slice() if fname != "" { diff --git a/cmd/webdav.go b/cmd/webdav.go index 4e85d0194aa0..f03f88e7bea0 100644 --- a/cmd/webdav.go +++ b/cmd/webdav.go @@ -61,14 +61,8 @@ $ juicefs webdav redis://localhost localhost:9007`, } func webdav(c *cli.Context) error { - setLoggerLevel(c) - if c.Args().Len() < 1 { - logger.Fatalf("meta url are required") - } + setup(c, 2) metaUrl := c.Args().Get(0) - if c.Args().Len() < 2 { - logger.Fatalf("listen address is required") - } listenAddr := c.Args().Get(1) m, store, conf := initForSvc(c, "webdav", metaUrl) jfs, err := fs.NewFileSystem(conf, m, store)