shithub: hugo

Download patch

ref: 166483fe1227b0c59c6b4d88cfdfaf7d7b0d79c5
parent: f01505c910a325acc18742ac6b3637aa01975e37
author: Bjørn Erik Pedersen <[email protected]>
date: Fri Jul 20 11:02:35 EDT 2018

resource/scss: Add IncludePaths config option

Takes paths relative to the current working dir.

Fixes #4921

--- a/hugolib/filesystems/basefs.go
+++ b/hugolib/filesystems/basefs.go
@@ -244,8 +244,7 @@
 	var dirnames []string
 	for _, dir := range d.Dirnames {
 		dirname := filepath.Join(dir, from)
-
-		if _, err := hugofs.Os.Stat(dirname); err == nil {
+		if _, err := d.SourceFs.Stat(dirname); err == nil {
 			dirnames = append(dirnames, dirname)
 		}
 	}
--- a/hugolib/page_bundler_capture_test.go
+++ b/hugolib/page_bundler_capture_test.go
@@ -90,8 +90,9 @@
 	}
 
 	assert := require.New(t)
-	ps, workDir := newTestBundleSymbolicSources(t)
+	ps, clean, workDir := newTestBundleSymbolicSources(t)
 	sourceSpec := source.NewSourceSpec(ps, ps.BaseFs.Content.Fs)
+	defer clean()
 
 	fileStore := &storeFilenames{}
 	logger := loggers.NewErrorLogger()
--- a/hugolib/page_bundler_test.go
+++ b/hugolib/page_bundler_test.go
@@ -14,13 +14,10 @@
 package hugolib
 
 import (
-	"io/ioutil"
-
 	"github.com/gohugoio/hugo/common/loggers"
 
 	"os"
 	"runtime"
-	"strings"
 	"testing"
 
 	"github.com/gohugoio/hugo/helpers"
@@ -325,7 +322,9 @@
 	}
 
 	assert := require.New(t)
-	ps, workDir := newTestBundleSymbolicSources(t)
+	ps, clean, workDir := newTestBundleSymbolicSources(t)
+	defer clean()
+
 	cfg := ps.Cfg
 	fs := ps.Fs
 
@@ -667,7 +666,7 @@
 	return fs, cfg
 }
 
