summaryrefslogtreecommitdiffstats
path: root/resource
diff options
context:
space:
mode:
Diffstat (limited to 'resource')
-rw-r--r--resource/image.go20
-rw-r--r--resource/image_cache.go2
-rw-r--r--resource/resource.go94
-rw-r--r--resource/resource_test.go2
-rw-r--r--resource/transform.go4
5 files changed, 86 insertions, 36 deletions
diff --git a/resource/image.go b/resource/image.go
index 57da4f93d..fd8aea376 100644
--- a/resource/image.go
+++ b/resource/image.go
@@ -268,7 +268,7 @@ func (i *Image) doWithImageConfig(action, spec string, f func(src image.Image, c
ci.config = image.Config{Width: b.Max.X, Height: b.Max.Y}
ci.configLoaded = true
- return ci, i.encodeToDestinations(converted, conf, resourceCacheFilename, ci.targetFilename())
+ return ci, i.encodeToDestinations(converted, conf, resourceCacheFilename, ci.targetFilenames()...)
})
}
@@ -447,13 +447,21 @@ func (i *Image) decodeSource() (image.Image, error) {
func (i *Image) copyToDestination(src string) error {
var res error
i.copyToDestinationInit.Do(func() {
- target := i.targetFilename()
+ targetFilenames := i.targetFilenames()
+ var changedFilenames []string
// Fast path:
// This is a processed version of the original.
// If it exists on destination with the same filename and file size, it is
// the same file, so no need to transfer it again.
- if fi, err := i.spec.BaseFs.PublishFs.Stat(target); err == nil && fi.Size() == i.osFileInfo.Size() {
+ for _, targetFilename := range targetFilenames {
+ if fi, err := i.spec.BaseFs.PublishFs.Stat(targetFilename); err == nil && fi.Size() == i.osFileInfo.Size() {
+ continue
+ }
+ changedFilenames = append(changedFilenames, targetFilename)
+ }
+
+ if len(changedFilenames) == 0 {
return
}
@@ -464,7 +472,7 @@ func (i *Image) copyToDestination(src string) error {
}
defer in.Close()
- out, err := helpers.OpenFileForWriting(i.spec.BaseFs.PublishFs, target)
+ out, err := helpers.OpenFilesForWriting(i.spec.BaseFs.PublishFs, changedFilenames...)
if err != nil {
res = err
@@ -485,9 +493,9 @@ func (i *Image) copyToDestination(src string) error {
return nil
}
-func (i *Image) encodeToDestinations(img image.Image, conf imageConfig, resourceCacheFilename, targetFilename string) error {
+func (i *Image) encodeToDestinations(img image.Image, conf imageConfig, resourceCacheFilename string, targetFilenames ...string) error {
- file1, err := helpers.OpenFileForWriting(i.spec.BaseFs.PublishFs, targetFilename)
+ file1, err := helpers.OpenFilesForWriting(i.spec.BaseFs.PublishFs, targetFilenames...)
if err != nil {
return err
}
diff --git a/resource/image_cache.go b/resource/image_cache.go
index fb2996c9d..470c24c99 100644
--- a/resource/image_cache.go
+++ b/resource/image_cache.go
@@ -69,7 +69,7 @@ func (c *imageCache) getOrCreate(
parent *Image, conf imageConfig, create func(resourceCacheFilename string) (*Image, error)) (*Image, error) {
relTarget := parent.relTargetPathFromConfig(conf)
- key := parent.relTargetPathForRel(relTarget.path(), false)
+ key := parent.relTargetPathForRel(relTarget.path(), false, false)
// First check the in-memory store, then the disk.
c.mu.RLock()
diff --git a/resource/resource.go b/resource/resource.go
index a1e29c52f..01e66078b 100644
--- a/resource/resource.go
+++ b/resource/resource.go
@@ -16,6 +16,7 @@ package resource
import (
"errors"
"fmt"
+ "io"
"io/ioutil"
"mime"
"os"
@@ -62,8 +63,8 @@ type Source interface {
type permalinker interface {
relPermalinkFor(target string) string
permalinkFor(target string) string
- relTargetPathFor(target string) string
- relTargetPath() string
+ relTargetPathsFor(target string) []string
+ relTargetPaths() []string
targetPath() string
}
@@ -332,10 +333,12 @@ type ResourceSourceDescriptor struct {
// Typically the language code if this resource should be published to its sub-folder.
URLBase string
- // Any base path prepended to the target path. This will also typically be the
+ // Any base paths prepended to the target path. This will also typically be the
// language code, but setting it here means that it should not have any effect on
// the permalink.
- TargetPathBase string
+ // This may be several values. In multihost mode we may publish the same resources to
+ // multiple targets.
+ TargetBasePaths []string
// Delay publishing until either Permalink or RelPermalink is called. Maybe never.
LazyPublish bool
@@ -373,6 +376,11 @@ func (r *Spec) newResourceForFs(sourceFs afero.Fs, fd ResourceSourceDescriptor)
fd.RelTargetFilename = fd.Filename()
}
+ if len(fd.TargetBasePaths) == 0 {
+ // If not set, we publish the same resource to all hosts.
+ fd.TargetBasePaths = r.MultihostTargetBasePaths
+ }
+
return r.newResource(sourceFs, fd)
}
@@ -418,7 +426,7 @@ func (r *Spec) newResource(sourceFs afero.Fs, fd ResourceSourceDescriptor) (Reso
fd.LazyPublish,
fd.OpenReadSeekCloser,
fd.URLBase,
- fd.TargetPathBase,
+ fd.TargetBasePaths,
fd.TargetPathBuilder,
fi,
sourceFilename,
@@ -505,8 +513,8 @@ type resourcePathDescriptor struct {
baseURLDir string
// This will normally be the same as above, but this will only apply to publishing
- // of resources.
- baseTargetPathDir string
+ // of resources. It may be mulltiple values when in multihost mode.
+ baseTargetPathDirs []string
// baseOffset is set when the output format's path has a offset, e.g. for AMP.
baseOffset string
@@ -688,12 +696,12 @@ func (l *genericResource) permalinkFor(target string) string {
return l.spec.PermalinkForBaseURL(l.relPermalinkForRel(target), l.spec.BaseURL.HostURL())
}
-func (l *genericResource) relTargetPathFor(target string) string {
- return l.relTargetPathForRel(target, false)
+func (l *genericResource) relTargetPathsFor(target string) []string {
+ return l.relTargetPathsForRel(target)
}
-func (l *genericResource) relTargetPath() string {
- return l.relTargetPathForRel(l.targetPath(), false)
+func (l *genericResource) relTargetPaths() []string {
+ return l.relTargetPathsForRel(l.targetPath())
}
func (l *genericResource) Name() string {
@@ -731,11 +739,34 @@ func (l *genericResource) updateParams(params map[string]interface{}) {
}
func (l *genericResource) relPermalinkForRel(rel string) string {
- return l.spec.PathSpec.URLizeFilename(l.relTargetPathForRel(rel, true))
+ return l.spec.PathSpec.URLizeFilename(l.relTargetPathForRel(rel, false, true))
+}
+
+func (l *genericResource) relTargetPathsForRel(rel string) []string {
+ if len(l.baseTargetPathDirs) == 0 {
+ return []string{l.relTargetPathForRelAndBasePath(rel, "", false)}
+ }
+
+ var targetPaths = make([]string, len(l.baseTargetPathDirs))
+ for i, dir := range l.baseTargetPathDirs {
+ targetPaths[i] = l.relTargetPathForRelAndBasePath(rel, dir, false)
+ }
+ return targetPaths
}
-func (l *genericResource) relTargetPathForRel(rel string, isURL bool) string {
+func (l *genericResource) relTargetPathForRel(rel string, addBaseTargetPath, isURL bool) string {
+ if addBaseTargetPath && len(l.baseTargetPathDirs) > 1 {
+ panic("multiple baseTargetPathDirs")
+ }
+ var basePath string
+ if addBaseTargetPath && len(l.baseTargetPathDirs) > 0 {
+ basePath = l.baseTargetPathDirs[0]
+ }
+ return l.relTargetPathForRelAndBasePath(rel, basePath, isURL)
+}
+
+func (l *genericResource) relTargetPathForRelAndBasePath(rel, basePath string, isURL bool) string {
if l.targetPathBuilder != nil {
rel = l.targetPathBuilder(rel)
}
@@ -744,8 +775,8 @@ func (l *genericResource) relTargetPathForRel(rel string, isURL bool) string {
rel = path.Join(l.baseURLDir, rel)
}
- if !isURL && l.baseTargetPathDir != "" {
- rel = path.Join(l.baseTargetPathDir, rel)
+ if basePath != "" {
+ rel = path.Join(basePath, rel)
}
if l.baseOffset != "" {
@@ -772,12 +803,19 @@ func (l *genericResource) String() string {
}
func (l *genericResource) Publish() error {
- f, err := l.ReadSeekCloser()
+ fr, err := l.ReadSeekCloser()
if err != nil {
return err
}
- defer f.Close()
- return helpers.WriteToDisk(l.targetFilename(), f, l.spec.BaseFs.PublishFs)
+ defer fr.Close()
+ fw, err := helpers.OpenFilesForWriting(l.spec.BaseFs.PublishFs, l.targetFilenames()...)
+ if err != nil {
+ return err
+ }
+ defer fw.Close()
+
+ _, err = io.Copy(fw, fr)
+ return err
}
// Path is stored with Unix style slashes.
@@ -785,8 +823,12 @@ func (l *genericResource) targetPath() string {
return l.relTargetDirFile.path()
}
-func (l *genericResource) targetFilename() string {
- return filepath.Clean(l.relTargetPath())
+func (l *genericResource) targetFilenames() []string {
+ paths := l.relTargetPaths()
+ for i, p := range paths {
+ paths[i] = filepath.Clean(p)
+ }
+ return paths
}
// TODO(bep) clean up below
@@ -801,7 +843,7 @@ func (r *Spec) newGenericResource(sourceFs afero.Fs,
false,
nil,
"",
- "",
+ nil,
targetPathBuilder,
osFileInfo,
sourceFilename,
@@ -816,7 +858,7 @@ func (r *Spec) newGenericResourceWithBase(
lazyPublish bool,
openReadSeekerCloser OpenReadSeekCloser,
urlBaseDir string,
- targetPathBaseDir string,
+ targetPathBaseDirs []string,
targetPathBuilder func(base string) string,
osFileInfo os.FileInfo,
sourceFilename,
@@ -836,10 +878,10 @@ func (r *Spec) newGenericResourceWithBase(
}
pathDescriptor := resourcePathDescriptor{
- baseURLDir: urlBaseDir,
- baseTargetPathDir: targetPathBaseDir,
- targetPathBuilder: targetPathBuilder,
- relTargetDirFile: dirFile{dir: fpath, file: fname},
+ baseURLDir: urlBaseDir,
+ baseTargetPathDirs: targetPathBaseDirs,
+ targetPathBuilder: targetPathBuilder,
+ relTargetDirFile: dirFile{dir: fpath, file: fname},
}
var po *publishOnce
diff --git a/resource/resource_test.go b/resource/resource_test.go
index e699e6f3f..b76f0a604 100644
--- a/resource/resource_test.go
+++ b/resource/resource_test.go
@@ -93,7 +93,7 @@ func TestNewResourceFromFilenameSubPathInBaseURL(t *testing.T) {
assert.Equal("/docs/a/b/logo.png", r.RelPermalink())
assert.Equal("https://example.com/docs/a/b/logo.png", r.Permalink())
img := r.(*Image)
- assert.Equal(filepath.FromSlash("/a/b/logo.png"), img.targetFilename())
+ assert.Equal(filepath.FromSlash("/a/b/logo.png"), img.targetFilenames()[0])
}
diff --git a/resource/transform.go b/resource/transform.go
index c61a9771e..dd9cd143b 100644
--- a/resource/transform.go
+++ b/resource/transform.go
@@ -267,7 +267,7 @@ func (r *transformedResource) initContent() error {
func (r *transformedResource) transform(setContent bool) (err error) {
openPublishFileForWriting := func(relTargetPath string) (io.WriteCloser, error) {
- return helpers.OpenFileForWriting(r.cache.rs.PublishFs, r.linker.relTargetPathFor(relTargetPath))
+ return helpers.OpenFilesForWriting(r.cache.rs.PublishFs, r.linker.relTargetPathsFor(relTargetPath)...)
}
// This can be the last resource in a chain.
@@ -299,7 +299,7 @@ func (r *transformedResource) transform(setContent bool) (err error) {
key = key + "_" + v.transformation.Key().key()
case permalinker:
r.linker = v
- p := v.relTargetPath()
+ p := v.targetPath()
if p == "" {
panic("target path needed for key creation")
}