Add readFile template func

This also includes a refactor of the hugofs package and its usage.

The motivation for that is:

The Afero filesystems are brilliant. Hugo's way of adding a dozen of global variables for the different filesystems was a mistake. In readFile (and also in some other places in Hugo today) we need a way to restrict the access inside the working dir. We could use ioutil.ReadFile and implement the path checking, checking the base path and the dots ("..") etc. But it is obviously better to use an Afero BasePathFs combined witha ReadOnlyFs. We could create a use-once-filesystem and handle the initialization ourselves, but since this is also useful to others and the initialization depends on some other global state (which would mean to create a new file system on every invocation), we might as well do it properly and encapsulate the predefined set of filesystems. This change also leads the way, if needed, to encapsulate the file systems in a struct, making it possible to have several file system sets in action at once (parallel multilanguage site building? With Moore's law and all...)

Fixes #1551
This commit is contained in:
Bjørn Erik Pedersen
2016-03-22 00:28:42 +01:00
parent a89035bdaa
commit 4f66f790b1
32 changed files with 400 additions and 152 deletions

View File

@@ -423,14 +423,14 @@ func InitializeConfig(subCmdVs ...*cobra.Command) error {
if helpers.FilePathSeparator != cacheDir[len(cacheDir)-1:] {
cacheDir = cacheDir + helpers.FilePathSeparator
}
isDir, err := helpers.DirExists(cacheDir, hugofs.SourceFs)
isDir, err := helpers.DirExists(cacheDir, hugofs.Source())
utils.CheckErr(err)
if isDir == false {
mkdir(cacheDir)
}
viper.Set("CacheDir", cacheDir)
} else {
viper.Set("CacheDir", helpers.GetTempDir("hugo_cache", hugofs.SourceFs))
viper.Set("CacheDir", helpers.GetTempDir("hugo_cache", hugofs.Source()))
}
if verboseLog || logging || (viper.IsSet("LogFile") && viper.GetString("LogFile") != "") {
@@ -453,6 +453,9 @@ func InitializeConfig(subCmdVs ...*cobra.Command) error {
jww.INFO.Println("Using config file:", viper.ConfigFileUsed())
// Init file systems. This may be changed at a later point.
hugofs.InitDefaultFs()
themeDir := helpers.GetThemeDir()
if themeDir != "" {
if _, err := os.Stat(themeDir); os.IsNotExist(err) {
@@ -498,7 +501,7 @@ func build(watches ...bool) error {
// This is only used for benchmark testing. Cause the content is only visible
// in memory
if renderToMemory {
hugofs.DestinationFS = new(afero.MemMapFs)
hugofs.SetDestination(new(afero.MemMapFs))
// Rendering to memoryFS, publish to Root regardless of publishDir.
viper.Set("PublishDir", "/")
}
@@ -524,7 +527,7 @@ func build(watches ...bool) error {
}
func getStaticSourceFs() afero.Fs {
source := hugofs.SourceFs
source := hugofs.Source()
themeDir, err := helpers.GetThemeStaticDirPath()
staticDir := helpers.GetStaticDirPath() + helpers.FilePathSeparator
@@ -563,8 +566,8 @@ func getStaticSourceFs() afero.Fs {
jww.INFO.Println("using a UnionFS for static directory comprised of:")
jww.INFO.Println("Base:", themeDir)
jww.INFO.Println("Overlay:", staticDir)
base := afero.NewReadOnlyFs(afero.NewBasePathFs(hugofs.SourceFs, themeDir))
overlay := afero.NewReadOnlyFs(afero.NewBasePathFs(hugofs.SourceFs, staticDir))
base := afero.NewReadOnlyFs(afero.NewBasePathFs(hugofs.Source(), themeDir))
overlay := afero.NewReadOnlyFs(afero.NewBasePathFs(hugofs.Source(), staticDir))
return afero.NewCopyOnWriteFs(base, overlay)
}
@@ -587,7 +590,7 @@ func copyStatic() error {
syncer := fsync.NewSyncer()
syncer.NoTimes = viper.GetBool("notimes")
syncer.SrcFs = staticSourceFs
syncer.DestFs = hugofs.DestinationFS
syncer.DestFs = hugofs.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")
@@ -653,12 +656,12 @@ func getDirList() []string {
return nil
}
helpers.SymbolicWalk(hugofs.SourceFs, dataDir, walker)
helpers.SymbolicWalk(hugofs.SourceFs, helpers.AbsPathify(viper.GetString("ContentDir")), walker)
helpers.SymbolicWalk(hugofs.SourceFs, helpers.AbsPathify(viper.GetString("LayoutDir")), walker)
helpers.SymbolicWalk(hugofs.SourceFs, helpers.AbsPathify(viper.GetString("StaticDir")), walker)
helpers.SymbolicWalk(hugofs.Source(), dataDir, walker)
helpers.SymbolicWalk(hugofs.Source(), helpers.AbsPathify(viper.GetString("ContentDir")), walker)
helpers.SymbolicWalk(hugofs.Source(), helpers.AbsPathify(viper.GetString("LayoutDir")), walker)
helpers.SymbolicWalk(hugofs.Source(), helpers.AbsPathify(viper.GetString("StaticDir")), walker)
if helpers.ThemeSet() {
helpers.SymbolicWalk(hugofs.SourceFs, helpers.AbsPathify(viper.GetString("themesDir")+"/"+viper.GetString("theme")), walker)
helpers.SymbolicWalk(hugofs.Source(), helpers.AbsPathify(viper.GetString("themesDir")+"/"+viper.GetString("theme")), walker)
}
return a
@@ -770,8 +773,8 @@ func NewWatcher(port int) error {
// recursively add new directories to watch list
// When mkdir -p is used, only the top directory triggers an event (at least on OSX)
if ev.Op&fsnotify.Create == fsnotify.Create {
if s, err := hugofs.SourceFs.Stat(ev.Name); err == nil && s.Mode().IsDir() {
helpers.SymbolicWalk(hugofs.SourceFs, ev.Name, walkAdder)
if s, err := hugofs.Source().Stat(ev.Name); err == nil && s.Mode().IsDir() {
helpers.SymbolicWalk(hugofs.Source(), ev.Name, walkAdder)
}
}
@@ -813,7 +816,7 @@ func NewWatcher(port int) error {
syncer := fsync.NewSyncer()
syncer.NoTimes = viper.GetBool("notimes")
syncer.SrcFs = staticSourceFs
syncer.DestFs = hugofs.DestinationFS
syncer.DestFs = hugofs.Destination()
// prevent spamming the log on changes
logger := helpers.NewDistinctFeedbackLogger()
@@ -858,7 +861,7 @@ func NewWatcher(port int) error {
// If file doesn't exist in any static dir, remove it
toRemove := filepath.Join(publishDir, relPath)
logger.Println("File no longer exists in static dir, removing", toRemove)
hugofs.DestinationFS.RemoveAll(toRemove)
hugofs.Destination().RemoveAll(toRemove)
} else if err == nil {
// If file still exists, sync it
logger.Println("Syncing", relPath, "to", publishDir)
@@ -939,7 +942,7 @@ func isThemeVsHugoVersionMismatch() (mismatch bool, requiredMinVersion string) {
themeDir := helpers.GetThemeDir()
fs := hugofs.SourceFs
fs := hugofs.Source()
path := filepath.Join(themeDir, "theme.toml")
exists, err := helpers.Exists(path, fs)