Big refactor of how source files are used. Also added default destination extension option.

This commit is contained in:
spf13
2014-10-16 20:20:09 -04:00
parent 24bbfe7d32
commit 5dfc1dedb8
24 changed files with 646 additions and 465 deletions

114
source/file.go Normal file
View File

@@ -0,0 +1,114 @@
// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Licensed under the Simple Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://opensource.org/licenses/Simple-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package source
import (
"io"
"path"
"path/filepath"
"strings"
"github.com/spf13/hugo/helpers"
)
type File struct {
relpath string // Original Full Path eg. /Users/Home/Hugo/foo.txt
logicalName string // foo.txt
Contents io.Reader
section string // The first directory
dir string // The full directory Path (minus file name)
ext string // Just the ext (eg txt)
uniqueId string // MD5 of the filename
}
func (f *File) UniqueId() string {
if f.uniqueId == "" {
f.uniqueId = helpers.Md5String(f.LogicalName())
}
return f.uniqueId
}
// Filename without extension
func (f *File) BaseFileName() string {
return helpers.Filename(f.LogicalName())
}
func (f *File) Section() string {
if f.section != "" {
return f.section
} else {
f.section = helpers.GuessSection(f.Dir())
return f.section
}
}
func (f *File) LogicalName() string {
if f.logicalName != "" {
return f.logicalName
} else {
_, f.logicalName = path.Split(f.relpath)
return f.logicalName
}
}
//func (f *File) SetDir(dir string) {
//f.dir = dir
//}
func (f *File) Dir() string {
if f.dir != "" {
return f.dir
} else {
f.dir, _ = path.Split(f.relpath)
return f.dir
}
}
func (f *File) Extension() string {
if f.ext != "" {
return f.ext
} else {
f.ext = strings.TrimPrefix(filepath.Ext(f.LogicalName()), ".")
return f.ext
}
}
func (f *File) Ext() string {
return f.Extension()
}
func (f *File) Path() string {
return f.relpath
}
func NewFileWithContents(relpath string, content io.Reader) *File {
file := NewFile(relpath)
file.Contents = content
return file
}
func NewFile(relpath string) *File {
return &File{
relpath: relpath,
}
}
func 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
}

View File

@@ -1,34 +1,56 @@
// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Licensed under the Simple Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://opensource.org/licenses/Simple-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package source
import (
"bytes"
"errors"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"github.com/spf13/hugo/helpers"
)
type Input interface {
Files() []*File
}
type File struct {
name string
LogicalName string
Contents io.Reader
Section string
Dir string
}
type Filesystem struct {
files []*File
Base string
AvoidPaths []string
}
func (f *Filesystem) FilesByExts(exts ...string) []*File {
var newFiles []*File
if len(exts) == 0 {
return f.Files()
}
for _, x := range f.Files() {
for _, e := range exts {
if x.Ext() == strings.TrimPrefix(e, ".") {
newFiles = append(newFiles, x)
}
}
}
return newFiles
}
func (f *Filesystem) Files() []*File {
if len(f.files) < 1 {
f.captureFiles()
@@ -36,47 +58,23 @@ func (f *Filesystem) Files() []*File {
return f.files
}
var errMissingBaseDir = errors.New("source: missing base directory")
func (f *Filesystem) add(name string, reader io.Reader) (err error) {
var file *File
if name, err = f.getRelativePath(name); err != nil {
return err
//if f.Base == "" {
//file = NewFileWithContents(name, reader)
//} else {
file, err = NewFileFromAbs(f.Base, name, reader)
//}
if err == nil {
f.files = append(f.files, file)
}
// section should be the first part of the path
dir, logical := path.Split(name)
parts := strings.Split(dir, "/")
section := parts[0]
if section == "." {
section = ""
}
f.files = append(f.files, &File{
name: name,
LogicalName: logical,
Contents: reader,
Section: section,
Dir: dir,
})
return
return err
}
func (f *Filesystem) getRelativePath(name string) (final string, err error) {
if filepath.IsAbs(name) && f.Base == "" {
return "", errMissingBaseDir
}
name = filepath.Clean(name)
base := filepath.Clean(f.Base)
name, err = filepath.Rel(base, name)
if err != nil {
return "", err
}
name = filepath.ToSlash(name)
return name, nil
return helpers.GetRelativePath(name, f.Base)
}
func (f *Filesystem) captureFiles() {

View File

@@ -32,16 +32,17 @@ func TestAddFile(t *testing.T) {
}
for _, src := range []*Filesystem{srcDefault, srcWithBase} {
p := test.filename
if !filepath.IsAbs(test.filename) {
p = path.Join(src.Base, test.filename)
}
if err := src.add(p, bytes.NewReader([]byte(test.content))); err != nil {
if err == errMissingBaseDir {
if err.Error() == "source: missing base directory" {
continue
}
t.Fatalf("%s add returned and error: %s", p, err)
t.Fatalf("%s add returned an error: %s", p, err)
}
if len(src.Files()) != 1 {
@@ -49,8 +50,8 @@ func TestAddFile(t *testing.T) {
}
f := src.Files()[0]
if f.LogicalName != test.logical {
t.Errorf("Filename (Base: %q) expected: %q, got: %q", src.Base, test.logical, f.LogicalName)
if f.LogicalName() != test.logical {
t.Errorf("Filename (Base: %q) expected: %q, got: %q", src.Base, test.logical, f.LogicalName())
}
b := new(bytes.Buffer)
@@ -59,12 +60,12 @@ func TestAddFile(t *testing.T) {
t.Errorf("File (Base: %q) contents should be %q, got: %q", src.Base, test.content, b.String())
}
if f.Section != test.section {
t.Errorf("File section (Base: %q) expected: %q, got: %q", src.Base, test.section, f.Section)
if f.Section() != test.section {
t.Errorf("File section (Base: %q) expected: %q, got: %q", src.Base, test.section, f.Section())
}
if f.Dir != test.dir {
t.Errorf("Dir path (Base: %q) expected: %q, got: %q", src.Base, test.dir, f.Dir)
if f.Dir() != test.dir {
t.Errorf("Dir path (Base: %q) expected: %q, got: %q", src.Base, test.dir, f.Dir())
}
}
}

View File

@@ -3,17 +3,15 @@ package source
import (
"bytes"
"fmt"
"path"
)
type ByteSource struct {
Name string
Content []byte
Section string
}
func (b *ByteSource) String() string {
return fmt.Sprintf("%s %s %s", b.Name, b.Section, string(b.Content))
return fmt.Sprintf("%s %s", b.Name, string(b.Content))
}
type InMemorySource struct {
@@ -23,12 +21,7 @@ type InMemorySource struct {
func (i *InMemorySource) Files() (files []*File) {
files = make([]*File, len(i.ByteSource))
for i, fake := range i.ByteSource {
files[i] = &File{
LogicalName: fake.Name,
Contents: bytes.NewReader(fake.Content),
Section: fake.Section,
Dir: path.Dir(fake.Name),
}
files[i] = NewFileWithContents(fake.Name, bytes.NewReader(fake.Content))
}
return
}