resource/scss: Add IncludePaths config option

Takes paths relative to the current working dir.

Fixes #4921
This commit is contained in:
Bjørn Erik Pedersen 2018-07-20 15:02:35 +02:00
parent f01505c910
commit 166483fe12
7 changed files with 100 additions and 21 deletions

View file

@ -244,8 +244,7 @@ func (d *SourceFilesystem) RealDirs(from string) []string {
var dirnames []string var dirnames []string
for _, dir := range d.Dirnames { for _, dir := range d.Dirnames {
dirname := filepath.Join(dir, from) dirname := filepath.Join(dir, from)
if _, err := d.SourceFs.Stat(dirname); err == nil {
if _, err := hugofs.Os.Stat(dirname); err == nil {
dirnames = append(dirnames, dirname) dirnames = append(dirnames, dirname)
} }
} }

View file

@ -90,8 +90,9 @@ func TestPageBundlerCaptureSymlinks(t *testing.T) {
} }
assert := require.New(t) assert := require.New(t)
ps, workDir := newTestBundleSymbolicSources(t) ps, clean, workDir := newTestBundleSymbolicSources(t)
sourceSpec := source.NewSourceSpec(ps, ps.BaseFs.Content.Fs) sourceSpec := source.NewSourceSpec(ps, ps.BaseFs.Content.Fs)
defer clean()
fileStore := &storeFilenames{} fileStore := &storeFilenames{}
logger := loggers.NewErrorLogger() logger := loggers.NewErrorLogger()

View file

@ -14,13 +14,10 @@
package hugolib package hugolib
import ( import (
"io/ioutil"
"github.com/gohugoio/hugo/common/loggers" "github.com/gohugoio/hugo/common/loggers"
"os" "os"
"runtime" "runtime"
"strings"
"testing" "testing"
"github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/helpers"
@ -325,7 +322,9 @@ func TestPageBundlerSiteWitSymbolicLinksInContent(t *testing.T) {
} }
assert := require.New(t) assert := require.New(t)
ps, workDir := newTestBundleSymbolicSources(t) ps, clean, workDir := newTestBundleSymbolicSources(t)
defer clean()
cfg := ps.Cfg cfg := ps.Cfg
fs := ps.Fs fs := ps.Fs
@ -667,7 +666,7 @@ TheContent.
return fs, cfg return fs, cfg
} }
func newTestBundleSymbolicSources(t *testing.T) (*helpers.PathSpec, string) { func newTestBundleSymbolicSources(t *testing.T) (*helpers.PathSpec, func(), string) {
assert := require.New(t) assert := require.New(t)
// We need to use the OS fs for this. // We need to use the OS fs for this.
cfg := viper.New() cfg := viper.New()
@ -675,13 +674,8 @@ func newTestBundleSymbolicSources(t *testing.T) (*helpers.PathSpec, string) {
fs.Destination = &afero.MemMapFs{} fs.Destination = &afero.MemMapFs{}
loadDefaultSettingsFor(cfg) 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" contentDir := "base"
cfg.Set("workingDir", workDir) cfg.Set("workingDir", workDir)
@ -753,5 +747,5 @@ TheContent.
ps, _ := helpers.NewPathSpec(fs, cfg) ps, _ := helpers.NewPathSpec(fs, cfg)
return ps, workDir return ps, clean, workDir
} }

View file

@ -14,13 +14,71 @@
package hugolib package hugolib
import ( import (
"os"
"path/filepath" "path/filepath"
"testing" "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/common/loggers"
"github.com/gohugoio/hugo/resource/tocss/scss" "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) { func TestResourceChain(t *testing.T) {
t.Parallel() t.Parallel()

View file

@ -1,7 +1,9 @@
package hugolib package hugolib
import ( import (
"io/ioutil"
"path/filepath" "path/filepath"
"runtime"
"testing" "testing"
"bytes" "bytes"
@ -82,6 +84,20 @@ func newTestSitesBuilder(t testing.TB) *sitesBuilder {
return &sitesBuilder{T: t, Fs: fs, configFormat: "toml", dumper: litterOptions} 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 { func (s *sitesBuilder) Running() *sitesBuilder {
s.running = true s.running = true
return s return s

View file

@ -22,12 +22,13 @@ import (
) )
type Client struct { type Client struct {
rs *resource.Spec rs *resource.Spec
sfs *filesystems.SourceFilesystem sfs *filesystems.SourceFilesystem
workFs *filesystems.SourceFilesystem
} }
func New(fs *filesystems.SourceFilesystem, rs *resource.Spec) (*Client, error) { 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 { type Options struct {
@ -38,6 +39,13 @@ type Options struct {
// a Resource with that as a base for RelPermalink etc. // a Resource with that as a base for RelPermalink etc.
TargetPath string 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. // Default is nested.
// One of nested, expanded, compact, compressed. // One of nested, expanded, compact, compressed.
OutputStyle string OutputStyle string

View file

@ -49,10 +49,13 @@ func (t *toCSSTransformation) Transform(ctx *resource.ResourceTransformationCtx)
options := t.options 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)) 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 { if ctx.InMediaType.SubType == media.SASSType.SubType {
options.to.SassSyntax = true options.to.SassSyntax = true
} }