minio/cmd/main.go

219 lines
6.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package cmd
import (
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"runtime/debug"
"sort"
"strings"
"github.com/minio/cli"
"github.com/minio/minio/internal/color"
"github.com/minio/minio/internal/logger"
"github.com/minio/pkg/v2/console"
"github.com/minio/pkg/v2/env"
"github.com/minio/pkg/v2/trie"
"github.com/minio/pkg/v2/words"
)
// GlobalFlags - global flags for minio.
var GlobalFlags = []cli.Flag{
// Deprecated flag, so its hidden now - existing deployments will keep working.
cli.StringFlag{
Name: "config-dir, C",
Value: defaultConfigDir.Get(),
Usage: "[DEPRECATED] path to legacy configuration directory",
Hidden: true,
},
cli.StringFlag{
Name: "certs-dir, S",
Value: defaultCertsDir.Get(),
Usage: "path to certs directory",
},
cli.BoolFlag{
Name: "quiet",
Usage: "disable startup and info messages",
},
cli.BoolFlag{
Name: "anonymous",
Usage: "hide sensitive information from logging",
},
cli.BoolFlag{
Name: "json",
Usage: "output logs in JSON format",
},
// Deprecated flag, so its hidden now, existing deployments will keep working.
cli.BoolFlag{
Name: "compat",
Usage: "enable strict S3 compatibility by turning off certain performance optimizations",
Hidden: true,
},
// This flag is hidden and to be used only during certain performance testing.
cli.BoolFlag{
Name: "no-compat",
Usage: "disable strict S3 compatibility by turning on certain performance optimizations",
Hidden: true,
},
}
// Help template for minio.
var minioHelpTemplate = `NAME:
{{.Name}} - {{.Usage}}
DESCRIPTION:
{{.Description}}
USAGE:
{{.HelpName}} {{if .VisibleFlags}}[FLAGS] {{end}}COMMAND{{if .VisibleFlags}}{{end}} [ARGS...]
COMMANDS:
{{range .VisibleCommands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{if .VisibleFlags}}
FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}{{end}}
VERSION:
{{.Version}}
`
func newApp(name string) *cli.App {
// Collection of minio commands currently supported are.
commands := []cli.Command{}
// Collection of minio commands currently supported in a trie tree.
commandsTree := trie.NewTrie()
// registerCommand registers a cli command.
registerCommand := func(command cli.Command) {
commands = append(commands, command)
commandsTree.Insert(command.Name)
}
findClosestCommands := func(command string) []string {
var closestCommands []string
closestCommands = append(closestCommands, commandsTree.PrefixMatch(command)...)
sort.Strings(closestCommands)
// Suggest other close commands - allow missed, wrongly added and
// even transposed characters
for _, value := range commandsTree.Walk(commandsTree.Root()) {
if sort.SearchStrings(closestCommands, value) < len(closestCommands) {
continue
}
// 2 is arbitrary and represents the max
// allowed number of typed errors
if words.DamerauLevenshteinDistance(command, value) < 2 {
closestCommands = append(closestCommands, value)
}
}
return closestCommands
}
// Register all commands.
registerCommand(serverCmd)
registerCommand(gatewayCmd) // hidden kept for guiding users.
// Set up app.
cli.HelpFlag = cli.BoolFlag{
Name: "help, h",
Usage: "show help",
}
cli.VersionPrinter = printMinIOVersion
app := cli.NewApp()
app.Name = name
app.Author = "MinIO, Inc."
app.Version = ReleaseTag
app.Usage = "High Performance Object Storage"
app.Description = `Build high performance data infrastructure for machine learning, analytics and application data workloads with MinIO`
app.Flags = GlobalFlags
app.HideHelpCommand = true // Hide `help, h` command, we already have `minio --help`.
app.Commands = commands
app.CustomAppHelpTemplate = minioHelpTemplate
app.CommandNotFound = func(ctx *cli.Context, command string) {
console.Printf("%s is not a minio sub-command. See minio --help.\n", command)
closestCommands := findClosestCommands(command)
if len(closestCommands) > 0 {
console.Println()
console.Println("Did you mean one of these?")
for _, cmd := range closestCommands {
console.Printf("\t%s\n", cmd)
}
}
os.Exit(1)
}
return app
}
func startupBanner(banner io.Writer) {
fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", CopyrightYear))
fmt.Fprintln(banner, color.Blue("License:")+color.Bold(" GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>"))
fmt.Fprintln(banner, color.Blue("Version:")+color.Bold(" %s (%s %s/%s)", ReleaseTag, runtime.Version(), runtime.GOOS, runtime.GOARCH))
}
func versionBanner(c *cli.Context) io.Reader {
banner := &strings.Builder{}
fmt.Fprintln(banner, color.Bold("%s version %s (commit-id=%s)", c.App.Name, c.App.Version, CommitID))
fmt.Fprintln(banner, color.Blue("Runtime:")+color.Bold(" %s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH))
fmt.Fprintln(banner, color.Blue("License:")+color.Bold(" GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>"))
fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", CopyrightYear))
return strings.NewReader(banner.String())
}
func printMinIOVersion(c *cli.Context) {
io.Copy(c.App.Writer, versionBanner(c))
}
// Main main for minio server.
func Main(args []string) {
// Set the minio app name.
appName := filepath.Base(args[0])
if env.Get("_MINIO_DEBUG_NO_EXIT", "") != "" {
freeze := func(_ int) {
// Infinite blocking op
<-make(chan struct{})
}
// Override the logger os.Exit()
logger.ExitFunc = freeze
defer func() {
if err := recover(); err != nil {
fmt.Println("panic:", err)
fmt.Println("")
fmt.Println(string(debug.Stack()))
}
freeze(-1)
}()
}
// Run the app - exit on error.
if err := newApp(appName).Run(args); err != nil {
os.Exit(1) //nolint:gocritic
}
}