mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
resource/scss: Add IncludePaths config option
Takes paths relative to the current working dir. Fixes #4921
This commit is contained in:
parent
f01505c910
commit
166483fe12
7 changed files with 100 additions and 21 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue