From 93ca7c9e958e34469a337e4efcc7c75774ec50fd Mon Sep 17 00:00:00 2001 From: Bjørn Erik Pedersen Date: Sun, 5 Feb 2017 10:20:06 +0700 Subject: all: Refactor to nonglobal Viper, i18n etc. This is a final rewrite that removes all the global state in Hugo, which also enables the use if `t.Parallel` in tests. Updates #2701 Fixes #3016 --- source/content_directory_test.go | 13 ++++++++----- source/file.go | 27 +++++++++++++++++++-------- source/file_test.go | 26 +++++++++++++++++++------- source/filesystem.go | 31 ++++++++++++++----------------- source/filesystem_test.go | 15 +++++++-------- source/inmemory.go | 14 -------------- 6 files changed, 67 insertions(+), 59 deletions(-) (limited to 'source') diff --git a/source/content_directory_test.go b/source/content_directory_test.go index 107ca9837..48c3ae903 100644 --- a/source/content_directory_test.go +++ b/source/content_directory_test.go @@ -14,13 +14,13 @@ package source import ( - "github.com/spf13/viper" "testing" + + "github.com/spf13/hugo/hugofs" + "github.com/spf13/viper" ) func TestIgnoreDotFilesAndDirectories(t *testing.T) { - viper.Reset() - defer viper.Reset() tests := []struct { path string @@ -49,9 +49,12 @@ func TestIgnoreDotFilesAndDirectories(t *testing.T) { for _, test := range tests { - viper.Set("ignoreFiles", test.ignoreFilesRegexpes) + v := viper.New() + v.Set("ignoreFiles", test.ignoreFilesRegexpes) + + s := NewSourceSpec(v, hugofs.NewMem(v)) - if ignored := isNonProcessablePath(test.path); test.ignore != ignored { + if ignored := s.isNonProcessablePath(test.path); test.ignore != ignored { t.Errorf("File not ignored. Expected: %t, got: %t", test.ignore, ignored) } } diff --git a/source/file.go b/source/file.go index 18ed9d6f9..1dff9ac0b 100644 --- a/source/file.go +++ b/source/file.go @@ -18,10 +18,21 @@ import ( "path/filepath" "strings" + "github.com/spf13/hugo/hugofs" + + "github.com/spf13/hugo/config" "github.com/spf13/hugo/helpers" - "github.com/spf13/viper" ) +type SourceSpec struct { + Cfg config.Provider + Fs *hugofs.Fs +} + +func NewSourceSpec(cfg config.Provider, fs *hugofs.Fs) SourceSpec { + return SourceSpec{Cfg: cfg, Fs: fs} +} + // File represents a source content file. // All paths are relative from the source directory base type File struct { @@ -110,15 +121,15 @@ func (f *File) Path() string { // NewFileWithContents creates a new File pointer with the given relative path and // content. The language defaults to "en". -func NewFileWithContents(relpath string, content io.Reader) *File { - file := NewFile(relpath) +func (sp SourceSpec) NewFileWithContents(relpath string, content io.Reader) *File { + file := sp.NewFile(relpath) file.Contents = content file.lang = "en" return file } // NewFile creates a new File pointer with the given relative path. -func NewFile(relpath string) *File { +func (sp SourceSpec) NewFile(relpath string) *File { f := &File{ relpath: relpath, } @@ -128,8 +139,8 @@ func NewFile(relpath string) *File { f.baseName = helpers.Filename(f.LogicalName()) lang := strings.TrimPrefix(filepath.Ext(f.baseName), ".") - if _, ok := viper.GetStringMap("languages")[lang]; lang == "" || !ok { - f.lang = viper.GetString("defaultContentLanguage") + if _, ok := sp.Cfg.GetStringMap("languages")[lang]; lang == "" || !ok { + f.lang = sp.Cfg.GetString("defaultContentLanguage") f.translationBaseName = f.baseName } else { f.lang = lang @@ -144,11 +155,11 @@ func NewFile(relpath string) *File { // NewFileFromAbs creates a new File pointer with the given full file path path and // content. -func NewFileFromAbs(base, fullpath string, content io.Reader) (f *File, err error) { +func (sp SourceSpec) NewFileFromAbs(base, fullpath string, content io.Reader) (f *File, err error) { var name string if name, err = helpers.GetRelativePath(fullpath, base); err != nil { return nil, err } - return NewFileWithContents(name, content), nil + return sp.NewFileWithContents(name, content), nil } diff --git a/source/file_test.go b/source/file_test.go index 517474012..d87a154f5 100644 --- a/source/file_test.go +++ b/source/file_test.go @@ -18,28 +18,40 @@ import ( "strings" "testing" + "github.com/spf13/hugo/hugofs" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" ) func TestFileUniqueID(t *testing.T) { + ss := newTestSourceSpec() + f1 := File{uniqueID: "123"} - f2 := NewFile("a") + f2 := ss.NewFile("a") assert.Equal(t, "123", f1.UniqueID()) assert.Equal(t, "0cc175b9c0f1b6a831c399e269772661", f2.UniqueID()) - f3 := NewFile(filepath.FromSlash("test1/index.md")) - f4 := NewFile(filepath.FromSlash("test2/index.md")) + f3 := ss.NewFile(filepath.FromSlash("test1/index.md")) + f4 := ss.NewFile(filepath.FromSlash("test2/index.md")) assert.NotEqual(t, f3.UniqueID(), f4.UniqueID()) } func TestFileString(t *testing.T) { - assert.Equal(t, "abc", NewFileWithContents("a", strings.NewReader("abc")).String()) - assert.Equal(t, "", NewFile("a").String()) + ss := newTestSourceSpec() + assert.Equal(t, "abc", ss.NewFileWithContents("a", strings.NewReader("abc")).String()) + assert.Equal(t, "", ss.NewFile("a").String()) } func TestFileBytes(t *testing.T) { - assert.Equal(t, []byte("abc"), NewFileWithContents("a", strings.NewReader("abc")).Bytes()) - assert.Equal(t, []byte(""), NewFile("a").Bytes()) + ss := newTestSourceSpec() + assert.Equal(t, []byte("abc"), ss.NewFileWithContents("a", strings.NewReader("abc")).Bytes()) + assert.Equal(t, []byte(""), ss.NewFile("a").Bytes()) +} + +func newTestSourceSpec() SourceSpec { + v := viper.New() + return SourceSpec{Fs: hugofs.NewMem(v), Cfg: v} } diff --git a/source/filesystem.go b/source/filesystem.go index 6089824a0..a13128144 100644 --- a/source/filesystem.go +++ b/source/filesystem.go @@ -21,13 +21,10 @@ import ( "runtime" "strings" - "github.com/spf13/hugo/hugofs" - "golang.org/x/text/unicode/norm" - - "github.com/spf13/viper" - + "github.com/spf13/cast" "github.com/spf13/hugo/helpers" jww "github.com/spf13/jwalterweatherman" + "golang.org/x/text/unicode/norm" ) type Input interface { @@ -39,11 +36,11 @@ type Filesystem struct { Base string AvoidPaths []string - fs *hugofs.Fs + SourceSpec } -func NewFilesystem(fs *hugofs.Fs, base string, avoidPaths ...string) *Filesystem { - return &Filesystem{fs: fs, Base: base, AvoidPaths: avoidPaths} +func (sp SourceSpec) NewFilesystem(base string, avoidPaths ...string) *Filesystem { + return &Filesystem{SourceSpec: sp, Base: base, AvoidPaths: avoidPaths} } func (f *Filesystem) FilesByExts(exts ...string) []*File { @@ -79,7 +76,7 @@ func (f *Filesystem) add(name string, reader io.Reader) (err error) { name = norm.NFC.String(name) } - file, err = NewFileFromAbs(f.Base, name, reader) + file, err = f.SourceSpec.NewFileFromAbs(f.Base, name, reader) if err == nil { f.files = append(f.files, file) @@ -98,7 +95,7 @@ func (f *Filesystem) captureFiles() { return err } if b { - rd, err := NewLazyFileReader(f.fs.Source, filePath) + rd, err := NewLazyFileReader(f.Fs.Source, filePath) if err != nil { return err } @@ -107,10 +104,10 @@ func (f *Filesystem) captureFiles() { return err } - if f.fs == nil { + if f.Fs == nil { panic("Must have a fs") } - err := helpers.SymbolicWalk(f.fs.Source, f.Base, walker) + err := helpers.SymbolicWalk(f.Fs.Source, f.Base, walker) if err != nil { jww.ERROR.Println(err) @@ -128,7 +125,7 @@ func (f *Filesystem) shouldRead(filePath string, fi os.FileInfo) (bool, error) { jww.ERROR.Printf("Cannot read symbolic link '%s', error was: %s", filePath, err) return false, nil } - linkfi, err := f.fs.Source.Stat(link) + linkfi, err := f.Fs.Source.Stat(link) if err != nil { jww.ERROR.Printf("Cannot stat '%s', error was: %s", link, err) return false, nil @@ -140,13 +137,13 @@ func (f *Filesystem) shouldRead(filePath string, fi os.FileInfo) (bool, error) { } if fi.IsDir() { - if f.avoid(filePath) || isNonProcessablePath(filePath) { + if f.avoid(filePath) || f.isNonProcessablePath(filePath) { return false, filepath.SkipDir } return false, nil } - if isNonProcessablePath(filePath) { + if f.isNonProcessablePath(filePath) { return false, nil } return true, nil @@ -161,14 +158,14 @@ func (f *Filesystem) avoid(filePath string) bool { return false } -func isNonProcessablePath(filePath string) bool { +func (s SourceSpec) isNonProcessablePath(filePath string) bool { base := filepath.Base(filePath) if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "#") || strings.HasSuffix(base, "~") { return true } - ignoreFiles := viper.GetStringSlice("ignoreFiles") + ignoreFiles := cast.ToStringSlice(s.Cfg.Get("ignoreFiles")) if len(ignoreFiles) > 0 { for _, ignorePattern := range ignoreFiles { match, err := regexp.MatchString(ignorePattern, filePath) diff --git a/source/filesystem_test.go b/source/filesystem_test.go index 598a1b81d..90512ce3f 100644 --- a/source/filesystem_test.go +++ b/source/filesystem_test.go @@ -19,12 +19,11 @@ import ( "runtime" "strings" "testing" - - "github.com/spf13/hugo/hugofs" ) func TestEmptySourceFilesystem(t *testing.T) { - src := NewFilesystem(hugofs.NewMem(), "Empty") + ss := newTestSourceSpec() + src := ss.NewFilesystem("Empty") if len(src.Files()) != 0 { t.Errorf("new filesystem should contain 0 files.") } @@ -39,12 +38,12 @@ type TestPath struct { } func TestAddFile(t *testing.T) { - fs := hugofs.NewMem() + ss := newTestSourceSpec() tests := platformPaths for _, test := range tests { base := platformBase - srcDefault := NewFilesystem(fs, "") - srcWithBase := NewFilesystem(fs, base) + srcDefault := ss.NewFilesystem("") + srcWithBase := ss.NewFilesystem(base) for _, src := range []*Filesystem{srcDefault, srcWithBase} { @@ -100,10 +99,10 @@ func TestUnicodeNorm(t *testing.T) { {NFC: "é", NFD: "\x65\xcc\x81"}, } - fs := hugofs.NewMem() + ss := newTestSourceSpec() for _, path := range paths { - src := NewFilesystem(fs, "") + src := ss.NewFilesystem("") _ = src.add(path.NFD, strings.NewReader("")) f := src.Files()[0] if f.BaseFileName() != path.NFC { diff --git a/source/inmemory.go b/source/inmemory.go index 9d3af5194..431236a56 100644 --- a/source/inmemory.go +++ b/source/inmemory.go @@ -13,8 +13,6 @@ package source -import "bytes" - type ByteSource struct { Name string Content []byte @@ -23,15 +21,3 @@ type ByteSource struct { func (b *ByteSource) String() string { return b.Name + " " + string(b.Content) } - -type InMemorySource struct { - ByteSource []ByteSource -} - -func (i *InMemorySource) Files() (files []*File) { - files = make([]*File, len(i.ByteSource)) - for i, fake := range i.ByteSource { - files[i] = NewFileWithContents(fake.Name, bytes.NewReader(fake.Content)) - } - return -} -- cgit v1.2.3