summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--commands/gendoc.go6
-rw-r--r--commands/genman.go6
-rw-r--r--commands/hugo.go37
-rw-r--r--commands/import_jekyll.go10
-rw-r--r--commands/new.go26
-rw-r--r--commands/new_test.go31
-rw-r--r--commands/server.go6
-rw-r--r--create/content_test.go12
-rw-r--r--docs/content/templates/functions.md8
-rw-r--r--helpers/pygments.go4
-rw-r--r--hugofs/fs.go83
-rw-r--r--hugofs/fs_test.go72
-rw-r--r--hugolib/handler_test.go5
-rw-r--r--hugolib/menu_test.go5
-rw-r--r--hugolib/page.go6
-rw-r--r--hugolib/robotstxt_test.go18
-rw-r--r--hugolib/rss_test.go7
-rw-r--r--hugolib/shortcode_test.go2
-rw-r--r--hugolib/site.go4
-rw-r--r--hugolib/site_test.go37
-rw-r--r--hugolib/site_url_test.go9
-rw-r--r--hugolib/sitemap_test.go7
-rw-r--r--source/filesystem.go4
-rw-r--r--target/file.go4
-rw-r--r--target/htmlredirect.go4
-rw-r--r--target/page.go4
-rw-r--r--tpl/template.go14
-rw-r--r--tpl/template_funcs.go35
-rw-r--r--tpl/template_funcs_test.go64
-rw-r--r--tpl/template_resources.go10
-rw-r--r--tpl/template_resources_test.go4
-rw-r--r--tpl/template_test.go8
32 files changed, 400 insertions, 152 deletions
diff --git a/commands/gendoc.go b/commands/gendoc.go
index 0f65e7dc9..046d3839c 100644
--- a/commands/gendoc.go
+++ b/commands/gendoc.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2016 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.
@@ -51,9 +51,9 @@ for rendering in Hugo.`,
if !strings.HasSuffix(gendocdir, helpers.FilePathSeparator) {
gendocdir += helpers.FilePathSeparator
}
- if found, _ := helpers.Exists(gendocdir, hugofs.OsFs); !found {
+ if found, _ := helpers.Exists(gendocdir, hugofs.Os()); !found {
jww.FEEDBACK.Println("Directory", gendocdir, "does not exist, creating...")
- hugofs.OsFs.MkdirAll(gendocdir, 0777)
+ hugofs.Os().MkdirAll(gendocdir, 0777)
}
now := time.Now().Format(time.RFC3339)
prepender := func(filename string) string {
diff --git a/commands/genman.go b/commands/genman.go
index e12d02773..d1f54ae31 100644
--- a/commands/genman.go
+++ b/commands/genman.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2016 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.
@@ -41,9 +41,9 @@ in the "man" directory under the current directory.`,
if !strings.HasSuffix(genmandir, helpers.FilePathSeparator) {
genmandir += helpers.FilePathSeparator
}
- if found, _ := helpers.Exists(genmandir, hugofs.OsFs); !found {
+ if found, _ := helpers.Exists(genmandir, hugofs.Os()); !found {
jww.FEEDBACK.Println("Directory", genmandir, "does not exist, creating...")
- hugofs.OsFs.MkdirAll(genmandir, 0777)
+ hugofs.Os().MkdirAll(genmandir, 0777)
}
cmd.Root().DisableAutoGenTag = true
diff --git a/commands/hugo.go b/commands/hugo.go
index 19fcb57f7..131879ce9 100644
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -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)
diff --git a/commands/import_jekyll.go b/commands/import_jekyll.go
index 26020b0f9..20356f1e1 100644
--- a/commands/import_jekyll.go
+++ b/commands/import_jekyll.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2016 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.
@@ -124,7 +124,7 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
return convertJekyllPost(path, relPath, targetDir, draft)
}
- err = helpers.SymbolicWalk(hugofs.OsFs, jekyllRoot, callback)
+ err = helpers.SymbolicWalk(hugofs.Os(), jekyllRoot, callback)
if err != nil {
return err
@@ -139,7 +139,7 @@ func importFromJekyll(cmd *cobra.Command, args []string) error {
// TODO: Consider calling doNewSite() instead?
func createSiteFromJekyll(jekyllRoot, targetDir string, force bool) error {
- fs := hugofs.SourceFs
+ fs := hugofs.Source()
if exists, _ := helpers.Exists(targetDir, fs); exists {
if isDir, _ := helpers.IsDir(targetDir, fs); !isDir {
return errors.New("Target path \"" + targetDir + "\" already exists but not a directory")
@@ -187,7 +187,7 @@ func createSiteFromJekyll(jekyllRoot, targetDir string, force bool) error {
}
func loadJekyllConfig(jekyllRoot string) map[string]interface{} {
- fs := hugofs.SourceFs
+ fs := hugofs.Source()
path := filepath.Join(jekyllRoot, "_config.yml")
exists, err := helpers.Exists(path, fs)
@@ -252,7 +252,7 @@ func createConfigFromJekyll(inpath string, kind string, jekyllConfig map[string]
return err
}
- err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), hugofs.SourceFs)
+ err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), hugofs.Source())
if err != nil {
return
}
diff --git a/commands/new.go b/commands/new.go
index 4fc000319..c3f04f471 100644
--- a/commands/new.go
+++ b/commands/new.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2016 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.
@@ -110,7 +110,7 @@ func NewContent(cmd *cobra.Command, args []string) error {
kind = contentType
}
- return create.NewContent(hugofs.SourceFs, kind, createpath)
+ return create.NewContent(hugofs.Source(), kind, createpath)
}
func doNewSite(basepath string, force bool) error {
@@ -123,12 +123,12 @@ func doNewSite(basepath string, force bool) error {
filepath.Join(basepath, "themes"),
}
- if exists, _ := helpers.Exists(basepath, hugofs.SourceFs); exists {
- if isDir, _ := helpers.IsDir(basepath, hugofs.SourceFs); !isDir {
+ if exists, _ := helpers.Exists(basepath, hugofs.Source()); exists {
+ if isDir, _ := helpers.IsDir(basepath, hugofs.Source()); !isDir {
return errors.New(basepath + " already exists but not a directory")
}
- isEmpty, _ := helpers.IsEmpty(basepath, hugofs.SourceFs)
+ isEmpty, _ := helpers.IsEmpty(basepath, hugofs.Source())
switch {
case !isEmpty && !force:
@@ -137,7 +137,7 @@ func doNewSite(basepath string, force bool) error {
case !isEmpty && force:
all := append(dirs, filepath.Join(basepath, "config."+configFormat))
for _, path := range all {
- if exists, _ := helpers.Exists(path, hugofs.SourceFs); exists {
+ if exists, _ := helpers.Exists(path, hugofs.Source()); exists {
return errors.New(path + " already exists")
}
}
@@ -145,7 +145,7 @@ func doNewSite(basepath string, force bool) error {
}
for _, dir := range dirs {
- hugofs.SourceFs.MkdirAll(dir, 0777)
+ hugofs.Source().MkdirAll(dir, 0777)
}
createConfig(basepath, configFormat)
@@ -185,7 +185,7 @@ func NewTheme(cmd *cobra.Command, args []string) error {
createpath := helpers.AbsPathify(filepath.Join(viper.GetString("themesDir"), args[0]))
jww.INFO.Println("creating theme at", createpath)
- if x, _ := helpers.Exists(createpath, hugofs.SourceFs); x {
+ if x, _ := helpers.Exists(createpath, hugofs.Source()); x {
return newUserError(createpath, "already exists")
}
@@ -204,7 +204,7 @@ func NewTheme(cmd *cobra.Command, args []string) error {
archDefault := []byte("+++\n+++\n")
- err := helpers.WriteToDisk(filepath.Join(createpath, "archetypes", "default.md"), bytes.NewReader(archDefault), hugofs.SourceFs)
+ err := helpers.WriteToDisk(filepath.Join(createpath, "archetypes", "default.md"), bytes.NewReader(archDefault), hugofs.Source())
if err != nil {
return err
}
@@ -234,7 +234,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`)
- err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE.md"), bytes.NewReader(by), hugofs.SourceFs)
+ err = helpers.WriteToDisk(filepath.Join(createpath, "LICENSE.md"), bytes.NewReader(by), hugofs.Source())
if err != nil {
return err
}
@@ -256,7 +256,7 @@ func mkdir(x ...string) {
func touchFile(x ...string) {
inpath := filepath.Join(x...)
mkdir(filepath.Dir(inpath))
- err := helpers.WriteToDisk(inpath, bytes.NewReader([]byte{}), hugofs.SourceFs)
+ err := helpers.WriteToDisk(inpath, bytes.NewReader([]byte{}), hugofs.Source())
if err != nil {
jww.FATAL.Fatalln(err)
}
@@ -287,7 +287,7 @@ min_version = 0.15
repo = ""
`)
- err = helpers.WriteToDisk(filepath.Join(inpath, "theme.toml"), bytes.NewReader(by), hugofs.SourceFs)
+ err = helpers.WriteToDisk(filepath.Join(inpath, "theme.toml"), bytes.NewReader(by), hugofs.Source())
if err != nil {
return
}
@@ -321,7 +321,7 @@ func createConfig(inpath string, kind string) (err error) {
return err
}
- err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), hugofs.SourceFs)
+ err = helpers.WriteToDisk(filepath.Join(inpath, "config."+kind), bytes.NewReader(by), hugofs.Source())
if err != nil {
return
}
diff --git a/commands/new_test.go b/commands/new_test.go
index e74e9cfcc..5991e1813 100644
--- a/commands/new_test.go
+++ b/commands/new_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2016 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.
@@ -18,7 +18,6 @@ import (
"path/filepath"
"testing"
- "github.com/spf13/afero"
"github.com/spf13/hugo/hugofs"
"github.com/stretchr/testify/assert"
)
@@ -41,14 +40,14 @@ func checkNewSiteInited(basepath string, t *testing.T) {
}
for _, path := range paths {
- _, err := hugofs.SourceFs.Stat(path)
+ _, err := hugofs.Source().Stat(path)
assert.Nil(t, err)
}
}
func TestDoNewSite(t *testing.T) {
basepath := filepath.Join(os.TempDir(), "blog")
- hugofs.SourceFs = new(afero.MemMapFs)
+ hugofs.InitMemFs()
err := doNewSite(basepath, false)
assert.Nil(t, err)
@@ -57,17 +56,17 @@ func TestDoNewSite(t *testing.T) {
func TestDoNewSite_noerror_base_exists_but_empty(t *testing.T) {
basepath := filepath.Join(os.TempDir(), "blog")
- hugofs.SourceFs = new(afero.MemMapFs)
- hugofs.SourceFs.MkdirAll(basepath, 777)
+ hugofs.InitMemFs()
+ hugofs.Source().MkdirAll(basepath, 777)
err := doNewSite(basepath, false)
assert.Nil(t, err)
}
func TestDoNewSite_error_base_exists(t *testing.T) {
basepath := filepath.Join(os.TempDir(), "blog")
- hugofs.SourceFs = new(afero.MemMapFs)
- hugofs.SourceFs.MkdirAll(basepath, 777)
- hugofs.SourceFs.Create(filepath.Join(basepath, "foo"))
+ hugofs.InitMemFs()
+ hugofs.Source().MkdirAll(basepath, 777)
+ hugofs.Source().Create(filepath.Join(basepath, "foo"))
// Since the directory already exists and isn't empty, expect an error
err := doNewSite(basepath, false)
assert.NotNil(t, err)
@@ -75,8 +74,8 @@ func TestDoNewSite_error_base_exists(t *testing.T) {
func TestDoNewSite_force_empty_dir(t *testing.T) {
basepath := filepath.Join(os.TempDir(), "blog")
- hugofs.SourceFs = new(afero.MemMapFs)
- hugofs.SourceFs.MkdirAll(basepath, 777)
+ hugofs.InitMemFs()
+ hugofs.Source().MkdirAll(basepath, 777)
err := doNewSite(basepath, true)
assert.Nil(t, err)
@@ -86,8 +85,8 @@ func TestDoNewSite_force_empty_dir(t *testing.T) {
func TestDoNewSite_error_force_dir_inside_exists(t *testing.T) {
basepath := filepath.Join(os.TempDir(), "blog")
contentPath := filepath.Join(basepath, "content")
- hugofs.SourceFs = new(afero.MemMapFs)
- hugofs.SourceFs.MkdirAll(contentPath, 777)
+ hugofs.InitMemFs()
+ hugofs.Source().MkdirAll(contentPath, 777)
err := doNewSite(basepath, true)
assert.NotNil(t, err)
}
@@ -95,9 +94,9 @@ func TestDoNewSite_error_force_dir_inside_exists(t *testing.T) {
func TestDoNewSite_error_force_config_inside_exists(t *testing.T) {
basepath := filepath.Join(os.TempDir(), "blog")
configPath := filepath.Join(basepath, "config.toml")
- hugofs.SourceFs = new(afero.MemMapFs)
- hugofs.SourceFs.MkdirAll(basepath, 777)
- hugofs.SourceFs.Create(configPath)
+ hugofs.InitMemFs()
+ hugofs.Source().MkdirAll(basepath, 777)
+ hugofs.Source().Create(configPath)
err := doNewSite(basepath, true)
assert.NotNil(t, err)
}
diff --git a/commands/server.go b/commands/server.go
index 124541b90..345d2dec6 100644
--- a/commands/server.go
+++ b/commands/server.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2016 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.
@@ -152,7 +152,7 @@ func server(cmd *cobra.Command, args []string) error {
// Hugo writes the output to memory instead of the disk
if !renderToDisk {
- hugofs.DestinationFS = new(afero.MemMapFs)
+ hugofs.SetDestination(new(afero.MemMapFs))
// Rendering to memoryFS, publish to Root regardless of publishDir.
viper.Set("PublishDir", "/")
}
@@ -191,7 +191,7 @@ func serve(port int) {
jww.FEEDBACK.Println("Serving pages from memory")
}
- httpFs := afero.NewHttpFs(hugofs.DestinationFS)
+ httpFs := afero.NewHttpFs(hugofs.Destination())
fs := filesOnlyFs{httpFs.Dir(helpers.AbsPathify(viper.GetString("PublishDir")))}
fileserver := http.FileServer(fs)
diff --git a/create/content_test.go b/create/content_test.go
index f0b3de1a0..0ccbd03ea 100644
--- a/create/content_test.go
+++ b/create/content_test.go
@@ -44,19 +44,19 @@ func TestNewContent(t *testing.T) {
}
for i, c := range cases {
- err = create.NewContent(hugofs.SourceFs, c.kind, c.path)
+ err = create.NewContent(hugofs.Source(), c.kind, c.path)
if err != nil {
t.Errorf("[%d] NewContent: %s", i, err)
}
fname := filepath.Join(os.TempDir(), "content", filepath.FromSlash(c.path))
- _, err = hugofs.SourceFs.Stat(fname)
+ _, err = hugofs.Source().Stat(fname)
if err != nil {
t.Errorf("[%d] Stat: %s", i, err)
}
for _, v := range c.resultStrings {
- found, err := afero.FileContainsBytes(hugofs.SourceFs, fname, []byte(v))
+ found, err := afero.FileContainsBytes(hugofs.Source(), fname, []byte(v))
if err != nil {
t.Errorf("[%d] FileContainsBytes: %s", i, err)
}
@@ -77,7 +77,7 @@ func initViper() {
}
func initFs() error {
- hugofs.SourceFs = new(afero.MemMapFs)
+ hugofs.SetSource(new(afero.MemMapFs))
perm := os.FileMode(0755)
var err error
@@ -89,7 +89,7 @@ func initFs() error {
}
for _, dir := range dirs {
dir = filepath.Join(os.TempDir(), dir)
- err = hugofs.SourceFs.Mkdir(dir, perm)
+ err = hugofs.Source().Mkdir(dir, perm)
if err != nil {
return err
}
@@ -109,7 +109,7 @@ func initFs() error {
content: "+++\n+++\n",
},
} {
- f, err := hugofs.SourceFs.Create(v.path)
+ f, err := hugofs.Source().Create(v.path)
if err != nil {
return err
}
diff --git a/docs/content/templates/functions.md b/docs/content/templates/functions.md
index b271e33e1..fe0f2e251 100644
--- a/docs/content/templates/functions.md
+++ b/docs/content/templates/functions.md
@@ -83,7 +83,7 @@ e.g. Pass into "foo.html" a map with the keys "important, content"
or create a map on the fly to pass into
{{partial "foo" (dict "important" "Smiles" "content" "You should do more")}}
-
+
### slice
@@ -336,6 +336,12 @@ e.g.
{{ .Content }}
{{ end }}
+## Files
+### readFile
+Reads a file from disk and converts it into a string. Note that the filename must be relative to the current project working dir.
+ So, if you have a file with the name `README.txt` in the root of your project with the content `Hugo Rocks!`:
+
+ `{{readFile "README.txt"}}` → `"Hugo Rocks!"`
## Math
diff --git a/helpers/pygments.go b/helpers/pygments.go
index fe14ad49f..637f61b19 100644
--- a/helpers/pygments.go
+++ b/helpers/pygments.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2016 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.
@@ -60,7 +60,7 @@ func Highlight(code, lang, optsStr string) string {
io.WriteString(hash, lang)
io.WriteString(hash, options)
- fs := hugofs.OsFs
+ fs := hugofs.Os()
cacheDir := viper.GetString("CacheDir")
var cachefile string
diff --git a/hugofs/fs.go b/hugofs/fs.go
index 7807bf935..a3cb55ea1 100644
--- a/hugofs/fs.go
+++ b/hugofs/fs.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Hugo Authors. All rights reserved.
+// Copyright 2016 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.
@@ -13,8 +13,81 @@
package hugofs
-import "github.com/spf13/afero"
+import (
+ "github.com/spf13/afero"
+ "github.com/spf13/viper"
+)
-var SourceFs afero.Fs = new(afero.OsFs)
-var DestinationFS afero.Fs = new(afero.OsFs)
-var OsFs afero.Fs = new(afero.OsFs)
+var (
+ sourceFs afero.Fs
+ destinationFs afero.Fs
+ osFs afero.Fs = &afero.OsFs{}
+ workingDirFs *afero.BasePathFs
+)
+
+// Source returns Hugo's source file system.
+func Source() afero.Fs {
+ return sourceFs
+}
+
+// SetSource sets Hugo's source file system
+// and re-initializes dependent file systems.
+func SetSource(fs afero.Fs) {
+ sourceFs = fs
+ initSourceDependencies()
+}
+
+// Destination returns Hugo's destionation file system.
+func Destination() afero.Fs {
+ return destinationFs
+}
+
+// SetDestination sets Hugo's destionation file system
+func SetDestination(fs afero.Fs) {
+ destinationFs = fs
+}
+
+// Os returns an OS file system.
+func Os() afero.Fs {
+ return osFs
+}
+
+// WorkingDir returns a read-only file system
+// restricted to the project working dir.
+func WorkingDir() *afero.BasePathFs {
+ return workingDirFs
+}
+
+// InitFs initializes with the OS file system
+// as source and destination file systems.
+func InitDefaultFs() {
+ InitFs(&afero.OsFs{})
+}
+
+// InitMemFs initializes with a MemMapFs as source and destination file systems.
+// Useful for testing.
+func InitMemFs() {
+ InitFs(&afero.MemMapFs{})
+}
+
+// InitFs initializes with the given file system
+// as source and destination file systems.
+func InitFs(fs afero.Fs) {
+ sourceFs = fs
+ destinationFs = fs
+
+ initSourceDependencies()
+}