-func newTestBundleSymbolicSources(t *testing.T) (*helpers.PathSpec, string) {
+func newTestBundleSymbolicSources(t *testing.T) (*helpers.PathSpec, func(), string) {
 	assert := require.New(t)
 	// We need to use the OS fs for this.
 	cfg := viper.New()
@@ -675,14 +674,9 @@
 	fs.Destination = &afero.MemMapFs{}
 	loadDefaultSettingsFor(cfg)
 
-	workDir, err := ioutil.TempDir("", "hugosym")
+	workDir, clean, err := createTempDir("hugosym")
+	assert.NoError(err)
 
-	if runtime.GOOS == "darwin" && !strings.HasPrefix(workDir, "/private") {
-		// To get the entry folder in line with the rest. This its a little bit
-		// mysterious, but so be it.
-		workDir = "/private" + workDir
-	}
-
 	contentDir := "base"
 	cfg.Set("workingDir", workDir)
 	cfg.Set("contentDir", contentDir)
@@ -753,5 +747,5 @@
 
 	ps, _ := helpers.NewPathSpec(fs, cfg)
 
-	return ps, workDir
+	return ps, clean, workDir
 }
--- a/hugolib/resource_chain_test.go
+++ b/hugolib/resource_chain_test.go
@@ -14,12 +14,70 @@
 package hugolib
 
 import (
+	"os"
 	"path/filepath"
 	"testing"
 
+	"github.com/spf13/viper"
+
+	"github.com/stretchr/testify/require"
+
+	"github.com/gohugoio/hugo/hugofs"
+
 	"github.com/gohugoio/hugo/common/loggers"
 	"github.com/gohugoio/hugo/resource/tocss/scss"
 )
+
+func TestSCSSWithIncludePaths(t *testing.T) {
+	if !scss.Supports() {
+		t.Skip("Skip SCSS")
+	}
+	assert := require.New(t)
+	workDir, clean, err := createTempDir("hugo-scss-include")
+	assert.NoError(err)
+	defer clean()
+
+	v := viper.New()
+	v.Set("workingDir", workDir)
+	b := newTestSitesBuilder(t).WithLogger(loggers.NewWarningLogger())
+	b.WithViper(v)
+	b.WithWorkingDir(workDir)
+	// Need to use OS fs for this.
+	b.Fs = hugofs.NewDefault(v)
+
+	fooDir := filepath.Join(workDir, "node_modules", "foo")
+	scssDir := filepath.Join(workDir, "assets", "scss")
+	assert.NoError(os.MkdirAll(fooDir, 0777))
+	assert.NoError(os.MkdirAll(filepath.Join(workDir, "content", "sect"), 0777))
+	assert.NoError(os.MkdirAll(filepath.Join(workDir, "data"), 0777))
+	assert.NoError(os.MkdirAll(filepath.Join(workDir, "i18n"), 0777))
+	assert.NoError(os.MkdirAll(filepath.Join(workDir, "layouts", "shortcodes"), 0777))
+	assert.NoError(os.MkdirAll(filepath.Join(workDir, "layouts", "_default"), 0777))
+	assert.NoError(os.MkdirAll(filepath.Join(scssDir), 0777))
+
+	b.WithSourceFile(filepath.Join(fooDir, "_moo.scss"), `
+$moolor: #fff;
+
+moo {
+  color: $moolor;
+}
+`)
+
+	b.WithSourceFile(filepath.Join(scssDir, "main.scss"), `
+@import "moo";
+
+`)
+
+	b.WithTemplatesAdded("index.html", `
+{{ $cssOpts := (dict "includePaths" (slice "node_modules/foo" ) ) }}
+{{ $r := resources.Get "scss/main.scss" |  toCSS $cssOpts  | minify  }}
+T1: {{ $r.Content }}
+`)
+	b.Build(BuildCfg{})
+
+	b.AssertFileContent(filepath.Join(workDir, "public/index.html"), `T1: moo{color:#fff}`)
+
+}
 
 func TestResourceChain(t *testing.T) {
 	t.Parallel()
--- a/hugolib/testhelpers_test.go
+++ b/hugolib/testhelpers_test.go
@@ -1,7 +1,9 @@
 package hugolib
 
 import (
+	"io/ioutil"
 	"path/filepath"
+	"runtime"
 	"testing"
 
 	"bytes"
@@ -80,6 +82,20 @@
 	}
 
 	return &sitesBuilder{T: t, Fs: fs, configFormat: "toml", dumper: litterOptions}
+}
+
+func createTempDir(prefix string) (string, func(), error) {
+	workDir, err := ioutil.TempDir("", prefix)
+	if err != nil {
+		return "", nil, err
+	}
+
+	if runtime.GOOS == "darwin" && !strings.HasPrefix(workDir, "/private") {
+		// To get the entry folder in line with the rest. This its a little bit
+		// mysterious, but so be it.
+		workDir = "/private" + workDir
+	}
+	return workDir, func() { os.RemoveAll(workDir) }, nil
 }
 
 func (s *sitesBuilder) Running() *sitesBuilder {
--- a/resource/tocss/scss/client.go
+++ b/resource/tocss/scss/client.go
@@ -22,12 +22,13 @@
 )
 
 type Client struct {
-	rs  *resource.Spec
-	sfs *filesystems.SourceFilesystem
+	rs     *resource.Spec
+	sfs    *filesystems.SourceFilesystem
+	workFs *filesystems.SourceFilesystem
 }
 
 func New(fs *filesystems.SourceFilesystem, rs *resource.Spec) (*Client, error) {
-	return &Client{sfs: fs, rs: rs}, nil
+	return &Client{sfs: fs, workFs: rs.BaseFs.Work, rs: rs}, nil
 }
 
 type Options struct {
@@ -37,6 +38,13 @@
 	// control this by setting this, e.g. "styles/main.css" will create
 	// a Resource with that as a base for RelPermalink etc.
 	TargetPath string
+
+	// Hugo automatically adds the entry directories (where the main.scss lives)
+	// for project and themes to the list of include paths sent to LibSASS.
+	// Any paths set in this setting will be appended. Note that these will be
+	// treated as relative to the working dir, i.e. no include paths outside the
+	// project/themes.
+	IncludePaths []string
 
 	// Default is nested.
 	// One of nested, expanded, compact, compressed.
--- a/resource/tocss/scss/tocss.go
+++ b/resource/tocss/scss/tocss.go
@@ -49,9 +49,12 @@
 
 	options := t.options
 
-	// We may allow the end user to add IncludePaths later, if we find a use
-	// case for that.
 	options.to.IncludePaths = t.c.sfs.RealDirs(path.Dir(ctx.SourcePath))
+
+	// Append any workDir relative include paths
+	for _, ip := range options.from.IncludePaths {
+		options.to.IncludePaths = append(options.to.IncludePaths, t.c.workFs.RealDirs(filepath.Clean(ip))...)
+	}
 
 	if ctx.InMediaType.SubType == media.SASSType.SubType {
 		options.to.SassSyntax = true