all repos — homestead @ 58fd23d385300f7faa1ee3bba766a0dd7aae6d93

Code for my website

drop storage interface (only one implementation)

Alin
commit

58fd23d385300f7faa1ee3bba766a0dd7aae6d93

parent

fadcc67ff52629041da2a8013c4fe786c6164cc9

M domain/content/builder/build/main.go → domain/content/builder/build/main.go
@@ -10,7 +10,7 @@ "github.com/ardanlabs/conf/v3"
"alin.ovh/homestead/domain/content/builder" "alin.ovh/homestead/shared/config" - "alin.ovh/homestead/shared/storage/files" + "alin.ovh/homestead/shared/storage" "alin.ovh/homestead/shared/vcs" )
@@ -42,10 +42,10 @@ panic("could not open repository: " + err.Error())
} options.Repo = repo - options.Storage, err = files.NewWriter( + options.Storage, err = storage.NewWriter( options.Destination, log.Named("storage"), - &files.Options{ + &storage.Options{ Compress: options.Compress, }, )
M domain/content/builder/builder.go → domain/content/builder/builder.go
@@ -30,7 +30,7 @@ Source string `conf:"default:.,short:s,flag:src"`
Development bool `conf:"default:false,flag:dev"` VCSRemoteURL config.URL `conf:"default:https://git.alin.ovh/website"` - Storage storage.Writer `conf:"-"` + Storage *storage.Writer `conf:"-"` Repo *vcs.Repository `conf:"-"` }
@@ -40,7 +40,7 @@ return filepath.Join(src, rel)
} } -func copyFile(storage storage.Writer, src string, rel string) error { +func copyFile(storage *storage.Writer, src string, rel string) error { sf, err := os.Open(src) if err != nil { return fault.Wrap(err)
M domain/web/website.go → domain/web/website.go
@@ -23,7 +23,6 @@ "alin.ovh/homestead/shared/events"
"alin.ovh/homestead/shared/file" ihttp "alin.ovh/homestead/shared/http" "alin.ovh/homestead/shared/storage" - "alin.ovh/homestead/shared/storage/files" ) type Options struct {
@@ -46,7 +45,7 @@ config *config.Config
siteSettings *templates.SiteSettings counter analytics.Counter log *log.Logger - reader storage.Reader + reader *storage.Reader identity *identity.Service *server.App }
@@ -140,7 +139,7 @@ }
website.Domain = cfg.BaseURL.Hostname() - website.reader, err = files.NewReader(root, log.Named("reader")) + website.reader, err = storage.NewReader(root, log.Named("reader")) if err != nil { log.Panic("could not create database reader", "error", err) }
M shared/storage/file.go → shared/storage/file.go
@@ -2,10 +2,17 @@ package storage
import ( "errors" + "fmt" + "hash/fnv" + "io" "mime" "os" "path/filepath" + "strings" "time" + + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" ) type File struct {
@@ -21,6 +28,12 @@ }
var ( ErrEncodingNotFound = errors.New("encoding not found") + + encodings = map[string]string{ + "br": ".br", + "gzip": ".gz", + "zstd": ".zstd", + } ) func NewFile(urlPath string, filename string) (*File, error) {
@@ -68,3 +81,69 @@ f.ContentType = mime.TypeByExtension(ext)
return f.ContentType } + +func (r *Reader) OpenFile(path string, filename string) (*File, error) { + file, err := NewFile(path, filename) + if err != nil { + return nil, fault.Wrap(err, fmsg.With("could not init file")) + } + + file.Etag, err = etag(file.Encodings["identity"]) + if err != nil { + return nil, err + } + + for enc, suffix := range encodings { + _, err := os.Stat(filename + suffix) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + continue + } + + return nil, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not stat file %s", filename+suffix)), + ) + } + f, err := os.Open(filename + suffix) + if err != nil { + return nil, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not read file %s", filename+suffix)), + ) + } + file.Encodings[enc] = f + } + + return file, nil +} + +func etag(f io.Reader) (string, error) { + hash := fnv.New64a() + if _, err := io.Copy(hash, f); err != nil { + return "", fault.Wrap(err, fmsg.With("could not hash file")) + } + + return fmt.Sprintf(`W/"%x"`, hash.Sum(nil)), nil +} + +func pathNameToFileName(pathname string) string { + if strings.HasSuffix(pathname, "/") { + pathname += "index.html" + } + + return strings.TrimPrefix(pathname, "/") +} + +func cutSuffix(s, suffix string) string { + out, _ := strings.CutSuffix(s, suffix) + + return out +} + +func fileNameToPathName(filename string) string { + return cutSuffix( + cutSuffix(filename, "index.html"), + ".html", + ) +}
D shared/storage/files/file.go
@@ -1,87 +0,0 @@
-package files - -import ( - "errors" - "fmt" - "hash/fnv" - "io" - "os" - "strings" - - "github.com/Southclaws/fault" - "github.com/Southclaws/fault/fmsg" - - "alin.ovh/homestead/shared/storage" -) - -var encodings = map[string]string{ - "br": ".br", - "gzip": ".gz", - "zstd": ".zstd", -} - -func (r *Reader) OpenFile(path string, filename string) (*storage.File, error) { - file, err := storage.NewFile(path, filename) - if err != nil { - return nil, fault.Wrap(err, fmsg.With("could not init file")) - } - - file.Etag, err = etag(file.Encodings["identity"]) - if err != nil { - return nil, err - } - - for enc, suffix := range encodings { - _, err := os.Stat(filename + suffix) - if err != nil { - if errors.Is(err, os.ErrNotExist) { - continue - } - - return nil, fault.Wrap( - err, - fmsg.With(fmt.Sprintf("could not stat file %s", filename+suffix)), - ) - } - f, err := os.Open(filename + suffix) - if err != nil { - return nil, fault.Wrap( - err, - fmsg.With(fmt.Sprintf("could not read file %s", filename+suffix)), - ) - } - file.Encodings[enc] = f - } - - return file, nil -} - -func etag(f io.Reader) (string, error) { - hash := fnv.New64a() - if _, err := io.Copy(hash, f); err != nil { - return "", fault.Wrap(err, fmsg.With("could not hash file")) - } - - return fmt.Sprintf(`W/"%x"`, hash.Sum(nil)), nil -} - -func pathNameToFileName(pathname string) string { - if strings.HasSuffix(pathname, "/") { - pathname += "index.html" - } - - return strings.TrimPrefix(pathname, "/") -} - -func cutSuffix(s, suffix string) string { - out, _ := strings.CutSuffix(s, suffix) - - return out -} - -func fileNameToPathName(filename string) string { - return cutSuffix( - cutSuffix(filename, "index.html"), - ".html", - ) -}
M shared/storage/files/reader.go → shared/storage/reader.go
@@ -1,4 +1,4 @@
-package files +package storage import ( "fmt"
@@ -9,21 +9,19 @@
"alin.ovh/x/log" "github.com/Southclaws/fault" "github.com/Southclaws/fault/fmsg" - - "alin.ovh/homestead/shared/storage" ) type Reader struct { root string log *log.Logger - files map[string]*storage.File + files map[string]*File } func NewReader(path string, log *log.Logger) (*Reader, error) { r := &Reader{ root: path, log: log, - files: make(map[string]*storage.File), + files: make(map[string]*File), } if err := r.registerContentFiles(); err != nil { return nil, fault.Wrap(err, fmsg.With("registering content files"))
@@ -32,7 +30,7 @@
return r, nil } -func (r *Reader) GetFile(urlPath string) (*storage.File, error) { +func (r *Reader) GetFile(urlPath string) (*File, error) { return r.files[urlPath], nil }
M shared/storage/files/writer.go → shared/storage/writer.go
@@ -1,4 +1,4 @@
-package files +package storage import ( "compress/gzip"
@@ -14,10 +14,9 @@ "github.com/klauspost/compress/zstd"
"alin.ovh/homestead/domain/content" "alin.ovh/homestead/shared/file" - "alin.ovh/homestead/shared/storage" ) -type Files struct { +type Writer struct { outputDirectory string options *Options log *log.Logger
@@ -32,15 +31,15 @@ gzipLevel = 6
brotliLevel = 9 ) -func NewWriter(outputDirectory string, logger *log.Logger, opts *Options) (*Files, error) { - return &Files{ +func NewWriter(outputDirectory string, logger *log.Logger, opts *Options) (*Writer, error) { + return &Writer{ outputDirectory: outputDirectory, options: opts, log: logger, }, nil } -func (f *Files) OpenRead(filename string) (io.ReadCloser, error) { +func (f *Writer) OpenRead(filename string) (io.ReadCloser, error) { file, err := os.Open(f.join(filename)) if err != nil { return nil, fault.Wrap(err)
@@ -49,11 +48,11 @@
return file, nil } -func (f *Files) OpenWrite(filename string) (io.WriteCloser, error) { +func (f *Writer) OpenWrite(filename string) (io.WriteCloser, error) { return openFileWrite(f.join(filename)) } -func (f *Files) WritePost(post *content.Post, wt io.WriterTo) error { +func (f *Writer) WritePost(post *content.Post, wt io.WriterTo) error { fd, err := f.write(post.URL, wt) if err != nil { return err
@@ -75,7 +74,7 @@
return nil } -func (f *Files) Write(pathname string, _ string, wt io.WriterTo) error { +func (f *Writer) Write(pathname string, _ string, wt io.WriterTo) error { fd, err := f.write(pathname, wt) if err != nil { return err
@@ -88,15 +87,15 @@
return nil } -func (f *Files) NewFileFromPost(post *content.Post) *storage.File { - return &storage.File{ +func (f *Writer) NewFileFromPost(post *content.Post) *File { + return &File{ Path: post.URL, FSPath: pathNameToFileName(post.URL), Encodings: map[string]*os.File{}, } } -func (f *Files) CopyFile(file *storage.File, src *os.File) error { +func (f *Writer) CopyFile(file *File, src *os.File) error { dst, err := f.write(file.Path, src) if err != nil { return err
@@ -109,11 +108,11 @@
return nil } -func (f *Files) WriteFile(file *storage.File, wt io.WriterTo) error { +func (f *Writer) WriteFile(file *File, wt io.WriterTo) error { return f.Write(file.Path, file.Title, wt) } -func (f *Files) OpenFileAndVariants(filename string) (file.FileLike, error) { +func (f *Writer) OpenFileAndVariants(filename string) (file.FileLike, error) { if f.options.Compress { return multiOpenFile(f.join(filename)) }
@@ -121,7 +120,7 @@
return openFileWrite(f.join(filename)) } -func (f *Files) Mkdirp(dir string) error { +func (f *Writer) Mkdirp(dir string) error { err := os.MkdirAll(f.join(dir), 0o750) if err != nil { return fault.Wrap(err, fmsg.With("could not create directory"))
@@ -130,7 +129,7 @@
return nil } -func (f *Files) write( +func (f *Writer) write( pathname string, writer io.WriterTo, ) (file.FileLike, error) {
@@ -224,6 +223,6 @@
return file.NewMultiFile(r, gz, br, zst), nil } -func (f *Files) join(filename string) string { +func (f *Writer) join(filename string) string { return filepath.Join(f.outputDirectory, pathNameToFileName(filename)) }
D shared/storage/interface.go
@@ -1,22 +0,0 @@
-package storage - -import ( - "io" - - "alin.ovh/homestead/domain/content" -) - -type Reader interface { - GetFile(path string) (*File, error) - CanonicalisePath(path string) (string, bool) -} - -type Writer interface { - Mkdirp(path string) error - - NewFileFromPost(*content.Post) *File - - Write(string, string, io.WriterTo) error - WritePost(*content.Post, io.WriterTo) error - WriteFile(*File, io.WriterTo) error -}