func LoadGlobalConfig(args []string, extraFlags func(*flag.FlagSet)) (*GlobalConfig, error) {
	cfg := NewGlobalConfig()
	fs := flag.NewFlagSet("", flag.ContinueOnError)
	var configFilePath string
	fs.StringVar(&configFilePath, "c", "", "(deprecated alias of -config)")
	fs.StringVar(&configFilePath, "config", "", "tidb-lightning configuration file")
	printVersion := fs.Bool("V", false, "print version of lightning")
	logLevel := flagext.ChoiceVar(fs, "L", "", `log level: info, debug, warn, error, fatal (default info)`, "", "info", "debug", "warn", "warning", "error", "fatal")
	logFilePath := fs.String("log-file", "", "log file path")
	tidbHost := fs.String("tidb-host", "", "TiDB server host")
	tidbPort := fs.Int("tidb-port", 0, "TiDB server port (default 4000)")
	tidbUser := fs.String("tidb-user", "", "TiDB user name to connect")
	tidbPsw := fs.String("tidb-password", "", "TiDB password to connect")
	tidbStatusPort := fs.Int("tidb-status", 0, "TiDB server status port (default 10080)")
	pdAddr := fs.String("pd-urls", "", "PD endpoint address")
	dataSrcPath := fs.String("d", "", "Directory of the dump to import")
	importerAddr := fs.String("importer", "", "address (host:port) to connect to tikv-importer")
	backend := flagext.ChoiceVar(fs, "backend", "", `delivery backend: importer, tidb, local (default importer)`, "", "importer", "tidb", "local")
	sortedKVDir := fs.String("sorted-kv-dir", "", "path for KV pairs when local backend enabled")
	enableCheckpoint := fs.Bool("enable-checkpoint", true, "whether to enable checkpoints")
	noSchema := fs.Bool("no-schema", false, "ignore schema files, get schema directly from TiDB instead")
	checksum := flagext.ChoiceVar(fs, "checksum", "", "compare checksum after importing.", "", "required", "optional", "off", "true", "false")
	analyze := flagext.ChoiceVar(fs, "analyze", "", "analyze table after importing", "", "required", "optional", "off", "true", "false")
	checkRequirements := fs.Bool("check-requirements", true, "check cluster version before starting")
	tlsCAPath := fs.String("ca", "", "CA certificate path for TLS connection")
	tlsCertPath := fs.String("cert", "", "certificate path for TLS connection")
	tlsKeyPath := fs.String("key", "", "private key path for TLS connection")
	redactInfoLog := fs.Bool("redact-info-log", false, "whether to redact sensitive info in log")
	statusAddr := fs.String("status-addr", "", "the Lightning server address")
	serverMode := fs.Bool("server-mode", false, "start Lightning in server mode, wait for multiple tasks instead of starting immediately")
	var filter []string
	flagext.StringsVar(fs, &filter, "f", "select tables to import")
	if extraFlags != nil {
		extraFlags(fs)
	}
	if err := fs.Parse(args); err != nil {
		return nil, errors.Trace(err)
	}
	if *printVersion {
		fmt.Println(common.GetRawInfo())
		return nil, flag.ErrHelp
	}
	if len(configFilePath) > 0 {
		data, err := ioutil.ReadFile(configFilePath)
		if err != nil {
			return nil, errors.Annotatef(err, "Cannot read config file `%s`", configFilePath)
		}
		if err = toml.Unmarshal(data, cfg); err != nil {
			return nil, errors.Annotatef(err, "Cannot parse config file `%s`", configFilePath)
		}
		cfg.ConfigFileContent = data
	}
	if *logLevel != "" {
		cfg.App.Config.Level = *logLevel
	}
	if *logFilePath != "" {
		cfg.App.Config.File = *logFilePath
	}
	if cfg.App.Config.File == "-" {
		cfg.App.Config.File = ""
	} else if cfg.App.Config.File == "" {
		cfg.App.Config.File = timestampLogFileName()
	}
	if *tidbHost != "" {
		cfg.TiDB.Host = *tidbHost
	}
	if *tidbPort != 0 {
		cfg.TiDB.Port = *tidbPort
	}
	if *tidbStatusPort != 0 {
		cfg.TiDB.StatusPort = *tidbStatusPort
	}
	if *tidbUser != "" {
		cfg.TiDB.User = *tidbUser
	}
	if *tidbPsw != "" {
		cfg.TiDB.Psw = *tidbPsw
	}
	if *pdAddr != "" {
		cfg.TiDB.PdAddr = *pdAddr
	}
	if *dataSrcPath != "" {
		cfg.Mydumper.SourceDir = *dataSrcPath
	}
	if *importerAddr != "" {
		cfg.TikvImporter.Addr = *importerAddr
	}
	if *serverMode {
		cfg.App.ServerMode = true
	}
	if *statusAddr != "" {
		cfg.App.StatusAddr = *statusAddr
	}
	if *backend != "" {
		cfg.TikvImporter.Backend = *backend
	}
	if *sortedKVDir != "" {
		cfg.TikvImporter.SortedKVDir = *sortedKVDir
	}
	if !*enableCheckpoint {
		cfg.Checkpoint.Enable = false
	}
	if *noSchema {
		cfg.Mydumper.NoSchema = true
	}
	if *checksum != "" {
		_ = cfg.PostRestore.Checksum.FromStringValue(*checksum)
	}
	if *analyze != "" {
		_ = cfg.PostRestore.Analyze.FromStringValue(*analyze)
	}
	if cfg.App.StatusAddr == "" && cfg.App.PProfPort != 0 {
		cfg.App.StatusAddr = fmt.Sprintf(":%d", cfg.App.PProfPort)
	}
	if !*checkRequirements {
		cfg.App.CheckRequirements = false
	}
	if *tlsCAPath != "" {
		cfg.Security.CAPath = *tlsCAPath
	}
	if *tlsCertPath != "" {
		cfg.Security.CertPath = *tlsCertPath
	}
	if *tlsKeyPath != "" {
		cfg.Security.KeyPath = *tlsKeyPath
	}
	if *redactInfoLog {
		cfg.Security.RedactInfoLog = *redactInfoLog
	}
	if len(filter) > 0 {
		cfg.Mydumper.Filter = filter
	}
	if cfg.App.StatusAddr == "" && cfg.App.ServerMode {
		return nil, errors.New("If server-mode is enabled, the status-addr must be a valid listen address")
	}
	cfg.App.Config.Adjust()
	return cfg, nil
}
LoadGlobalConfig reads the arguments and fills in the GlobalConfig.
package config
import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"
	"github.com/BurntSushi/toml"
	"github.com/carlmjohnson/flagext"
	"github.com/pingcap/errors"
	"github.com/pingcap/tidb-lightning/lightning/common"
	"github.com/pingcap/tidb-lightning/lightning/log"
)
type GlobalLightning struct {
	log.Config
	StatusAddr        string `toml:"status-addr" json:"status-addr"`
	ServerMode        bool   `toml:"server-mode" json:"server-mode"`
	CheckRequirements bool   `toml:"check-requirements" json:"check-requirements"`
	PProfPort int `toml:"pprof-port" json:"-"`
}
type GlobalTiDB struct {
	Host       string `toml:"host" json:"host"`
	Port       int    `toml:"port" json:"port"`
	User       string `toml:"user" json:"user"`
	Psw        string `toml:"password" json:"-"`
	StatusPort int    `toml:"status-port" json:"status-port"`
	PdAddr     string `toml:"pd-addr" json:"pd-addr"`
	LogLevel   string `toml:"log-level" json:"log-level"`
}
type GlobalMydumper struct {
	SourceDir string   `toml:"data-source-dir" json:"data-source-dir"`
	NoSchema  bool     `toml:"no-schema" json:"no-schema"`
	Filter    []string `toml:"filter" json:"filter"`
}
type GlobalImporter struct {
	Addr        string `toml:"addr" json:"addr"`
	Backend     string `toml:"backend" json:"backend"`
	SortedKVDir string `toml:"sorted-kv-dir" json:"sorted-kv-dir"`
}
type GlobalConfig struct {
	App          GlobalLightning   `toml:"lightning" json:"lightning"`
	Checkpoint   GlobalCheckpoint  `toml:"checkpoint" json:"checkpoint"`
	TiDB         GlobalTiDB        `toml:"tidb" json:"tidb"`
	Mydumper     GlobalMydumper    `toml:"mydumper" json:"mydumper"`
	TikvImporter GlobalImporter    `toml:"tikv-importer" json:"tikv-importer"`
	PostRestore  GlobalPostRestore `toml:"post-restore" json:"post-restore"`
	Security     Security          `toml:"security" json:"security"`
	ConfigFileContent []byte
}
type GlobalCheckpoint struct {
	Enable bool `toml:"enable" json:"enable"`
}
type GlobalPostRestore struct {
	Checksum PostOpLevel `toml:"checksum" json:"checksum"`
	Analyze  PostOpLevel `toml:"analyze" json:"analyze"`
}
func NewGlobalConfig() *GlobalConfig {
	return &GlobalConfig{
		App: GlobalLightning{
			ServerMode:        false,
			CheckRequirements: true,
		},
		Checkpoint: GlobalCheckpoint{
			Enable: true,
		},
		TiDB: GlobalTiDB{
			Host:       "127.0.0.1",
			User:       "root",
			StatusPort: 10080,
			LogLevel:   "error",
		},
		Mydumper: GlobalMydumper{
			Filter: DefaultFilter,
		},
		TikvImporter: GlobalImporter{
			Backend: "importer",
		},
		PostRestore: GlobalPostRestore{
			Checksum: OpLevelRequired,
			Analyze:  OpLevelOptional,
		},
	}
}
func Must(cfg *GlobalConfig, err error) *GlobalConfig {
	switch errors.Cause(err) {
	case nil:
	case flag.ErrHelp:
		os.Exit(0)
	default:
		fmt.Println("Failed to parse command flags: ", err)
		os.Exit(2)
	}
	return cfg
}
func timestampLogFileName() string {
	return filepath.Join(os.TempDir(), time.Now().Format("lightning.log.2006-01-02T15.04.05Z0700"))
}