mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-21 21:35:28 +02:00
all: Refactor to nonglobal Viper, i18n etc.
This is a final rewrite that removes all the global state in Hugo, which also enables the use if `t.Parallel` in tests. Updates #2701 Fixes #3016
This commit is contained in:
@@ -54,7 +54,7 @@ func benchmark(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
c := commandeer{cfg}
|
||||
c := newCommandeer(cfg)
|
||||
|
||||
var memProf *os.File
|
||||
if memProfileFile != "" {
|
||||
|
46
commands/commandeer.go
Normal file
46
commands/commandeer.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2017 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 (
|
||||
"github.com/spf13/hugo/deps"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
)
|
||||
|
||||
type commandeer struct {
|
||||
*deps.DepsCfg
|
||||
pathSpec *helpers.PathSpec
|
||||
configured bool
|
||||
}
|
||||
|
||||
func (c *commandeer) Set(key string, value interface{}) {
|
||||
if c.configured {
|
||||
panic("commandeer cannot be changed")
|
||||
}
|
||||
c.Cfg.Set(key, value)
|
||||
}
|
||||
|
||||
// PathSpec lazily creates a new PathSpec, as all the paths must
|
||||
// be configured before it is created.
|
||||
func (c *commandeer) PathSpec() *helpers.PathSpec {
|
||||
c.configured = true
|
||||
if c.pathSpec == nil {
|
||||
c.pathSpec = helpers.NewPathSpec(c.Fs, c.Cfg)
|
||||
}
|
||||
return c.pathSpec
|
||||
}
|
||||
|
||||
func newCommandeer(cfg *deps.DepsCfg) *commandeer {
|
||||
return &commandeer{DepsCfg: cfg}
|
||||
}
|
@@ -21,11 +21,8 @@ import (
|
||||
|
||||
"github.com/spf13/cast"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
"github.com/spf13/hugo/hugolib"
|
||||
"github.com/spf13/hugo/parser"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var outputDir string
|
||||
@@ -86,7 +83,7 @@ func convertContents(mark rune) error {
|
||||
return err
|
||||
}
|
||||
|
||||
h, err := hugolib.NewHugoSitesFromConfiguration(cfg)
|
||||
h, err := hugolib.NewHugoSites(*cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -104,10 +101,10 @@ func convertContents(mark rune) error {
|
||||
return errors.New("No source files found")
|
||||
}
|
||||
|
||||
contentDir := helpers.AbsPathify(viper.GetString("contentDir"))
|
||||
jww.FEEDBACK.Println("processing", len(site.Source.Files()), "content files")
|
||||
contentDir := site.PathSpec.AbsPathify(site.Cfg.GetString("contentDir"))
|
||||
site.Log.FEEDBACK.Println("processing", len(site.Source.Files()), "content files")
|
||||
for _, file := range site.Source.Files() {
|
||||
jww.INFO.Println("Attempting to convert", file.LogicalName())
|
||||
site.Log.INFO.Println("Attempting to convert", file.LogicalName())
|
||||
page, err := site.NewPage(file.LogicalName())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -115,12 +112,12 @@ func convertContents(mark rune) error {
|
||||
|
||||
psr, err := parser.ReadFrom(file.Contents)
|
||||
if err != nil {
|
||||
jww.ERROR.Println("Error processing file:", file.Path())
|
||||
site.Log.ERROR.Println("Error processing file:", file.Path())
|
||||
return err
|
||||
}
|
||||
metadata, err := psr.Metadata()
|
||||
if err != nil {
|
||||
jww.ERROR.Println("Error processing file:", file.Path())
|
||||
site.Log.ERROR.Println("Error processing file:", file.Path())
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -139,7 +136,7 @@ func convertContents(mark rune) error {
|
||||
page.SetDir(filepath.Join(contentDir, file.Dir()))
|
||||
page.SetSourceContent(psr.Content())
|
||||
if err = page.SetSourceMetaData(metadata, mark); err != nil {
|
||||
jww.ERROR.Printf("Failed to set source metadata for file %q: %s. For more info see For more info see https://github.com/spf13/hugo/issues/2458", page.FullFilePath(), err)
|
||||
site.Log.ERROR.Printf("Failed to set source metadata for file %q: %s. For more info see For more info see https://github.com/spf13/hugo/issues/2458", page.FullFilePath(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -153,7 +150,7 @@ func convertContents(mark rune) error {
|
||||
return fmt.Errorf("Failed to save file %q: %s", page.FullFilePath(), err)
|
||||
}
|
||||
} else {
|
||||
jww.FEEDBACK.Println("Unsafe operation not allowed, use --unsafe or set a different output path")
|
||||
site.Log.FEEDBACK.Println("Unsafe operation not allowed, use --unsafe or set a different output path")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
326
commands/hugo.go
326
commands/hugo.go
@@ -27,8 +27,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/hugo/tpl"
|
||||
|
||||
"github.com/spf13/hugo/config"
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
|
||||
"github.com/spf13/hugo/parser"
|
||||
@@ -51,10 +50,6 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type commandeer struct {
|
||||
deps.DepsCfg
|
||||
}
|
||||
|
||||
// Hugo represents the Hugo sites to build. This variable is exported as it
|
||||
// is used by at least one external library (the Hugo caddy plugin). We should
|
||||
// provide a cleaner external API, but until then, this is it.
|
||||
@@ -64,7 +59,6 @@ var Hugo *hugolib.HugoSites
|
||||
// for benchmark testing etc. via the CLI commands.
|
||||
func Reset() error {
|
||||
Hugo = nil
|
||||
viper.Reset()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -124,10 +118,10 @@ Complete documentation is available at http://gohugo.io/.`,
|
||||
return err
|
||||
}
|
||||
|
||||
c := commandeer{cfg}
|
||||
c := newCommandeer(cfg)
|
||||
|
||||
if buildWatch {
|
||||
viper.Set("disableLiveReload", true)
|
||||
cfg.Cfg.Set("disableLiveReload", true)
|
||||
c.watchConfig()
|
||||
}
|
||||
|
||||
@@ -148,16 +142,17 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
baseURL string
|
||||
cacheDir string
|
||||
contentDir string
|
||||
layoutDir string
|
||||
cfgFile string
|
||||
destination string
|
||||
logFile string
|
||||
theme string
|
||||
themesDir string
|
||||
source string
|
||||
baseURL string
|
||||
cacheDir string
|
||||
contentDir string
|
||||
layoutDir string
|
||||
cfgFile string
|
||||
destination string
|
||||
logFile string
|
||||
theme string
|
||||
themesDir string
|
||||
source string
|
||||
logI18nWarnings bool
|
||||
)
|
||||
|
||||
// Execute adds all child commands to the root command HugoCmd and sets flags appropriately.
|
||||
@@ -242,7 +237,7 @@ func initHugoBuildCommonFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().BoolP("forceSyncStatic", "", false, "Copy all files when static is changed.")
|
||||
cmd.Flags().BoolP("noTimes", "", false, "Don't sync modification time of files")
|
||||
cmd.Flags().BoolP("noChmod", "", false, "Don't sync permission mode of files")
|
||||
cmd.Flags().BoolVarP(&tpl.Logi18nWarnings, "i18n-warnings", "", false, "Print missing translations")
|
||||
cmd.Flags().BoolVarP(&logI18nWarnings, "i18n-warnings", "", false, "Print missing translations")
|
||||
|
||||
// Set bash-completion.
|
||||
// Each flag must first be defined before using the SetAnnotation() call.
|
||||
@@ -275,39 +270,56 @@ func init() {
|
||||
}
|
||||
|
||||
// InitializeConfig initializes a config file with sensible default configuration flags.
|
||||
func InitializeConfig(subCmdVs ...*cobra.Command) (deps.DepsCfg, error) {
|
||||
func InitializeConfig(subCmdVs ...*cobra.Command) (*deps.DepsCfg, error) {
|
||||
|
||||
var cfg deps.DepsCfg
|
||||
var cfg *deps.DepsCfg = &deps.DepsCfg{}
|
||||
|
||||
if err := hugolib.LoadGlobalConfig(source, cfgFile); err != nil {
|
||||
// Init file systems. This may be changed at a later point.
|
||||
osFs := hugofs.Os
|
||||
|
||||
config, err := hugolib.LoadConfig(osFs, source, cfgFile)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
cfg.Cfg = config
|
||||
|
||||
c := newCommandeer(cfg)
|
||||
|
||||
for _, cmdV := range append([]*cobra.Command{hugoCmdV}, subCmdVs...) {
|
||||
initializeFlags(cmdV)
|
||||
c.initializeFlags(cmdV)
|
||||
}
|
||||
|
||||
logger, err := createLogger(cfg.Cfg)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
cfg.Logger = logger
|
||||
|
||||
config.Set("logI18nWarnings", logI18nWarnings)
|
||||
|
||||
if baseURL != "" {
|
||||
if !strings.HasSuffix(baseURL, "/") {
|
||||
baseURL = baseURL + "/"
|
||||
}
|
||||
viper.Set("baseURL", baseURL)
|
||||
config.Set("baseURL", baseURL)
|
||||
}
|
||||
|
||||
if !viper.GetBool("relativeURLs") && viper.GetString("baseURL") == "" {
|
||||
jww.ERROR.Println("No 'baseURL' set in configuration or as a flag. Features like page menus will not work without one.")
|
||||
if !config.GetBool("relativeURLs") && config.GetString("baseURL") == "" {
|
||||
cfg.Logger.ERROR.Println("No 'baseURL' set in configuration or as a flag. Features like page menus will not work without one.")
|
||||
}
|
||||
|
||||
if theme != "" {
|
||||
viper.Set("theme", theme)
|
||||
config.Set("theme", theme)
|
||||
}
|
||||
|
||||
if themesDir != "" {
|
||||
viper.Set("themesDir", themesDir)
|
||||
config.Set("themesDir", themesDir)
|
||||
}
|
||||
|
||||
if destination != "" {
|
||||
viper.Set("publishDir", destination)
|
||||
config.Set("publishDir", destination)
|
||||
}
|
||||
|
||||
var dir string
|
||||
@@ -316,24 +328,32 @@ func InitializeConfig(subCmdVs ...*cobra.Command) (deps.DepsCfg, error) {
|
||||
} else {
|
||||
dir, _ = os.Getwd()
|
||||
}
|
||||
viper.Set("workingDir", dir)
|
||||
config.Set("workingDir", dir)
|
||||
|
||||
cfg.Fs = hugofs.NewFrom(osFs, config)
|
||||
|
||||
// Hugo writes the output to memory instead of the disk.
|
||||
// This is only used for benchmark testing. Cause the content is only visible
|
||||
// in memory.
|
||||
if renderToMemory {
|
||||
c.Fs.Destination = new(afero.MemMapFs)
|
||||
// Rendering to memoryFS, publish to Root regardless of publishDir.
|
||||
c.Set("publishDir", "/")
|
||||
}
|
||||
|
||||
if contentDir != "" {
|
||||
viper.Set("contentDir", contentDir)
|
||||
config.Set("contentDir", contentDir)
|
||||
}
|
||||
|
||||
if layoutDir != "" {
|
||||
viper.Set("layoutDir", layoutDir)
|
||||
config.Set("layoutDir", layoutDir)
|
||||
}
|
||||
|
||||
if cacheDir != "" {
|
||||
viper.Set("cacheDir", cacheDir)
|
||||
config.Set("cacheDir", cacheDir)
|
||||
}
|
||||
|
||||
// Init file systems. This may be changed at a later point.
|
||||
cfg.Fs = hugofs.NewDefault()
|
||||
|
||||
cacheDir = viper.GetString("cacheDir")
|
||||
cacheDir = config.GetString("cacheDir")
|
||||
if cacheDir != "" {
|
||||
if helpers.FilePathSeparator != cacheDir[len(cacheDir)-1:] {
|
||||
cacheDir = cacheDir + helpers.FilePathSeparator
|
||||
@@ -343,39 +363,32 @@ func InitializeConfig(subCmdVs ...*cobra.Command) (deps.DepsCfg, error) {
|
||||
if !isDir {
|
||||
mkdir(cacheDir)
|
||||
}
|
||||
viper.Set("cacheDir", cacheDir)
|
||||
config.Set("cacheDir", cacheDir)
|
||||
} else {
|
||||
viper.Set("cacheDir", helpers.GetTempDir("hugo_cache", cfg.Fs.Source))
|
||||
config.Set("cacheDir", helpers.GetTempDir("hugo_cache", cfg.Fs.Source))
|
||||
}
|
||||
|
||||
jww.INFO.Println("Using config file:", viper.ConfigFileUsed())
|
||||
cfg.Logger.INFO.Println("Using config file:", viper.ConfigFileUsed())
|
||||
|
||||
themeDir := helpers.GetThemeDir()
|
||||
themeDir := c.PathSpec().GetThemeDir()
|
||||
if themeDir != "" {
|
||||
if _, err := cfg.Fs.Source.Stat(themeDir); os.IsNotExist(err) {
|
||||
return cfg, newSystemError("Unable to find theme Directory:", themeDir)
|
||||
}
|
||||
}
|
||||
|
||||
themeVersionMismatch, minVersion := isThemeVsHugoVersionMismatch(cfg.Fs.Source)
|
||||
themeVersionMismatch, minVersion := c.isThemeVsHugoVersionMismatch()
|
||||
|
||||
if themeVersionMismatch {
|
||||
jww.ERROR.Printf("Current theme does not support Hugo version %s. Minimum version required is %s\n",
|
||||
cfg.Logger.ERROR.Printf("Current theme does not support Hugo version %s. Minimum version required is %s\n",
|
||||
helpers.HugoReleaseVersion(), minVersion)
|
||||
}
|
||||
|
||||
logger, err := createLogger()
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
cfg.Logger = logger
|
||||
|
||||
return cfg, nil
|
||||
|
||||
}
|
||||
|
||||
func createLogger() (*jww.Notepad, error) {
|
||||
func createLogger(cfg config.Provider) (*jww.Notepad, error) {
|
||||
var (
|
||||
logHandle = ioutil.Discard
|
||||
outHandle = os.Stdout
|
||||
@@ -383,11 +396,11 @@ func createLogger() (*jww.Notepad, error) {
|
||||
logThreshold = jww.LevelWarn
|
||||
)
|
||||
|
||||
if verboseLog || logging || (viper.IsSet("logFile") && viper.GetString("logFile") != "") {
|
||||
if verboseLog || logging || (cfg.GetString("logFile") != "") {
|
||||
|
||||
var err error
|
||||
if viper.IsSet("logFile") && viper.GetString("logFile") != "" {
|
||||
path := viper.GetString("logFile")
|
||||
if cfg.GetString("logFile") != "" {
|
||||
path := cfg.GetString("logFile")
|
||||
logHandle, err = os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
return nil, newSystemError("Failed to open log file:", path, err)
|
||||
@@ -398,7 +411,7 @@ func createLogger() (*jww.Notepad, error) {
|
||||
return nil, newSystemError(err)
|
||||
}
|
||||
}
|
||||
} else if !quiet && viper.GetBool("verbose") {
|
||||
} else if !quiet && cfg.GetBool("verbose") {
|
||||
stdoutThreshold = jww.LevelInfo
|
||||
}
|
||||
|
||||
@@ -409,7 +422,7 @@ func createLogger() (*jww.Notepad, error) {
|
||||
return jww.NewNotepad(stdoutThreshold, logThreshold, outHandle, logHandle, "", log.Ldate|log.Ltime), nil
|
||||
}
|
||||
|
||||
func initializeFlags(cmd *cobra.Command) {
|
||||
func (c *commandeer) initializeFlags(cmd *cobra.Command) {
|
||||
persFlagKeys := []string{"verbose", "logFile"}
|
||||
flagKeys := []string{
|
||||
"cleanDestinationDir",
|
||||
@@ -432,21 +445,21 @@ func initializeFlags(cmd *cobra.Command) {
|
||||
}
|
||||
|
||||
for _, key := range persFlagKeys {
|
||||
setValueFromFlag(cmd.PersistentFlags(), key)
|
||||
c.setValueFromFlag(cmd.PersistentFlags(), key)
|
||||
}
|
||||
for _, key := range flagKeys {
|
||||
setValueFromFlag(cmd.Flags(), key)
|
||||
c.setValueFromFlag(cmd.Flags(), key)
|
||||
}
|
||||
}
|
||||
|
||||
func setValueFromFlag(flags *flag.FlagSet, key string) {
|
||||
if flagChanged(flags, key) {
|
||||
func (c *commandeer) setValueFromFlag(flags *flag.FlagSet, key string) {
|
||||
if c.flagChanged(flags, key) {
|
||||
f := flags.Lookup(key)
|
||||
viper.Set(key, f.Value.String())
|
||||
c.Set(key, f.Value.String())
|
||||
}
|
||||
}
|
||||
|
||||
func flagChanged(flags *flag.FlagSet, key string) bool {
|
||||
func (c *commandeer) flagChanged(flags *flag.FlagSet, key string) bool {
|
||||
flag := flags.Lookup(key)
|
||||
if flag == nil {
|
||||
return false
|
||||
@@ -454,31 +467,23 @@ func flagChanged(flags *flag.FlagSet, key string) bool {
|
||||
return flag.Changed
|
||||
}
|
||||
|
||||
func (c commandeer) watchConfig() {
|
||||
viper.WatchConfig()
|
||||
viper.OnConfigChange(func(e fsnotify.Event) {
|
||||
jww.FEEDBACK.Println("Config file changed:", e.Name)
|
||||
func (c *commandeer) watchConfig() {
|
||||
v := c.Cfg.(*viper.Viper)
|
||||
v.WatchConfig()
|
||||
v.OnConfigChange(func(e fsnotify.Event) {
|
||||
c.Logger.FEEDBACK.Println("Config file changed:", e.Name)
|
||||
// Force a full rebuild
|
||||
utils.CheckErr(c.recreateAndBuildSites(true))
|
||||
if !viper.GetBool("disableLiveReload") {
|
||||
if !c.Cfg.GetBool("disableLiveReload") {
|
||||
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
|
||||
livereload.ForceRefresh()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (c commandeer) build(watches ...bool) error {
|
||||
// Hugo writes the output to memory instead of the disk.
|
||||
// This is only used for benchmark testing. Cause the content is only visible
|
||||
// in memory.
|
||||
if renderToMemory {
|
||||
c.Fs.Destination = new(afero.MemMapFs)
|
||||
// Rendering to memoryFS, publish to Root regardless of publishDir.
|
||||
viper.Set("publishDir", "/")
|
||||
}
|
||||
|
||||
func (c *commandeer) build(watches ...bool) error {
|
||||
if err := c.copyStatic(); err != nil {
|
||||
return fmt.Errorf("Error copying static files to %s: %s", helpers.AbsPathify(viper.GetString("publishDir")), err)
|
||||
return fmt.Errorf("Error copying static files to %s: %s", c.PathSpec().AbsPathify(c.Cfg.GetString("publishDir")), err)
|
||||
}
|
||||
watch := false
|
||||
if len(watches) > 0 && watches[0] {
|
||||
@@ -489,37 +494,35 @@ func (c commandeer) build(watches ...bool) error {
|
||||
}
|
||||
|
||||
if buildWatch {
|
||||
jww.FEEDBACK.Println("Watching for changes in", helpers.AbsPathify(viper.GetString("contentDir")))
|
||||
jww.FEEDBACK.Println("Press Ctrl+C to stop")
|
||||
c.Logger.FEEDBACK.Println("Watching for changes in", c.PathSpec().AbsPathify(c.Cfg.GetString("contentDir")))
|
||||
c.Logger.FEEDBACK.Println("Press Ctrl+C to stop")
|
||||
utils.CheckErr(c.newWatcher(0))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c commandeer) getStaticSourceFs() afero.Fs {
|
||||
func (c *commandeer) getStaticSourceFs() afero.Fs {
|
||||
source := c.Fs.Source
|
||||
pathSpec := helpers.NewPathSpec(c.Fs, viper.GetViper())
|
||||
themeDir, err := pathSpec.GetThemeStaticDirPath()
|
||||
staticDir := helpers.GetStaticDirPath() + helpers.FilePathSeparator
|
||||
|
||||
themeDir, err := c.PathSpec().GetThemeStaticDirPath()
|
||||
staticDir := c.PathSpec().GetStaticDirPath() + helpers.FilePathSeparator
|
||||
useTheme := true
|
||||
useStatic := true
|
||||
|
||||
if err != nil {
|
||||
if err != helpers.ErrThemeUndefined {
|
||||
jww.WARN.Println(err)
|
||||
c.Logger.WARN.Println(err)
|
||||
}
|
||||
useTheme = false
|
||||
} else {
|
||||
if _, err := source.Stat(themeDir); os.IsNotExist(err) {
|
||||
jww.WARN.Println("Unable to find Theme Static Directory:", themeDir)
|
||||
c.Logger.WARN.Println("Unable to find Theme Static Directory:", themeDir)
|
||||
useTheme = false
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := source.Stat(staticDir); os.IsNotExist(err) {
|
||||
jww.WARN.Println("Unable to find Static Directory:", staticDir)
|
||||
c.Logger.WARN.Println("Unable to find Static Directory:", staticDir)
|
||||
useStatic = false
|
||||
}
|
||||
|
||||
@@ -528,25 +531,25 @@ func (c commandeer) getStaticSourceFs() afero.Fs {
|
||||
}
|
||||
|
||||
if !useStatic {
|
||||
jww.INFO.Println(themeDir, "is the only static directory available to sync from")
|
||||
c.Logger.INFO.Println(themeDir, "is the only static directory available to sync from")
|
||||
return afero.NewReadOnlyFs(afero.NewBasePathFs(source, themeDir))
|
||||
}
|
||||
|
||||
if !useTheme {
|
||||
jww.INFO.Println(staticDir, "is the only static directory available to sync from")
|
||||
c.Logger.INFO.Println(staticDir, "is the only static directory available to sync from")
|
||||
return afero.NewReadOnlyFs(afero.NewBasePathFs(source, staticDir))
|
||||
}
|
||||
|
||||
jww.INFO.Println("using a UnionFS for static directory comprised of:")
|
||||
jww.INFO.Println("Base:", themeDir)
|
||||
jww.INFO.Println("Overlay:", staticDir)
|
||||
c.Logger.INFO.Println("using a UnionFS for static directory comprised of:")
|
||||
c.Logger.INFO.Println("Base:", themeDir)
|
||||
c.Logger.INFO.Println("Overlay:", staticDir)
|
||||
base := afero.NewReadOnlyFs(afero.NewBasePathFs(source, themeDir))
|
||||
overlay := afero.NewReadOnlyFs(afero.NewBasePathFs(source, staticDir))
|
||||
return afero.NewCopyOnWriteFs(base, overlay)
|
||||
}
|
||||
|
||||
func (c commandeer) copyStatic() error {
|
||||
publishDir := helpers.AbsPathify(viper.GetString("publishDir")) + helpers.FilePathSeparator
|
||||
func (c *commandeer) copyStatic() error {
|
||||
publishDir := c.PathSpec().AbsPathify(c.Cfg.GetString("publishDir")) + helpers.FilePathSeparator
|
||||
|
||||
// If root, remove the second '/'
|
||||
if publishDir == "//" {
|
||||
@@ -557,22 +560,22 @@ func (c commandeer) copyStatic() error {
|
||||
staticSourceFs := c.getStaticSourceFs()
|
||||
|
||||
if staticSourceFs == nil {
|
||||
jww.WARN.Println("No static directories found to sync")
|
||||
c.Logger.WARN.Println("No static directories found to sync")
|
||||
return nil
|
||||
}
|
||||
|
||||
syncer := fsync.NewSyncer()
|
||||
syncer.NoTimes = viper.GetBool("noTimes")
|
||||
syncer.NoChmod = viper.GetBool("noChmod")
|
||||
syncer.NoTimes = c.Cfg.GetBool("noTimes")
|
||||
syncer.NoChmod = c.Cfg.GetBool("noChmod")
|
||||
syncer.SrcFs = staticSourceFs
|
||||
syncer.DestFs = c.Fs.Destination
|
||||
// Now that we are using a unionFs for the static directories
|
||||
// We can effectively clean the publishDir on initial sync
|
||||
syncer.Delete = viper.GetBool("cleanDestinationDir")
|
||||
syncer.Delete = c.Cfg.GetBool("cleanDestinationDir")
|
||||
if syncer.Delete {
|
||||
jww.INFO.Println("removing all files from destination that don't exist in static dirs")
|
||||
c.Logger.INFO.Println("removing all files from destination that don't exist in static dirs")
|
||||
}
|
||||
jww.INFO.Println("syncing static files to", publishDir)
|
||||
c.Logger.INFO.Println("syncing static files to", publishDir)
|
||||
|
||||
// because we are using a baseFs (to get the union right).
|
||||
// set sync src to root
|
||||
@@ -580,37 +583,37 @@ func (c commandeer) copyStatic() error {
|
||||
}
|
||||
|
||||
// getDirList provides NewWatcher() with a list of directories to watch for changes.
|
||||
func (c commandeer) getDirList() []string {
|
||||
func (c *commandeer) getDirList() []string {
|
||||
var a []string
|
||||
dataDir := helpers.AbsPathify(viper.GetString("dataDir"))
|
||||
i18nDir := helpers.AbsPathify(viper.GetString("i18nDir"))
|
||||
layoutDir := helpers.AbsPathify(viper.GetString("layoutDir"))
|
||||
staticDir := helpers.AbsPathify(viper.GetString("staticDir"))
|
||||
dataDir := c.PathSpec().AbsPathify(c.Cfg.GetString("dataDir"))
|
||||
i18nDir := c.PathSpec().AbsPathify(c.Cfg.GetString("i18nDir"))
|
||||
layoutDir := c.PathSpec().AbsPathify(c.Cfg.GetString("layoutDir"))
|
||||
staticDir := c.PathSpec().AbsPathify(c.Cfg.GetString("staticDir"))
|
||||
var themesDir string
|
||||
|
||||
if helpers.ThemeSet() {
|
||||
themesDir = helpers.AbsPathify(viper.GetString("themesDir") + "/" + viper.GetString("theme"))
|
||||
if c.PathSpec().ThemeSet() {
|
||||
themesDir = c.PathSpec().AbsPathify(c.Cfg.GetString("themesDir") + "/" + c.Cfg.GetString("theme"))
|
||||
}
|
||||
|
||||
walker := func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
if path == dataDir && os.IsNotExist(err) {
|
||||
jww.WARN.Println("Skip dataDir:", err)
|
||||
c.Logger.WARN.Println("Skip dataDir:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if path == i18nDir && os.IsNotExist(err) {
|
||||
jww.WARN.Println("Skip i18nDir:", err)
|
||||
c.Logger.WARN.Println("Skip i18nDir:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if path == layoutDir && os.IsNotExist(err) {
|
||||
jww.WARN.Println("Skip layoutDir:", err)
|
||||
c.Logger.WARN.Println("Skip layoutDir:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if path == staticDir && os.IsNotExist(err) {
|
||||
jww.WARN.Println("Skip staticDir:", err)
|
||||
c.Logger.WARN.Println("Skip staticDir:", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -619,23 +622,23 @@ func (c commandeer) getDirList() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
jww.ERROR.Println("Walker: ", err)
|
||||
c.Logger.ERROR.Println("Walker: ", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
link, err := filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
jww.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", path, err)
|
||||
c.Logger.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", path, err)
|
||||
return nil
|
||||
}
|
||||
linkfi, err := c.Fs.Source.Stat(link)
|
||||
if err != nil {
|
||||
jww.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)
|
||||
c.Logger.ERROR.Printf("Cannot stat '%s', error was: %s", link, err)
|
||||
return nil
|
||||
}
|
||||
if !linkfi.Mode().IsRegular() {
|
||||
jww.ERROR.Printf("Symbolic links for directories not supported, skipping '%s'", path)
|
||||
c.Logger.ERROR.Printf("Symbolic links for directories not supported, skipping '%s'", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -651,12 +654,12 @@ func (c commandeer) getDirList() []string {
|
||||
}
|
||||
|
||||
helpers.SymbolicWalk(c.Fs.Source, dataDir, walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, helpers.AbsPathify(viper.GetString("contentDir")), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, c.PathSpec().AbsPathify(c.Cfg.GetString("contentDir")), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, i18nDir, walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, helpers.AbsPathify(viper.GetString("layoutDir")), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, c.PathSpec().AbsPathify(c.Cfg.GetString("layoutDir")), walker)
|
||||
|
||||
helpers.SymbolicWalk(c.Fs.Source, staticDir, walker)
|
||||
if helpers.ThemeSet() {
|
||||
if c.PathSpec().ThemeSet() {
|
||||
helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "layouts"), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "static"), walker)
|
||||
helpers.SymbolicWalk(c.Fs.Source, filepath.Join(themesDir, "i18n"), walker)
|
||||
@@ -667,32 +670,31 @@ func (c commandeer) getDirList() []string {
|
||||
return a
|
||||
}
|
||||
|
||||
func (c commandeer) recreateAndBuildSites(watching bool) (err error) {
|
||||
func (c *commandeer) recreateAndBuildSites(watching bool) (err error) {
|
||||
if err := c.initSites(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !quiet {
|
||||
jww.FEEDBACK.Println("Started building sites ...")
|
||||
c.Logger.FEEDBACK.Println("Started building sites ...")
|
||||
}
|
||||
return Hugo.Build(hugolib.BuildCfg{CreateSitesFromConfig: true, Watching: watching, PrintStats: !quiet})
|
||||
}
|
||||
|
||||
func (c commandeer) resetAndBuildSites(watching bool) (err error) {
|
||||
func (c *commandeer) resetAndBuildSites(watching bool) (err error) {
|
||||
if err = c.initSites(); err != nil {
|
||||
return
|
||||
}
|
||||
if !quiet {
|
||||
jww.FEEDBACK.Println("Started building sites ...")
|
||||
c.Logger.FEEDBACK.Println("Started building sites ...")
|
||||
}
|
||||
return Hugo.Build(hugolib.BuildCfg{ResetState: true, Watching: watching, PrintStats: !quiet})
|
||||
}
|
||||
|
||||
func (c commandeer) initSites() error {
|
||||
func (c *commandeer) initSites() error {
|
||||
if Hugo != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
h, err := hugolib.NewHugoSitesFromConfiguration(c.DepsCfg)
|
||||
h, err := hugolib.NewHugoSites(*c.DepsCfg)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -702,17 +704,17 @@ func (c commandeer) initSites() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c commandeer) buildSites(watching bool) (err error) {
|
||||
func (c *commandeer) buildSites(watching bool) (err error) {
|
||||
if err := c.initSites(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !quiet {
|
||||
jww.FEEDBACK.Println("Started building sites ...")
|
||||
c.Logger.FEEDBACK.Println("Started building sites ...")
|
||||
}
|
||||
return Hugo.Build(hugolib.BuildCfg{Watching: watching, PrintStats: !quiet})
|
||||
}
|
||||
|
||||
func (c commandeer) rebuildSites(events []fsnotify.Event) error {
|
||||
func (c *commandeer) rebuildSites(events []fsnotify.Event) error {
|
||||
if err := c.initSites(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -720,13 +722,11 @@ func (c commandeer) rebuildSites(events []fsnotify.Event) error {
|
||||
}
|
||||
|
||||
// newWatcher creates a new watcher to watch filesystem events.
|
||||
func (c commandeer) newWatcher(port int) error {
|
||||
func (c *commandeer) newWatcher(port int) error {
|
||||
if runtime.GOOS == "darwin" {
|
||||
tweakLimit()
|
||||
}
|
||||
|
||||
pathSpec := helpers.NewPathSpec(c.Fs, viper.GetViper())
|
||||
|
||||
watcher, err := watcher.New(1 * time.Second)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
@@ -748,7 +748,7 @@ func (c commandeer) newWatcher(port int) error {
|
||||
for {
|
||||
select {
|
||||
case evs := <-watcher.Events:
|
||||
jww.INFO.Println("Received System Events:", evs)
|
||||
c.Logger.INFO.Println("Received System Events:", evs)
|
||||
|
||||
staticEvents := []fsnotify.Event{}
|
||||
dynamicEvents := []fsnotify.Event{}
|
||||
@@ -794,7 +794,7 @@ func (c commandeer) newWatcher(port int) error {
|
||||
|
||||
walkAdder := func(path string, f os.FileInfo, err error) error {
|
||||
if f.IsDir() {
|
||||
jww.FEEDBACK.Println("adding created directory to watchlist", path)
|
||||
c.Logger.FEEDBACK.Println("adding created directory to watchlist", path)
|
||||
watcher.Add(path)
|
||||
}
|
||||
return nil
|
||||
@@ -808,7 +808,7 @@ func (c commandeer) newWatcher(port int) error {
|
||||
}
|
||||
}
|
||||
|
||||
isstatic := strings.HasPrefix(ev.Name, helpers.GetStaticDirPath()) || (len(pathSpec.GetThemesDirPath()) > 0 && strings.HasPrefix(ev.Name, pathSpec.GetThemesDirPath()))
|
||||
isstatic := strings.HasPrefix(ev.Name, c.PathSpec().GetStaticDirPath()) || (len(c.PathSpec().GetThemesDirPath()) > 0 && strings.HasPrefix(ev.Name, c.PathSpec().GetThemesDirPath()))
|
||||
|
||||
if isstatic {
|
||||
staticEvents = append(staticEvents, ev)
|
||||
@@ -818,19 +818,19 @@ func (c commandeer) newWatcher(port int) error {
|
||||
}
|
||||
|
||||
if len(staticEvents) > 0 {
|
||||
publishDir := helpers.AbsPathify(viper.GetString("publishDir")) + helpers.FilePathSeparator
|
||||
publishDir := c.PathSpec().AbsPathify(c.Cfg.GetString("publishDir")) + helpers.FilePathSeparator
|
||||
|
||||
// If root, remove the second '/'
|
||||
if publishDir == "//" {
|
||||
publishDir = helpers.FilePathSeparator
|
||||
}
|
||||
|
||||
jww.FEEDBACK.Println("\nStatic file changes detected")
|
||||
c.Logger.FEEDBACK.Println("\nStatic file changes detected")
|
||||
const layout = "2006-01-02 15:04 -0700"
|
||||
jww.FEEDBACK.Println(time.Now().Format(layout))
|
||||
c.Logger.FEEDBACK.Println(time.Now().Format(layout))
|
||||
|
||||
if viper.GetBool("forceSyncStatic") {
|
||||
jww.FEEDBACK.Printf("Syncing all static files\n")
|
||||
if c.Cfg.GetBool("forceSyncStatic") {
|
||||
c.Logger.FEEDBACK.Printf("Syncing all static files\n")
|
||||
err := c.copyStatic()
|
||||
if err != nil {
|
||||
utils.StopOnErr(err, fmt.Sprintf("Error copying static files to %s", publishDir))
|
||||
@@ -839,13 +839,13 @@ func (c commandeer) newWatcher(port int) error {
|
||||
staticSourceFs := c.getStaticSourceFs()
|
||||
|
||||
if staticSourceFs == nil {
|
||||
jww.WARN.Println("No static directories found to sync")
|
||||
c.Logger.WARN.Println("No static directories found to sync")
|
||||
return
|
||||
}
|
||||
|
||||
syncer := fsync.NewSyncer()
|
||||
syncer.NoTimes = viper.GetBool("noTimes")
|
||||
syncer.NoChmod = viper.GetBool("noChmod")
|
||||
syncer.NoTimes = c.Cfg.GetBool("noTimes")
|
||||
syncer.NoChmod = c.Cfg.GetBool("noChmod")
|
||||
syncer.SrcFs = staticSourceFs
|
||||
syncer.DestFs = c.Fs.Destination
|
||||
|
||||
@@ -872,9 +872,9 @@ func (c commandeer) newWatcher(port int) error {
|
||||
fromPath := ev.Name
|
||||
|
||||
// If we are here we already know the event took place in a static dir
|
||||
relPath, err := pathSpec.MakeStaticPathRelative(fromPath)
|
||||
relPath, err := c.PathSpec().MakeStaticPathRelative(fromPath)
|
||||
if err != nil {
|
||||
jww.ERROR.Println(err)
|
||||
c.Logger.ERROR.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -897,10 +897,10 @@ func (c commandeer) newWatcher(port int) error {
|
||||
// If file still exists, sync it
|
||||
logger.Println("Syncing", relPath, "to", publishDir)
|
||||
if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
|
||||
jww.ERROR.Println(err)
|
||||
c.Logger.ERROR.Println(err)
|
||||
}
|
||||
} else {
|
||||
jww.ERROR.Println(err)
|
||||
c.Logger.ERROR.Println(err)
|
||||
}
|
||||
|
||||
continue
|
||||
@@ -909,18 +909,18 @@ func (c commandeer) newWatcher(port int) error {
|
||||
// For all other event operations Hugo will sync static.
|
||||
logger.Println("Syncing", relPath, "to", publishDir)
|
||||
if err := syncer.Sync(filepath.Join(publishDir, relPath), relPath); err != nil {
|
||||
jww.ERROR.Println(err)
|
||||
c.Logger.ERROR.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !buildWatch && !viper.GetBool("disableLiveReload") {
|
||||
if !buildWatch && !c.Cfg.GetBool("disableLiveReload") {
|
||||
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
|
||||
|
||||
// force refresh when more than one file
|
||||
if len(staticEvents) > 0 {
|
||||
for _, ev := range staticEvents {
|
||||
path, _ := pathSpec.MakeStaticPathRelative(ev.Name)
|
||||
path, _ := c.PathSpec().MakeStaticPathRelative(ev.Name)
|
||||
livereload.RefreshPath(path)
|
||||
}
|
||||
|
||||
@@ -931,27 +931,27 @@ func (c commandeer) newWatcher(port int) error {
|
||||
}
|
||||
|
||||
if len(dynamicEvents) > 0 {
|
||||
jww.FEEDBACK.Println("\nChange detected, rebuilding site")
|
||||
c.Logger.FEEDBACK.Println("\nChange detected, rebuilding site")
|
||||
const layout = "2006-01-02 15:04 -0700"
|
||||
jww.FEEDBACK.Println(time.Now().Format(layout))
|
||||
c.Logger.FEEDBACK.Println(time.Now().Format(layout))
|
||||
|
||||
c.rebuildSites(dynamicEvents)
|
||||
|
||||
if !buildWatch && !viper.GetBool("disableLiveReload") {
|
||||
if !buildWatch && !c.Cfg.GetBool("disableLiveReload") {
|
||||
// Will block forever trying to write to a channel that nobody is reading if livereload isn't initialized
|
||||
livereload.ForceRefresh()
|
||||
}
|
||||
}
|
||||
case err := <-watcher.Errors:
|
||||
if err != nil {
|
||||
jww.ERROR.Println(err)
|
||||
c.Logger.ERROR.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if port > 0 {
|
||||
if !viper.GetBool("disableLiveReload") {
|
||||
if !c.Cfg.GetBool("disableLiveReload") {
|
||||
livereload.Initialize()
|
||||
http.HandleFunc("/livereload.js", livereload.ServeJS)
|
||||
http.HandleFunc("/livereload", livereload.Handler)
|
||||
@@ -966,30 +966,30 @@ func (c commandeer) newWatcher(port int) error {
|
||||
|
||||
// isThemeVsHugoVersionMismatch returns whether the current Hugo version is
|
||||
// less than the theme's min_version.
|
||||
func isThemeVsHugoVersionMismatch(fs afero.Fs) (mismatch bool, requiredMinVersion string) {
|
||||
if !helpers.ThemeSet() {
|
||||
func (c *commandeer) isThemeVsHugoVersionMismatch() (mismatch bool, requiredMinVersion string) {
|
||||
if !c.PathSpec().ThemeSet() {
|
||||
return
|
||||
}
|
||||
|
||||
themeDir := helpers.GetThemeDir()
|
||||
themeDir := c.PathSpec().GetThemeDir()
|
||||
|
||||
path := filepath.Join(themeDir, "theme.toml")
|
||||
|
||||
exists, err := helpers.Exists(path, fs)
|
||||
exists, err := helpers.Exists(path, c.Fs.Source)
|
||||
|
||||
if err != nil || !exists {
|
||||
return
|
||||
}
|
||||
|
||||
b, err := afero.ReadFile(fs, path)
|
||||
b, err := afero.ReadFile(c.Fs.Source, path)
|
||||
|
||||
c, err := parser.HandleTOMLMetaData(b)
|
||||
tomlMeta, err := parser.HandleTOMLMetaData(b)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
config := c.(map[string]interface{})
|
||||
config := tomlMeta.(map[string]interface{})
|
||||
|
||||
if minVersion, ok := config["min_version"]; ok {
|
||||
switch minVersion.(type) {
|
||||
|
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/hugo/hugolib"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -50,9 +49,11 @@ var listDraftsCmd = &cobra.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
viper.Set("buildDrafts", true)
|
||||
c := newCommandeer(cfg)
|
||||
|
||||
sites, err := hugolib.NewHugoSitesFromConfiguration(cfg)
|
||||
c.Set("buildDrafts", true)
|
||||
|
||||
sites, err := hugolib.NewHugoSites(*cfg)
|
||||
|
||||
if err != nil {
|
||||
return newSystemError("Error creating sites", err)
|
||||
@@ -86,9 +87,11 @@ posted in the future.`,
|
||||
return err
|
||||
}
|
||||
|
||||
viper.Set("buildFuture", true)
|
||||
c := newCommandeer(cfg)
|
||||
|
||||
sites, err := hugolib.NewHugoSitesFromConfiguration(cfg)
|
||||
c.Set("buildFuture", true)
|
||||
|
||||
sites, err := hugolib.NewHugoSites(*cfg)
|
||||
|
||||
if err != nil {
|
||||
return newSystemError("Error creating sites", err)
|
||||
@@ -122,9 +125,11 @@ expired.`,
|
||||
return err
|
||||
}
|
||||
|
||||
viper.Set("buildExpired", true)
|
||||
c := newCommandeer(cfg)
|
||||
|
||||
sites, err := hugolib.NewHugoSitesFromConfiguration(cfg)
|
||||
c.Set("buildExpired", true)
|
||||
|
||||
sites, err := hugolib.NewHugoSites(*cfg)
|
||||
|
||||
if err != nil {
|
||||
return newSystemError("Error creating sites", err)
|
||||
|
@@ -29,15 +29,17 @@ var configCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
func init() {
|
||||
configCmd.RunE = config
|
||||
configCmd.RunE = printConfig
|
||||
}
|
||||
|
||||
func config(cmd *cobra.Command, args []string) error {
|
||||
if _, err := InitializeConfig(configCmd); err != nil {
|
||||
func printConfig(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := InitializeConfig(configCmd)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
allSettings := viper.AllSettings()
|
||||
allSettings := cfg.Cfg.(*viper.Viper).AllSettings()
|
||||
|
||||
var separator string
|
||||
if allSettings["metadataformat"] == "toml" {
|
||||
|
@@ -93,12 +93,14 @@ func NewContent(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if flagChanged(cmd.Flags(), "format") {
|
||||
viper.Set("metaDataFormat", configFormat)
|
||||
c := newCommandeer(cfg)
|
||||
|
||||
if c.flagChanged(cmd.Flags(), "format") {
|
||||
c.Set("metaDataFormat", configFormat)
|
||||
}
|
||||
|
||||
if flagChanged(cmd.Flags(), "editor") {
|
||||
viper.Set("newContentEditor", contentEditor)
|
||||
if c.flagChanged(cmd.Flags(), "editor") {
|
||||
c.Set("newContentEditor", contentEditor)
|
||||
}
|
||||
|
||||
if len(args) < 1 {
|
||||
@@ -115,7 +117,7 @@ func NewContent(cmd *cobra.Command, args []string) error {
|
||||
kind = contentType
|
||||
}
|
||||
|
||||
s, err := hugolib.NewSite(cfg)
|
||||
s, err := hugolib.NewSite(*cfg)
|
||||
|
||||
if err != nil {
|
||||
return newSystemError(err)
|
||||
@@ -203,7 +205,7 @@ func NewSite(cmd *cobra.Command, args []string) error {
|
||||
|
||||
forceNew, _ := cmd.Flags().GetBool("force")
|
||||
|
||||
return doNewSite(hugofs.NewDefault(), createpath, forceNew)
|
||||
return doNewSite(hugofs.NewDefault(viper.New()), createpath, forceNew)
|
||||
}
|
||||
|
||||
// NewTheme creates a new Hugo theme.
|
||||
@@ -215,11 +217,12 @@ func NewTheme(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
|
||||
if len(args) < 1 {
|
||||
|
||||
return newUserError("theme name needs to be provided")
|
||||
}
|
||||
|
||||
createpath := helpers.AbsPathify(filepath.Join(viper.GetString("themesDir"), args[0]))
|
||||
c := newCommandeer(cfg)
|
||||
|
||||
createpath := c.PathSpec().AbsPathify(filepath.Join(c.Cfg.GetString("themesDir"), args[0]))
|
||||
jww.INFO.Println("creating theme at", createpath)
|
||||
|
||||
if x, _ := helpers.Exists(createpath, cfg.Fs.Source); x {
|
||||
|
@@ -18,6 +18,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/hugo/hugofs"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -48,7 +49,7 @@ func checkNewSiteInited(fs *hugofs.Fs, basepath string, t *testing.T) {
|
||||
|
||||
func TestDoNewSite(t *testing.T) {
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
_, fs := newTestCfg()
|
||||
|
||||
require.NoError(t, doNewSite(fs, basepath, false))
|
||||
|
||||
@@ -57,7 +58,7 @@ func TestDoNewSite(t *testing.T) {
|
||||
|
||||
func TestDoNewSite_noerror_base_exists_but_empty(t *testing.T) {
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
_, fs := newTestCfg()
|
||||
|
||||
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
|
||||
|
||||
@@ -66,7 +67,7 @@ func TestDoNewSite_noerror_base_exists_but_empty(t *testing.T) {
|
||||
|
||||
func TestDoNewSite_error_base_exists(t *testing.T) {
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
_, fs := newTestCfg()
|
||||
|
||||
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
|
||||
_, err := fs.Source.Create(filepath.Join(basepath, "foo"))
|
||||
@@ -78,7 +79,7 @@ func TestDoNewSite_error_base_exists(t *testing.T) {
|
||||
|
||||
func TestDoNewSite_force_empty_dir(t *testing.T) {
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
_, fs := newTestCfg()
|
||||
|
||||
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
|
||||
|
||||
@@ -89,7 +90,7 @@ func TestDoNewSite_force_empty_dir(t *testing.T) {
|
||||
|
||||
func TestDoNewSite_error_force_dir_inside_exists(t *testing.T) {
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
_, fs := newTestCfg()
|
||||
|
||||
contentPath := filepath.Join(basepath, "content")
|
||||
|
||||
@@ -99,7 +100,7 @@ func TestDoNewSite_error_force_dir_inside_exists(t *testing.T) {
|
||||
|
||||
func TestDoNewSite_error_force_config_inside_exists(t *testing.T) {
|
||||
basepath := filepath.Join("base", "blog")
|
||||
fs := hugofs.NewMem()
|
||||
_, fs := newTestCfg()
|
||||
|
||||
configPath := filepath.Join(basepath, "config.toml")
|
||||
require.NoError(t, fs.Source.MkdirAll(basepath, 777))
|
||||
@@ -108,3 +109,14 @@ func TestDoNewSite_error_force_config_inside_exists(t *testing.T) {
|
||||
|
||||
require.Error(t, doNewSite(fs, basepath, true))
|
||||
}
|
||||
|
||||
func newTestCfg() (*viper.Viper, *hugofs.Fs) {
|
||||
|
||||
v := viper.New()
|
||||
fs := hugofs.NewMem(v)
|
||||
|
||||
v.SetFs(fs.Source)
|
||||
|
||||
return v, fs
|
||||
|
||||
}
|
||||
|
@@ -28,9 +28,9 @@ import (
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/hugo/config"
|
||||
"github.com/spf13/hugo/helpers"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -42,8 +42,6 @@ var (
|
||||
serverWatch bool
|
||||
)
|
||||
|
||||
//var serverCmdV *cobra.Command
|
||||
|
||||
var serverCmd = &cobra.Command{
|
||||
Use: "server",
|
||||
Aliases: []string{"serve"},
|
||||
@@ -108,17 +106,17 @@ func server(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
c := commandeer{cfg}
|
||||
c := newCommandeer(cfg)
|
||||
|
||||
if flagChanged(cmd.Flags(), "disableLiveReload") {
|
||||
viper.Set("disableLiveReload", disableLiveReload)
|
||||
if c.flagChanged(cmd.Flags(), "disableLiveReload") {
|
||||
c.Set("disableLiveReload", disableLiveReload)
|
||||
}
|
||||
|
||||
if serverWatch {
|
||||
viper.Set("watch", true)
|
||||
c.Set("watch", true)
|
||||
}
|
||||
|
||||
if viper.GetBool("watch") {
|
||||
if c.Cfg.GetBool("watch") {
|
||||
serverWatch = true
|
||||
c.watchConfig()
|
||||
}
|
||||
@@ -127,7 +125,7 @@ func server(cmd *cobra.Command, args []string) error {
|
||||
if err == nil {
|
||||
l.Close()
|
||||
} else {
|
||||
if flagChanged(serverCmd.Flags(), "port") {
|
||||
if c.flagChanged(serverCmd.Flags(), "port") {
|
||||
// port set explicitly by user -- he/she probably meant it!
|
||||
return newSystemErrorF("Server startup failed: %s", err)
|
||||
}
|
||||
@@ -139,13 +137,13 @@ func server(cmd *cobra.Command, args []string) error {
|
||||
serverPort = sp.Port
|
||||
}
|
||||
|
||||
viper.Set("port", serverPort)
|
||||
c.Set("port", serverPort)
|
||||
|
||||
baseURL, err = fixURL(baseURL)
|
||||
baseURL, err = fixURL(c.Cfg, baseURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
viper.Set("baseURL", baseURL)
|
||||
c.Set("baseURL", baseURL)
|
||||
|
||||
if err := memStats(); err != nil {
|
||||
jww.ERROR.Println("memstats error:", err)
|
||||
@@ -160,7 +158,7 @@ func server(cmd *cobra.Command, args []string) error {
|
||||
if !renderToDisk {
|
||||
cfg.Fs.Destination = new(afero.MemMapFs)
|
||||
// Rendering to memoryFS, publish to Root regardless of publishDir.
|
||||
viper.Set("publishDir", "/")
|
||||
c.Set("publishDir", "/")
|
||||
}
|
||||
|
||||
if err := c.build(serverWatch); err != nil {
|
||||
@@ -170,7 +168,7 @@ func server(cmd *cobra.Command, args []string) error {
|
||||
// Watch runs its own server as part of the routine
|
||||
if serverWatch {
|
||||
watchDirs := c.getDirList()
|
||||
baseWatchDir := viper.GetString("workingDir")
|
||||
baseWatchDir := c.Cfg.GetString("workingDir")
|
||||
for i, dir := range watchDirs {
|
||||
watchDirs[i], _ = helpers.GetRelativePath(dir, baseWatchDir)
|
||||
}
|
||||
@@ -190,19 +188,19 @@ func server(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c commandeer) serve(port int) {
|
||||
func (c *commandeer) serve(port int) {
|
||||
if renderToDisk {
|
||||
jww.FEEDBACK.Println("Serving pages from " + helpers.AbsPathify(viper.GetString("publishDir")))
|
||||
jww.FEEDBACK.Println("Serving pages from " + c.PathSpec().AbsPathify(c.Cfg.GetString("publishDir")))
|
||||
} else {
|
||||
jww.FEEDBACK.Println("Serving pages from memory")
|
||||
}
|
||||
|
||||
httpFs := afero.NewHttpFs(c.Fs.Destination)
|
||||
fs := filesOnlyFs{httpFs.Dir(helpers.AbsPathify(viper.GetString("publishDir")))}
|
||||
fs := filesOnlyFs{httpFs.Dir(c.PathSpec().AbsPathify(c.Cfg.GetString("publishDir")))}
|
||||
fileserver := http.FileServer(fs)
|
||||
|
||||
// We're only interested in the path
|
||||
u, err := url.Parse(viper.GetString("baseURL"))
|
||||
u, err := url.Parse(c.Cfg.GetString("baseURL"))
|
||||
if err != nil {
|
||||
jww.ERROR.Fatalf("Invalid baseURL: %s", err)
|
||||
}
|
||||
@@ -225,10 +223,10 @@ func (c commandeer) serve(port int) {
|
||||
|
||||
// fixURL massages the baseURL into a form needed for serving
|
||||
// all pages correctly.
|
||||
func fixURL(s string) (string, error) {
|
||||
func fixURL(cfg config.Provider, s string) (string, error) {
|
||||
useLocalhost := false
|
||||
if s == "" {
|
||||
s = viper.GetString("baseURL")
|
||||
s = cfg.GetString("baseURL")
|
||||
useLocalhost = true
|
||||
}
|
||||
|
||||
|
@@ -20,8 +20,6 @@ import (
|
||||
)
|
||||
|
||||
func TestFixURL(t *testing.T) {
|
||||
defer viper.Reset()
|
||||
|
||||
type data struct {
|
||||
TestName string
|
||||
CLIBaseURL string
|
||||
@@ -44,12 +42,12 @@ func TestFixURL(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
viper.Reset()
|
||||
v := viper.New()
|
||||
baseURL = test.CLIBaseURL
|
||||
viper.Set("baseURL", test.CfgBaseURL)
|
||||
v.Set("baseURL", test.CfgBaseURL)
|
||||
serverAppend = test.AppendPort
|
||||
serverPort = test.Port
|
||||
result, err := fixURL(baseURL)
|
||||
result, err := fixURL(v, baseURL)
|
||||
if err != nil {
|
||||
t.Errorf("Test #%d %s: unexpected error %s", i, test.TestName, err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user