Skip to content

Commit

Permalink
Add /config dir support
Browse files Browse the repository at this point in the history
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 gohugoio#5422
  • Loading branch information
bep committed Dec 11, 2018
1 parent 931a132 commit 27cca4c
Show file tree
Hide file tree
Showing 36 changed files with 901 additions and 184 deletions.
16 changes: 14 additions & 2 deletions commands/commandeer.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,14 +249,16 @@ 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 {
c.ftch.flagsToConfig(cfg)
}

cfg.Set("workingDir", dir)

cfg.Set("environment", environment)
return nil
}

Expand All @@ -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)

Expand Down
41 changes: 39 additions & 2 deletions commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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/")
Expand Down
6 changes: 6 additions & 0 deletions commands/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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)
}
Expand All @@ -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)
Expand Down Expand Up @@ -233,6 +238,7 @@ Single: {{ .Title }}
writeFile(t, filepath.Join(d, "layouts", "_default", "list.html"), `
List: {{ .Title }}
Environment: {{ hugo.Environment }}
`)

Expand Down
16 changes: 13 additions & 3 deletions commands/hugo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}
Expand Down
3 changes: 2 additions & 1 deletion commands/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions commands/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions common/herrors/error_locator.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ package herrors
import (
"io"
"io/ioutil"
"path/filepath"
"strings"

"github.com/gohugoio/hugo/common/text"
"github.com/gohugoio/hugo/helpers"

"github.com/spf13/afero"
)
Expand Down Expand Up @@ -172,12 +172,16 @@ func chromaLexerFromType(fileType string) string {
return fileType
}

func extNoDelimiter(filename string) string {
return strings.TrimPrefix(".", filepath.Ext(filename))
}

func chromaLexerFromFilename(filename string) string {
if strings.Contains(filename, "layouts") {
return "go-html-template"
}

ext := helpers.ExtNoDelimiter(filename)
ext := extNoDelimiter(filename)
return chromaLexerFromType(ext)
}

Expand Down
44 changes: 33 additions & 11 deletions common/hugo/hugo.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,50 @@ import (
"html/template"
)

const (
EnvironmentDevelopment = "development"
EnvironmentProduction = "production"
)

var (
// CommitHash contains the current Git revision. Use make to build to make
// commitHash contains the current Git revision. Use make to build to make
// sure this gets set.
CommitHash string
commitHash string

// BuildDate contains the date of the current build.
BuildDate string
// buildDate contains the date of the current build.
buildDate string
)

// Info contains information about the current Hugo environment
type Info struct {
Version VersionString
Generator template.HTML
CommitHash string
BuildDate string

// The build environment.
// Defaults are "production" (hugo) and "development" (hugo server).
// This can also be set by the user.
// It can be any string, but it will be all lower case.
Environment string
}

func NewInfo() Info {
// Version returns the current version as a comparable version string.
func (i Info) Version() VersionString {
return CurrentVersion.Version()
}

// Generator a Hugo meta generator HTML tag.
func (i Info) Generator() template.HTML {
return template.HTML(fmt.Sprintf(`<meta name="generator" content="Hugo %s" />`, CurrentVersion.String()))
}

// NewInfo creates a new Hugo Info object.
func NewInfo(environment string) Info {
if environment == "" {
environment = EnvironmentProduction
}
return Info{
Version: CurrentVersion.Version(),
CommitHash: CommitHash,
BuildDate: BuildDate,
Generator: template.HTML(fmt.Sprintf(`<meta name="generator" content="Hugo %s" />`, CurrentVersion.String())),
CommitHash: commitHash,
BuildDate: buildDate,
Environment: environment,
}
}
13 changes: 7 additions & 6 deletions common/hugo/hugo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ import (
func TestHugoInfo(t *testing.T) {
assert := require.New(t)

hugoInfo := NewInfo()
hugoInfo := NewInfo("")

assert.Equal(CurrentVersion.Version(), hugoInfo.Version)
assert.IsType(VersionString(""), hugoInfo.Version)
assert.Equal(CommitHash, hugoInfo.CommitHash)
assert.Equal(BuildDate, hugoInfo.BuildDate)
assert.Contains(hugoInfo.Generator, fmt.Sprintf("Hugo %s", hugoInfo.Version))
assert.Equal(CurrentVersion.Version(), hugoInfo.Version())
assert.IsType(VersionString(""), hugoInfo.Version())
assert.Equal(commitHash, hugoInfo.CommitHash)
assert.Equal(buildDate, hugoInfo.BuildDate)
assert.Equal("production", hugoInfo.Environment)
assert.Contains(hugoInfo.Generator(), fmt.Sprintf("Hugo %s", hugoInfo.Version()))

}
14 changes: 6 additions & 8 deletions common/hugo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,23 +130,21 @@ func BuildVersionString() string {
program := "Hugo Static Site Generator"

version := "v" + CurrentVersion.String()
if CommitHash != "" {
version += "-" + strings.ToUpper(CommitHash)
if commitHash != "" {
version += "-" + strings.ToUpper(commitHash)
}
if isExtended {
version += "/extended"
}

osArch := runtime.GOOS + "/" + runtime.GOARCH

var buildDate string
if BuildDate != "" {
buildDate = BuildDate
} else {
buildDate = "unknown"
date := buildDate
if date == "" {
date = "unknown"
}

return fmt.Sprintf("%s %s %s BuildDate: %s", program, version, osArch, buildDate)
return fmt.Sprintf("%s %s %s BuildDate: %s", program, version, osArch, date)

}

Expand Down
Loading

0 comments on commit 27cca4c

Please sign in to comment.