summaryrefslogtreecommitdiffstats
path: root/resource/resource.go
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-03-21 17:21:46 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2018-04-02 08:06:21 +0200
commiteb42774e587816b1fbcafbcea59ed65df703882a (patch)
treefdb62cf17355b47fa485941f3c3fffd604896daa /resource/resource.go
parentf27977809ce5d5dce4db41db6323a4ad1b095985 (diff)
Add support for a content dir set per language
A sample config: ```toml defaultContentLanguage = "en" defaultContentLanguageInSubdir = true [Languages] [Languages.en] weight = 10 title = "In English" languageName = "English" contentDir = "content/english" [Languages.nn] weight = 20 title = "På Norsk" languageName = "Norsk" contentDir = "content/norwegian" ``` The value of `contentDir` can be any valid path, even absolute path references. The only restriction is that the content dirs cannot overlap. The content files will be assigned a language by 1. The placement: `content/norwegian/post/my-post.md` will be read as Norwegian content. 2. The filename: `content/english/post/my-post.nn.md` will be read as Norwegian even if it lives in the English content folder. The content directories will be merged into a big virtual filesystem with one simple rule: The most specific language file will win. This means that if both `content/norwegian/post/my-post.md` and `content/english/post/my-post.nn.md` exists, they will be considered duplicates and the version inside `content/norwegian` will win. Note that translations will be automatically assigned by Hugo by the content file's relative placement, so `content/norwegian/post/my-post.md` will be a translation of `content/english/post/my-post.md`. If this does not work for you, you can connect the translations together by setting a `translationKey` in the content files' front matter. Fixes #4523 Fixes #4552 Fixes #4553
Diffstat (limited to 'resource/resource.go')
-rw-r--r--resource/resource.go84
1 files changed, 50 insertions, 34 deletions
diff --git a/resource/resource.go b/resource/resource.go
index 2732f8b37..7fe3b4ff9 100644
--- a/resource/resource.go
+++ b/resource/resource.go
@@ -23,6 +23,8 @@ import (
"strings"
"sync"
+ "github.com/spf13/afero"
+
"github.com/spf13/cast"
"github.com/gobwas/glob"
@@ -214,6 +216,7 @@ func getGlob(pattern string) (glob.Glob, error) {
type Spec struct {
*helpers.PathSpec
+
mimeTypes media.Types
// Holds default filter settings etc.
@@ -221,7 +224,7 @@ type Spec struct {
imageCache *imageCache
- AbsGenImagePath string
+ GenImagePath string
}
func NewSpec(s *helpers.PathSpec, mimeTypes media.Types) (*Spec, error) {
@@ -232,41 +235,44 @@ func NewSpec(s *helpers.PathSpec, mimeTypes media.Types) (*Spec, error) {
}
s.GetLayoutDirPath()
- genImagePath := s.AbsPathify(filepath.Join(s.Cfg.GetString("resourceDir"), "_gen", "images"))
+ genImagePath := filepath.FromSlash("_gen/images")
- return &Spec{AbsGenImagePath: genImagePath, PathSpec: s, imaging: &imaging, mimeTypes: mimeTypes, imageCache: newImageCache(
- s,
- // We're going to write a cache pruning routine later, so make it extremely
- // unlikely that the user shoots him or herself in the foot
- // and this is set to a value that represents data he/she
- // cares about. This should be set in stone once released.
- genImagePath,
- s.AbsPathify(s.Cfg.GetString("publishDir")))}, nil
+ return &Spec{PathSpec: s,
+ GenImagePath: genImagePath,
+ imaging: &imaging, mimeTypes: mimeTypes, imageCache: newImageCache(
+ s,
+ // We're going to write a cache pruning routine later, so make it extremely
+ // unlikely that the user shoots him or herself in the foot
+ // and this is set to a value that represents data he/she
+ // cares about. This should be set in stone once released.
+ genImagePath,
+ )}, nil
}
func (r *Spec) NewResourceFromFile(
targetPathBuilder func(base string) string,
- absPublishDir string,
file source.File, relTargetFilename string) (Resource, error) {
- return r.newResource(targetPathBuilder, absPublishDir, file.Filename(), file.FileInfo(), relTargetFilename)
+ return r.newResource(targetPathBuilder, file.Filename(), file.FileInfo(), relTargetFilename)
}
func (r *Spec) NewResourceFromFilename(
targetPathBuilder func(base string) string,
- absPublishDir,
absSourceFilename, relTargetFilename string) (Resource, error) {
- fi, err := r.Fs.Source.Stat(absSourceFilename)
+ fi, err := r.sourceFs().Stat(absSourceFilename)
if err != nil {
return nil, err
}
- return r.newResource(targetPathBuilder, absPublishDir, absSourceFilename, fi, relTargetFilename)
+ return r.newResource(targetPathBuilder, absSourceFilename, fi, relTargetFilename)
+}
+
+func (r *Spec) sourceFs() afero.Fs {
+ return r.PathSpec.BaseFs.ContentFs
}
func (r *Spec) newResource(
targetPathBuilder func(base string) string,
- absPublishDir,
absSourceFilename string, fi os.FileInfo, relTargetFilename string) (Resource, error) {
var mimeType string
@@ -283,7 +289,7 @@ func (r *Spec) newResource(
}
}
- gr := r.newGenericResource(targetPathBuilder, fi, absPublishDir, absSourceFilename, relTargetFilename, mimeType)
+ gr := r.newGenericResource(targetPathBuilder, fi, absSourceFilename, relTargetFilename, mimeType)
if mimeType == "image" {
ext := strings.ToLower(helpers.Ext(absSourceFilename))
@@ -295,9 +301,9 @@ func (r *Spec) newResource(
return gr, nil
}
- f, err := r.Fs.Source.Open(absSourceFilename)
+ f, err := gr.sourceFs().Open(absSourceFilename)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("failed to open image source file: %s", err)
}
defer f.Close()
@@ -369,15 +375,30 @@ type genericResource struct {
params map[string]interface{}
// Absolute filename to the source, including any content folder path.
- absSourceFilename string
- absPublishDir string
- resourceType string
- osFileInfo os.FileInfo
+ // Note that this is absolute in relation to the filesystem it is stored in.
+ // It can be a base path filesystem, and then this filename will not match
+ // the path to the file on the real filesystem.
+ sourceFilename string
+
+ // This may be set to tell us to look in another filesystem for this resource.
+ // We, by default, use the sourceFs filesystem in the spec below.
+ overriddenSourceFs afero.Fs
+
+ spec *Spec
+
+ resourceType string
+ osFileInfo os.FileInfo
- spec *Spec
targetPathBuilder func(rel string) string
}
+func (l *genericResource) sourceFs() afero.Fs {
+ if l.overriddenSourceFs != nil {
+ return l.overriddenSourceFs
+ }
+ return l.spec.sourceFs()
+}
+
func (l *genericResource) Permalink() string {
return l.spec.PermalinkForBaseURL(l.relPermalinkForRel(l.relTargetPath.path(), false), l.spec.BaseURL.String())
}
@@ -455,19 +476,16 @@ func (l *genericResource) ResourceType() string {
}
func (l *genericResource) AbsSourceFilename() string {
- return l.absSourceFilename
+ return l.sourceFilename
}
func (l *genericResource) Publish() error {
- f, err := l.spec.Fs.Source.Open(l.AbsSourceFilename())
+ f, err := l.sourceFs().Open(l.AbsSourceFilename())
if err != nil {
return err
}
defer f.Close()
-
- target := filepath.Join(l.absPublishDir, l.target())
-
- return helpers.WriteToDisk(target, f, l.spec.Fs.Destination)
+ return helpers.WriteToDisk(l.target(), f, l.spec.BaseFs.PublishFs)
}
const counterPlaceHolder = ":counter"
@@ -574,8 +592,7 @@ func (l *genericResource) target() string {
func (r *Spec) newGenericResource(
targetPathBuilder func(base string) string,
osFileInfo os.FileInfo,
- absPublishDir,
- absSourceFilename,
+ sourceFilename,
baseFilename,
resourceType string) *genericResource {
@@ -587,8 +604,7 @@ func (r *Spec) newGenericResource(
return &genericResource{
targetPathBuilder: targetPathBuilder,
osFileInfo: osFileInfo,
- absPublishDir: absPublishDir,
- absSourceFilename: absSourceFilename,
+ sourceFilename: sourceFilename,
relTargetPath: dirFile{dir: fpath, file: fname},
resourceType: resourceType,
spec: r,