func CommandTidy(log logger.Logger) *cobra.Command {
	var debugMode bool
	perCommandTimeout := time.Second * 300
	cmd := &cobra.Command{
		Use:   "tidy [config file]",
		Short: "tidy the config file. It will replace the version number and install the protoc and proto plugins that declared in the config file",
		Run: func(cmd *cobra.Command, args []string) {
			ctx := cmd.Context()
			ctx = consts.WithPerCommandTimeout(ctx, perCommandTimeout)
			log.SetLogLevel(logger.LevelInfo)
			if debugMode {
				log.SetLogLevel(logger.LevelDebug)
				ctx = consts.WithDebugMode(ctx)
				log.LogWarn(nil, "running in debug mode")
			}
			var targets []string
			if len(args) != 0 {
				for _, arg := range args {
					dir, _ := filepath.Abs(arg)
					targets = append(targets, dir)
				}
			} else {
				dir, err := os.Getwd()
				if err != nil {
					log.LogFatal(nil, "failed to get current dir: %s", err)
				}
				targets = configs.ListConfigPaths(dir)
			}
			pluginManager, err := pluginmanager.NewPluginManager(pluginmanager.NewConfig(), log)
			if err != nil {
				log.LogFatal(nil, "failed to create plugin manager: %s", err)
			}
			configMap := map[string]struct{}{}
			for _, path := range targets {
				exists, err := util.IsFileExists(path)
				if err != nil {
					log.LogFatal(map[string]interface{}{
						"path": path,
						"err":  err,
					}, "failed to tidy config")
				}
				if !exists {
					continue
				}
				log.LogInfo(nil, "tidy %s", path)
				if err := tidy(ctx, pluginManager, path); err != nil {
					log.LogFatal(map[string]interface{}{
						"path": path,
						"err":  err,
					}, "failed to tidy config")
				}
				configMap[path] = struct{}{}
			}
			log.LogInfo(nil, "these following config files were tidied:")
			for path := range configMap {
				log.LogInfo(nil, "	%s", path)
			}
			log.LogInfo(nil, "\r\nsucceeded, you are ready to go :)")
		},
	}
	flags := cmd.PersistentFlags()
	flags.BoolVarP(&debugMode, "debug", "d", debugMode, "debug mode")
	flags.DurationVarP(&perCommandTimeout, "timeout", "t", perCommandTimeout, "execution timeout for per command")
	return cmd
}
CommandTidy is used to clean the config file
By default, clean the powerproto.yaml of the current directory and all parent directories
You can also explicitly specify the configuration file to clean up
package tidy
import (
	"context"
	"os"
	"path/filepath"
	"time"
	"github.com/spf13/cobra"
	"github.com/storyicon/powerproto/pkg/bootstraps"
	"github.com/storyicon/powerproto/pkg/component/pluginmanager"
	"github.com/storyicon/powerproto/pkg/configs"
	"github.com/storyicon/powerproto/pkg/consts"
	"github.com/storyicon/powerproto/pkg/util"
	"github.com/storyicon/powerproto/pkg/util/logger"
	"github.com/storyicon/powerproto/pkg/util/progressbar"
)
func tidy(ctx context.Context,
	pluginManager pluginmanager.PluginManager,
	configFilePath string) error {
	progress := progressbar.GetProgressBar(ctx, 1)
	progress.SetPrefix("tidy config")
	err := bootstraps.StepTidyConfigFile(ctx, pluginManager, progress, configFilePath)
	if err != nil {
		return err
	}
	progress.Incr()
	progress.Wait()
	configItems, err := configs.LoadConfigItems(configFilePath)
	if err != nil {
		return err
	}
	if err := bootstraps.StepInstallProtoc(ctx, pluginManager, configItems); err != nil {
		return err
	}
	if err := bootstraps.StepInstallRepositories(ctx, pluginManager, configItems); err != nil {
		return err
	}
	if err := bootstraps.StepInstallPlugins(ctx, pluginManager, configItems); err != nil {
		return err
	}
	return nil
}