mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-21 21:35:28 +02:00
Add /config dir support
This commit adds support for a configuration directory (default `config`). The different pieces in this puzzle are: * A new `--environment` (or `-e`) flag. This can also be set with the `HUGO_ENVIRONMENT` OS environment variable. The value for `environment` defaults to `production` when running `hugo` and `development` when running `hugo server`. You can set it to any value you want (e.g. `hugo server -e "Sensible Environment"`), but as it is used to load configuration from the file system, the letter case may be important. You can get this value in your templates with `{{ hugo.Environment }}`. * A new `--configDir` flag (defaults to `config` below your project). This can also be set with `HUGO_CONFIGDIR` OS environment variable. If the `configDir` exists, the configuration files will be read and merged on top of each other from left to right; the right-most value will win on duplicates. Given the example tree below: If `environment` is `production`, the left-most `config.toml` would be the one directly below the project (this can now be omitted if you want), and then `_default/config.toml` and finally `production/config.toml`. And since these will be merged, you can just provide the environment specific configuration setting in you production config, e.g. `enableGitInfo = true`. The order within the directories will be lexical (`config.toml` and then `params.toml`). ```bash config ├── _default │ ├── config.toml │ ├── languages.toml │ ├── menus │ │ ├── menus.en.toml │ │ └── menus.zh.toml │ └── params.toml ├── development │ └── params.toml └── production ├── config.toml └── params.toml ``` Some configuration maps support the language code in the filename (e.g. `menus.en.toml`): `menus` (`menu` also works) and `params`. Also note that the only folders with "a meaning" in the above listing is the top level directories below `config`. The `menus` sub folder is just added for better organization. We use `TOML` in the example above, but Hugo also supports `JSON` and `YAML` as configuration formats. These can be mixed. Fixes #5422
This commit is contained in:
@@ -249,6 +249,8 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
|
||||
sourceFs = c.DepsCfg.Fs.Source
|
||||
}
|
||||
|
||||
environment := c.h.getEnvironment(running)
|
||||
|
||||
doWithConfig := func(cfg config.Provider) error {
|
||||
|
||||
if c.ftch != nil {
|
||||
@@ -256,7 +258,7 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
|
||||
}
|
||||
|
||||
cfg.Set("workingDir", dir)
|
||||
|
||||
cfg.Set("environment", environment)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -269,8 +271,18 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
configPath := c.h.source
|
||||
if configPath == "" {
|
||||
configPath = dir
|
||||
}
|
||||
config, configFiles, err := hugolib.LoadConfig(
|
||||
hugolib.ConfigSourceDescriptor{Fs: sourceFs, Path: c.h.source, WorkingDir: dir, Filename: c.h.cfgFile},
|
||||
hugolib.ConfigSourceDescriptor{
|
||||
Fs: sourceFs,
|
||||
Path: configPath,
|
||||
WorkingDir: dir,
|
||||
Filename: c.h.cfgFile,
|
||||
AbsConfigDir: c.h.getConfigDir(dir),
|
||||
Environment: environment},
|
||||
doWithCommandeer,
|
||||
doWithConfig)
|
||||
|
||||
|
@@ -14,6 +14,11 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/gohugoio/hugo/hugolib/paths"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hugo"
|
||||
"github.com/gohugoio/hugo/common/loggers"
|
||||
"github.com/gohugoio/hugo/config"
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
@@ -159,6 +164,7 @@ Complete documentation is available at http://gohugo.io/.`,
|
||||
})
|
||||
|
||||
cc.cmd.PersistentFlags().StringVar(&cc.cfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
|
||||
cc.cmd.PersistentFlags().StringVar(&cc.cfgDir, "configDir", "config", "config dir")
|
||||
cc.cmd.PersistentFlags().BoolVar(&cc.quiet, "quiet", false, "build in quiet mode")
|
||||
|
||||
// Set bash-completion
|
||||
@@ -185,8 +191,9 @@ Complete documentation is available at http://gohugo.io/.`,
|
||||
}
|
||||
|
||||
type hugoBuilderCommon struct {
|
||||
source string
|
||||
baseURL string
|
||||
source string
|
||||
baseURL string
|
||||
environment string
|
||||
|
||||
buildWatch bool
|
||||
|
||||
@@ -200,15 +207,45 @@ type hugoBuilderCommon struct {
|
||||
quiet bool
|
||||
|
||||
cfgFile string
|
||||
cfgDir string
|
||||
logFile string
|
||||
}
|
||||
|
||||
func (cc *hugoBuilderCommon) getConfigDir(baseDir string) string {
|
||||
if cc.cfgDir != "" {
|
||||
return paths.AbsPathify(baseDir, cc.cfgDir)
|
||||
}
|
||||
|
||||
if v, found := os.LookupEnv("HUGO_CONFIGDIR"); found {
|
||||
return paths.AbsPathify(baseDir, v)
|
||||
}
|
||||
|
||||
return paths.AbsPathify(baseDir, "config")
|
||||
}
|
||||
|
||||
func (cc *hugoBuilderCommon) getEnvironment(isServer bool) string {
|
||||
if cc.environment != "" {
|
||||
return cc.environment
|
||||
}
|
||||
|
||||
if v, found := os.LookupEnv("HUGO_ENVIRONMENT"); found {
|
||||
return v
|
||||
}
|
||||
|
||||
if isServer {
|
||||
return hugo.EnvironmentDevelopment
|
||||
}
|
||||
|
||||
return hugo.EnvironmentProduction
|
||||
}
|
||||
|
||||
func (cc *hugoBuilderCommon) handleFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().Bool("cleanDestinationDir", false, "remove files from destination not found in static directories")
|
||||
cmd.Flags().BoolP("buildDrafts", "D", false, "include content marked as draft")
|
||||
cmd.Flags().BoolP("buildFuture", "F", false, "include content with publishdate in the future")
|
||||
cmd.Flags().BoolP("buildExpired", "E", false, "include expired content")
|
||||
cmd.Flags().StringVarP(&cc.source, "source", "s", "", "filesystem path to read files relative from")
|
||||
cmd.Flags().StringVarP(&cc.environment, "environment", "e", "", "build environment")
|
||||
cmd.Flags().StringP("contentDir", "c", "", "filesystem path to content directory")
|
||||
cmd.Flags().StringP("layoutDir", "l", "", "filesystem path to layout directory")
|
||||
cmd.Flags().StringP("cacheDir", "", "", "filesystem path to cache directory. Defaults: $TMPDIR/hugo_cache/")
|
||||
|
@@ -56,8 +56,11 @@ func TestCommandsPersistentFlags(t *testing.T) {
|
||||
check func(command []cmder)
|
||||
}{{[]string{"server",
|
||||
"--config=myconfig.toml",
|
||||
"--configDir=myconfigdir",
|
||||
"--contentDir=mycontent",
|
||||
"--disableKinds=page,home",
|
||||
"--environment=testing",
|
||||
"--configDir=myconfigdir",
|
||||
"--layoutDir=mylayouts",
|
||||
"--theme=mytheme",
|
||||
"--gc",
|
||||
@@ -78,6 +81,7 @@ func TestCommandsPersistentFlags(t *testing.T) {
|
||||
if b, ok := command.(commandsBuilderGetter); ok {
|
||||
v := b.getCommandsBuilder().hugoBuilderCommon
|
||||
assert.Equal("myconfig.toml", v.cfgFile)
|
||||
assert.Equal("myconfigdir", v.cfgDir)
|
||||
assert.Equal("mysource", v.source)
|
||||
assert.Equal("https://example.com/b/", v.baseURL)
|
||||
}
|
||||
@@ -93,6 +97,7 @@ func TestCommandsPersistentFlags(t *testing.T) {
|
||||
assert.True(sc.noHTTPCache)
|
||||
assert.True(sc.renderToDisk)
|
||||
assert.Equal(1366, sc.serverPort)
|
||||
assert.Equal("testing", sc.environment)
|
||||
|
||||
cfg := viper.New()
|
||||
sc.flagsToConfig(cfg)
|
||||
@@ -233,6 +238,7 @@ Single: {{ .Title }}
|
||||
writeFile(t, filepath.Join(d, "layouts", "_default", "list.html"), `
|
||||
|
||||
List: {{ .Title }}
|
||||
Environment: {{ hugo.Environment }}
|
||||
|
||||
`)
|
||||
|
||||
|
@@ -718,8 +718,8 @@ func (c *commandeer) newWatcher(dirList ...string) (*watcher.Batcher, error) {
|
||||
// Identifies changes to config (config.toml) files.
|
||||
configSet := make(map[string]bool)
|
||||
|
||||
c.logger.FEEDBACK.Println("Watching for config changes in", strings.Join(c.configFiles, ", "))
|
||||
for _, configFile := range c.configFiles {
|
||||
c.logger.FEEDBACK.Println("Watching for config changes in", configFile)
|
||||
watcher.Add(configFile)
|
||||
configSet[configFile] = true
|
||||
}
|
||||
@@ -750,7 +750,17 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
|
||||
configSet map[string]bool) {
|
||||
|
||||
for _, ev := range evs {
|
||||
if configSet[ev.Name] {
|
||||
isConfig := configSet[ev.Name]
|
||||
if !isConfig {
|
||||
// It may be one of the /config folders
|
||||
dirname := filepath.Dir(ev.Name)
|
||||
if dirname != "." && configSet[dirname] {
|
||||
isConfig = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if isConfig {
|
||||
if ev.Op&fsnotify.Chmod == fsnotify.Chmod {
|
||||
continue
|
||||
}
|
||||
@@ -766,7 +776,7 @@ func (c *commandeer) handleEvents(watcher *watcher.Batcher,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Config file changed. Need full rebuild.
|
||||
// Config file(s) changed. Need full rebuild.
|
||||
c.fullRebuild()
|
||||
break
|
||||
}
|
||||
|
@@ -36,7 +36,6 @@ import (
|
||||
"github.com/gohugoio/hugo/tpl"
|
||||
|
||||
"github.com/gohugoio/hugo/config"
|
||||
|
||||
"github.com/gohugoio/hugo/helpers"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -301,6 +300,8 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro
|
||||
|
||||
absPublishDir := f.c.hugo.PathSpec.AbsPathify(publishDir)
|
||||
|
||||
jww.FEEDBACK.Printf("Environment: %q", f.c.hugo.Deps.Site.Hugo().Environment)
|
||||
|
||||
if i == 0 {
|
||||
if f.s.renderToDisk {
|
||||
jww.FEEDBACK.Println("Serving pages from " + absPublishDir)
|
||||
|
@@ -68,6 +68,7 @@ func TestServer(t *testing.T) {
|
||||
homeContent := helpers.ReaderToString(resp.Body)
|
||||
|
||||
assert.Contains(homeContent, "List: Hugo Commands")
|
||||
assert.Contains(homeContent, "Environment: development")
|
||||
|
||||
// Stop the server.
|
||||
stop <- true
|
||||
|
Reference in New Issue
Block a user