// Copyright 2023 The Hugo Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package commands import ( "bytes" "errors" "fmt" "log" "os" "path/filepath" "strings" "github.com/bep/simplecobra" "github.com/gohugoio/hugo/config" "github.com/gohugoio/hugo/helpers" "github.com/spf13/afero" "github.com/spf13/pflag" ) const ( ansiEsc = "\u001B" clearLine = "\r\033[K" hideCursor = ansiEsc + "[?25l" showCursor = ansiEsc + "[?25h" ) func newUserError(a ...any) *simplecobra.CommandError { return &simplecobra.CommandError{Err: errors.New(fmt.Sprint(a...))} } func setValueFromFlag(flags *pflag.FlagSet, key string, cfg config.Provider, targetKey string, force bool) { key = strings.TrimSpace(key) if (force && flags.Lookup(key) != nil) || flags.Changed(key) { f := flags.Lookup(key) configKey := key if targetKey != "" { configKey = targetKey } // Gotta love this API. switch f.Value.Type() { case "bool": bv, _ := flags.GetBool(key) cfg.Set(configKey, bv) case "string": cfg.Set(configKey, f.Value.String()) case "stringSlice": bv, _ := flags.GetStringSlice(key) cfg.Set(configKey, bv) case "int": iv, _ := flags.GetInt(key) cfg.Set(configKey, iv) default: panic(fmt.Sprintf("update switch with %s", f.Value.Type())) } } } func flagsToCfg(cd *simplecobra.Commandeer, cfg config.Provider) config.Provider { return flagsToCfgWithAdditionalConfigBase(cd, cfg, "") } func flagsToCfgWithAdditionalConfigBase(cd *simplecobra.Commandeer, cfg config.Provider, additionalConfigBase string) config.Provider { if cfg == nil { cfg = config.New() } // Flags with a different name in the config. keyMap := map[string]string{ "minify": "minifyOutput", "destination": "publishDir", "printI18nWarnings": "logI18nWarnings", "printPathWarnings": "logPathWarnings", "editor": "newContentEditor", } // Flags that we for some reason don't want to expose in the site config. internalKeySet := map[string]bool{ "quiet": true, "verbose": true, "watch": true, "disableLiveReload": true, "liveReloadPort": true, "renderToMemory": true, "clock": true, } cmd := cd.CobraCommand flags := cmd.Flags() flags.VisitAll(func(f *pflag.Flag) { if f.Changed { targetKey := f.Name if internalKeySet[targetKey] { targetKey = "internal." + targetKey } else if mapped, ok := keyMap[targetKey]; ok { targetKey = mapped } setValueFromFlag(flags, f.Name, cfg, targetKey, false) if additionalConfigBase != "" { setValueFromFlag(flags, f.Name, cfg, additionalConfigBase+"."+targetKey, true) } } }) return cfg } func mkdir(x ...string) { p := filepath.Join(x...) err := os.MkdirAll(p, 0777) // before umask if err != nil { log.Fatal(err) } } func touchFile(fs afero.Fs, filename string) { mkdir(filepath.Dir(filename)) err := helpers.WriteToDisk(filename, bytes.NewReader([]byte{}), fs) if err != nil { log.Fatal(err) } }