Merge branch 'feature/file' into develop
/ docker (push) Successful in 1m11s
Details
/ docker (push) Successful in 1m11s
Details
This commit is contained in:
commit
6080cce45f
|
@ -0,0 +1,102 @@
|
|||
package domain
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
language language.Tag
|
||||
baseFileName string
|
||||
contentBaseName string
|
||||
dir string
|
||||
ext string
|
||||
filename string
|
||||
logicalName string
|
||||
path string
|
||||
translationBaseName string
|
||||
uniqueId string
|
||||
}
|
||||
|
||||
func NewFile(path string) File {
|
||||
out := File{
|
||||
language: language.Tag{},
|
||||
baseFileName: "",
|
||||
contentBaseName: "",
|
||||
dir: filepath.Dir(path) + "/",
|
||||
ext: strings.TrimPrefix(filepath.Ext(path), "."),
|
||||
filename: path,
|
||||
logicalName: filepath.Base(path),
|
||||
path: path,
|
||||
translationBaseName: "",
|
||||
uniqueId: "",
|
||||
}
|
||||
out.path, _ = filepath.Abs(path)
|
||||
out.baseFileName = strings.TrimSuffix(out.logicalName, filepath.Ext(out.logicalName))
|
||||
|
||||
parts := strings.Split(out.baseFileName, ".")
|
||||
out.language = language.Make(parts[len(parts)-1])
|
||||
out.translationBaseName = strings.Join(parts[:len(parts)-1], ".")
|
||||
out.contentBaseName = out.translationBaseName
|
||||
|
||||
switch out.translationBaseName {
|
||||
default:
|
||||
out.contentBaseName = out.translationBaseName
|
||||
case "_index", "index":
|
||||
out.contentBaseName = filepath.Base(out.dir)
|
||||
}
|
||||
|
||||
hash := md5.New()
|
||||
_, _ = hash.Write([]byte(out.path))
|
||||
out.uniqueId = string(hash.Sum(nil))
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// BaseFileName returns file name without extention.
|
||||
func (f File) BaseFileName() string {
|
||||
return f.baseFileName
|
||||
}
|
||||
|
||||
func (f File) ContentBaseName() string {
|
||||
return f.contentBaseName
|
||||
}
|
||||
|
||||
// Dir returns directory path.
|
||||
func (f File) Dir() string {
|
||||
return f.dir
|
||||
}
|
||||
|
||||
// Ext returns file extention.
|
||||
func (f File) Ext() string {
|
||||
return f.ext
|
||||
}
|
||||
|
||||
func (f File) Filename() string {
|
||||
return f.filename
|
||||
}
|
||||
|
||||
// Language returns language.Tag of current file based on his suffix before
|
||||
// extention.
|
||||
func (f File) Language() language.Tag {
|
||||
return f.language
|
||||
}
|
||||
|
||||
func (f File) LogicalName() string {
|
||||
return f.logicalName
|
||||
}
|
||||
|
||||
func (f File) Path() string {
|
||||
return f.path
|
||||
}
|
||||
|
||||
func (f File) TranslationBaseName() string {
|
||||
return f.translationBaseName
|
||||
}
|
||||
|
||||
func (f File) UniqueID() string {
|
||||
return f.uniqueId
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
package domain_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"source.toby3d.me/toby3d/home/internal/domain"
|
||||
)
|
||||
|
||||
var (
|
||||
testRegularFile string = filepath.Join("news", "a.en.md")
|
||||
testLeafFile string = filepath.Join("news", "b", "index.en.md")
|
||||
testBranchFile string = filepath.Join("news", "_index.en.md")
|
||||
)
|
||||
|
||||
func TestFile_BaseFileName(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
input, expect string
|
||||
}{
|
||||
"regular": {testRegularFile, "a.en"},
|
||||
"leaf": {testLeafFile, "index.en"},
|
||||
"branch": {testBranchFile, "_index.en"},
|
||||
} {
|
||||
name, tc := name, tc
|
||||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if actual := domain.NewFile(tc.input).BaseFileName(); actual != tc.expect {
|
||||
t.Errorf("BaseFileName() = '%s', want '%s'", actual, tc.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFile_ContentBaseName(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
input, expect string
|
||||
}{
|
||||
"regular": {testRegularFile, "a"},
|
||||
"leaf": {testLeafFile, "b"},
|
||||
"branch": {testBranchFile, "news"},
|
||||
} {
|
||||
name, tc := name, tc
|
||||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if actual := domain.NewFile(tc.input).ContentBaseName(); actual != tc.expect {
|
||||
t.Errorf("ContentBaseName() = '%s', want '%s'", actual, tc.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFile_Dir(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
input, expect string
|
||||
}{
|
||||
"regular": {testRegularFile, "news/"},
|
||||
"leaf": {testLeafFile, "news/b/"},
|
||||
"branch": {testBranchFile, "news/"},
|
||||
} {
|
||||
name, tc := name, tc
|
||||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if actual := domain.NewFile(tc.input).Dir(); actual != tc.expect {
|
||||
t.Errorf("Dir() = '%s', want '%s'", actual, tc.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFile_Ext(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const expect string = "md"
|
||||
|
||||
for name, input := range map[string]string{
|
||||
"regular": testRegularFile,
|
||||
"leaf": testLeafFile,
|
||||
"branch": testBranchFile,
|
||||
} {
|
||||
name, input := name, input
|
||||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if actual := domain.NewFile(input).Ext(); actual != expect {
|
||||
t.Errorf("Ext() = '%s', want '%s'", actual, expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFile_Language(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var expect language.Tag = language.English
|
||||
|
||||
for name, input := range map[string]string{
|
||||
"regular": testRegularFile,
|
||||
"leaf": testLeafFile,
|
||||
"branch": testBranchFile,
|
||||
} {
|
||||
name, input := name, input
|
||||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if actual := domain.NewFile(input).Language(); actual != expect {
|
||||
t.Errorf("Language() = '%s', want '%s'", actual, expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFile_LogicalName(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
input, expect string
|
||||
}{
|
||||
"regular": {testRegularFile, "a.en.md"},
|
||||
"leaf": {testLeafFile, "index.en.md"},
|
||||
"branch": {testBranchFile, "_index.en.md"},
|
||||
} {
|
||||
name, tc := name, tc
|
||||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if actual := domain.NewFile(tc.input).LogicalName(); actual != tc.expect {
|
||||
t.Errorf("LogicalName() = '%s', want '%s'", actual, tc.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFile_TranslationBaseName(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
input, expect string
|
||||
}{
|
||||
"regular": {testRegularFile, "a"},
|
||||
"leaf": {testLeafFile, "index"},
|
||||
"branch": {testBranchFile, "_index"},
|
||||
} {
|
||||
name, tc := name, tc
|
||||
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if actual := domain.NewFile(tc.input).TranslationBaseName(); actual != tc.expect {
|
||||
t.Errorf("TranslationBaseName() = '%s', want '%s'", actual, tc.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -5,9 +5,13 @@ import "golang.org/x/text/language"
|
|||
type Page struct {
|
||||
Language language.Tag
|
||||
Params map[string]any
|
||||
File File
|
||||
Description string
|
||||
Title string
|
||||
Content []byte
|
||||
Resources Resources
|
||||
IsHome bool
|
||||
}
|
||||
|
||||
func (p Page) IsHome() bool {
|
||||
return p.File.dir == "./" && p.File.translationBaseName == "index"
|
||||
}
|
||||
|
|
|
@ -10,8 +10,9 @@ import (
|
|||
type Site struct {
|
||||
Language language.Tag
|
||||
BaseURL *url.URL
|
||||
TimeZone *time.Location
|
||||
Params map[string]any
|
||||
TimeZone *time.Location
|
||||
File File
|
||||
Title string
|
||||
Resources Resources
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"strings"
|
||||
|
||||
"github.com/adrg/frontmatter"
|
||||
"golang.org/x/text/language"
|
||||
|
@ -45,11 +44,11 @@ func (repo *fileSystemPageRepository) Get(ctx context.Context, lang language.Tag
|
|||
ext = "." + base.String() + ext
|
||||
}
|
||||
|
||||
index := p + ext
|
||||
target := p + ext
|
||||
|
||||
f, err := repo.dir.Open(index)
|
||||
f, err := repo.dir.Open(target)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot open '%s' page file: %w", index, err)
|
||||
return nil, fmt.Errorf("cannot open '%s' page file: %w", target, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
|
@ -61,12 +60,12 @@ func (repo *fileSystemPageRepository) Get(ctx context.Context, lang language.Tag
|
|||
}
|
||||
|
||||
return &domain.Page{
|
||||
File: domain.NewFile(target),
|
||||
Language: lang,
|
||||
Title: data.Title,
|
||||
Content: data.Content,
|
||||
Description: data.Description,
|
||||
Params: data.Params,
|
||||
Resources: make([]*domain.Resource, 0),
|
||||
IsHome: strings.HasPrefix(index, "index.") && strings.HasSuffix(index, ".md"),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ func (ucase *pageUseCase) Do(ctx context.Context, lang language.Tag, p string) (
|
|||
continue
|
||||
}
|
||||
|
||||
out.Resources, _, _ = ucase.statics.Fetch(ctx, path.Dir(targets[i]))
|
||||
out.Resources, _, _ = ucase.statics.Fetch(ctx, out.File.Dir()+"*")
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ func (repo *fileSystemSiteRepository) Get(ctx context.Context, lang language.Tag
|
|||
}
|
||||
|
||||
return &domain.Site{
|
||||
File: domain.NewFile(target),
|
||||
Language: lang,
|
||||
Title: data.Title,
|
||||
BaseURL: data.BaseURL.URL,
|
||||
|
|
|
@ -29,7 +29,7 @@ func (ucase *siteUseCase) Do(ctx context.Context, lang language.Tag) (*domain.Si
|
|||
return nil, fmt.Errorf("cannot find base site data: %w", err)
|
||||
}
|
||||
|
||||
out.Resources, _, _ = ucase.statics.Fetch(ctx, ".")
|
||||
out.Resources, _, _ = ucase.statics.Fetch(ctx, "")
|
||||
|
||||
sub, err := ucase.sites.Get(ctx, lang)
|
||||
if err != nil {
|
||||
|
|
|
@ -12,7 +12,7 @@ type (
|
|||
Get(ctx context.Context, path string) (*domain.Resource, error)
|
||||
|
||||
// Fetch returns all resources from dir recursevly.
|
||||
Fetch(ctx context.Context, dir string) (domain.Resources, int, error)
|
||||
Fetch(ctx context.Context, pattern string) (domain.Resources, int, error)
|
||||
}
|
||||
|
||||
dummyRepository struct{}
|
||||
|
@ -26,6 +26,6 @@ func (dummyRepository) Get(ctx context.Context, path string) (*domain.Resource,
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (dummyRepository) Fetch(ctx context.Context, dir string) (domain.Resources, int, error) {
|
||||
func (dummyRepository) Fetch(ctx context.Context, pattern string) (domain.Resources, int, error) {
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
|
|
@ -46,28 +46,40 @@ func (repo *fileServerStaticRepository) Get(ctx context.Context, p string) (*dom
|
|||
return domain.NewResource(info.ModTime(), content, p), nil
|
||||
}
|
||||
|
||||
func (repo *fileServerStaticRepository) Fetch(ctx context.Context, dir string) (domain.Resources, int, error) {
|
||||
targets := make([]string, 0)
|
||||
if err := fs.WalkDir(repo.root, dir, func(path string, de fs.DirEntry, err error) error {
|
||||
func (repo *fileServerStaticRepository) Fetch(ctx context.Context, pattern string) (domain.Resources, int, error) {
|
||||
var (
|
||||
err error
|
||||
matches []string
|
||||
)
|
||||
|
||||
if pattern != "" {
|
||||
if matches, err = fs.Glob(repo.root, pattern); err != nil {
|
||||
return nil, 0, fmt.Errorf("cannot match any static by pattern '%s': %w", pattern, err)
|
||||
}
|
||||
} else {
|
||||
if err = fs.WalkDir(repo.root, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("received error while walking through '%s': %w", dir, err)
|
||||
return fmt.Errorf("catched error while walk: %w", err)
|
||||
}
|
||||
|
||||
if de.IsDir() {
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
targets = append(targets, path)
|
||||
matches = append(matches, path)
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, 0, fmt.Errorf("cannot read directory on path '%s': %w", dir, err)
|
||||
return nil, 0, fmt.Errorf("cannot walk through static directories: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
out := make(domain.Resources, len(targets))
|
||||
out := make(domain.Resources, 0, len(matches))
|
||||
|
||||
for i := range targets {
|
||||
out[i], _ = repo.Get(ctx, targets[i])
|
||||
for i := range matches {
|
||||
if r, err := repo.Get(ctx, matches[i]); err == nil {
|
||||
out = append(out, r)
|
||||
}
|
||||
}
|
||||
|
||||
return out, len(out), nil
|
||||
|
|
Loading…
Reference in New Issue