all repos — homestead @ 4c07535d9120fb999b0c008f1866972865f424f7

Code for my website

replace tozd/errors with Southclaws/fault

Alan Pearce
commit

4c07535d9120fb999b0c008f1866972865f424f7

parent

90a4ac43b915abb7a2949f4b5313b40d705b6071

M .golangci.yaml.golangci.yaml
@@ -24,6 +24,11 @@ settings:
staticcheck: dot-import-whitelist: - "go.alanpearce.eu/gomponents/html" + wrapcheck: + ignore-sigs: + - fault.New( + - fault.Newf( + - fault.Wrap( exclusions: generated: strict warn-unused: true
M cmd/barkeep/main.gocmd/barkeep/main.go
@@ -1,11 +1,11 @@
package main import ( + "errors" "fmt" "os" "github.com/ardanlabs/conf/v3" - "gitlab.com/tozd/go/errors" "go.alanpearce.eu/homestead/internal/publisher" "go.alanpearce.eu/homestead/internal/server"
M cmd/build/main.gocmd/build/main.go
@@ -2,6 +2,7 @@ package main
import ( "database/sql" + "errors" "fmt" "os" "path/filepath"
@@ -16,7 +17,6 @@ "go.alanpearce.eu/homestead/internal/vcs"
"go.alanpearce.eu/x/log" "github.com/ardanlabs/conf/v3" - "gitlab.com/tozd/go/errors" ) const branch = "main"
M go.modgo.mod
@@ -7,6 +7,7 @@
require ( github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c github.com/PuerkitoBio/goquery v1.10.2 + github.com/Southclaws/fault v0.8.1 github.com/adrg/frontmatter v0.2.0 github.com/alanpearce/htmlformat v0.0.0-20250508141223-2478490ea63e github.com/andybalholm/brotli v1.1.1
@@ -27,7 +28,6 @@ github.com/redis/go-redis/v9 v9.7.1
github.com/snabb/sitemap v1.0.4 github.com/stefanfritsch/goldmark-fences v1.0.0 github.com/yuin/goldmark v1.7.8 - gitlab.com/tozd/go/errors v0.10.0 go.alanpearce.eu/gomponents v1.4.0 go.alanpearce.eu/x v0.0.0-20250213214218-1bdfdc914d6c go.hacdias.com/indielib v0.4.3
@@ -136,6 +136,7 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
github.com/vishvananda/netns v0.0.4 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect + gitlab.com/tozd/go/errors v0.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
M go.sumgo.sum
@@ -16,6 +16,8 @@ github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8= github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU= +github.com/Southclaws/fault v0.8.1 h1:mgqqdC6kUBQ6ExMALZ0nNaDfNJD5h2+wq3se5mAyX+8= +github.com/Southclaws/fault v0.8.1/go.mod h1:VUVkAWutC59SL16s6FTqf3I6I2z77RmnaW5XRz4bLOE= github.com/adrg/frontmatter v0.2.0 h1:/DgnNe82o03riBd1S+ZDjd43wAmC6W35q67NHeLkPd4= github.com/adrg/frontmatter v0.2.0/go.mod h1:93rQCj3z3ZlwyxxpQioRKC1wDLto4aXHrbqIsnH9wmE= github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
M gomod2nix.tomlgomod2nix.toml
@@ -22,6 +22,9 @@ hash = "sha256-XlFT3uxgpPYFTND54uO8fH33jtQqAHWa7zrv24nw/PE="
[mod."github.com/PuerkitoBio/goquery"] version = "v1.10.2" hash = "sha256-2h4Ol31ucXHieeZUJq+xi7F5m2FzzsOKRLjUehA5lbE=" + [mod."github.com/Southclaws/fault"] + version = "v0.8.1" + hash = "sha256-yqRVXWyUcknuy3x10MyUnU0iOrsneOMEAoEi2VYwzD4=" [mod."github.com/adrg/frontmatter"] version = "v0.2.0" hash = "sha256-WJsVcdCpkIkjqUz5fJOFStZYwQlrcFzQ6+mZatZiimo="
M internal/atom/atom.gointernal/atom/atom.go
@@ -6,7 +6,7 @@ "encoding/xml"
"net/url" "time" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" "go.alanpearce.eu/homestead/internal/config" )
@@ -14,18 +14,18 @@ func MakeTagURI(config *config.Config, specific string) string {
return "tag:" + config.OriginalDomain + "," + config.DomainStartDate + ":" + specific } -func LinkXSL(w *bytes.Buffer, url string) errors.E { +func LinkXSL(w *bytes.Buffer, url string) error { _, err := w.WriteString(`<?xml-stylesheet href="`) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } err = xml.EscapeText(w, []byte(url)) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } _, err = w.WriteString(`" type="text/xsl"?>`) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } return nil
M internal/builder/builder.gointernal/builder/builder.go
@@ -19,8 +19,9 @@ "go.alanpearce.eu/homestead/internal/vcs"
"go.alanpearce.eu/homestead/templates" "go.alanpearce.eu/x/log" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" mapset "github.com/deckarep/golang-set/v2" - "gitlab.com/tozd/go/errors" ) type Options struct {
@@ -38,20 +39,20 @@ return filepath.Join(src, rel)
} } -func copyFile(storage storage.Writer, src string, rel string) errors.E { +func copyFile(storage storage.Writer, src string, rel string) error { buf := new(buffer.Buffer) sf, err := os.Open(src) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } defer sf.Close() buf.Reset() if _, err := io.Copy(buf, sf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if err := storage.Write("/"+rel, "", buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } return nil
@@ -61,7 +62,7 @@ func build(
options *Options, config *config.Config, log *log.Logger, -) errors.E { +) error { buf := new(buffer.Buffer) joinSource := joinSourcePath(options.Source) storage := options.Storage
@@ -80,7 +81,7 @@ PostDir: postDir,
Repo: options.Repo, }, log.Named("content")) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } sitemap := sitemap.New(config)
@@ -94,11 +95,11 @@ log.Debug("rendering post", "post", post.Basename)
sitemap.AddPath(post.URL, post.Date) buf.Reset() if err := templates.PostPage(siteSettings, post).Render(buf); err != nil { - return errors.WithMessage(err, "could not render post") + return fault.Wrap(err, fmsg.With("could not render post")) } if err := storage.WritePost(post, buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } }
@@ -108,10 +109,10 @@ if err := templates.TagsPage(siteSettings, templates.TagsPageVars{
Title: "Tags", Tags: mapset.Sorted(cc.Tags), }).Render(buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if err := storage.Write("/tags/", "Tags", buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } sitemap.AddPath("/tags/", lastMod)
@@ -129,10 +130,10 @@ if err := templates.TagPage(siteSettings, templates.TagPageVars{
Tag: tag, Posts: matchingPosts, }).Render(buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if err = storage.Write(url, tag, buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } sitemap.AddPath(url, matchingPosts[0].Date)
@@ -145,14 +146,14 @@ matchingPosts,
tag, ) if err != nil { - return errors.WithMessage(err, "could not render tag feed page") + return fault.Wrap(err, fmsg.With("could not render tag feed page")) } buf.Reset() if _, err := feed.WriteTo(buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if err := storage.Write(path.Join("/tags", tag, "atom.xml"), title, buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } }
@@ -161,34 +162,37 @@ buf.Reset()
if err := templates.ListPage(siteSettings, templates.ListPageVars{ Posts: cc.Posts, }).Render(buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if err := storage.Write(path.Join("/", postDir)+"/", "Posts", buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } sitemap.AddPath(path.Join("/", postDir)+"/", lastMod) log.Debug("rendering feed") feed, err := template.RenderFeed(config.Title, config, cc.Posts, "feed") if err != nil { - return errors.WithMessage(err, "could not render feed") + return fault.Wrap(err, fmsg.With("could not render feed")) } buf.Reset() if _, err := feed.WriteTo(buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if err := storage.Write("/atom.xml", config.Title, buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } for _, filename := range []string{"feed-styles.xsl", "style.css"} { buf.Reset() log.Debug("rendering template file", "filename", filename) if err := template.CopyFile(filename, buf); err != nil { - return errors.WithMessagef(err, "could not render template file %s", filename) + return fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not render template file %s", filename)), + ) } if err := storage.Write("/"+filename, "", buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } }
@@ -201,17 +205,17 @@ Email: config.Email,
Me: config.RelMe, Posts: cc.Posts, }, post).Render(buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } } else { if err := templates.Page(siteSettings, post).Render(buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } } file := storage.NewFileFromPost(post) file.ContentType = "text/html; charset=utf-8" if err := storage.WriteFile(file, buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } }
@@ -220,26 +224,26 @@ // date would be wrong as the homepage has its own content file
// without a date, which could be newer sitemap.AddPath("/", time.Time{}) if err := buf.SeekStart(); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } log.Debug("rendering sitemap") buf.Reset() if _, err := sitemap.WriteTo(buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if err := storage.Write("/sitemap.xml", "sitemap", buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } log.Debug("rendering robots.txt") buf.Reset() err = template.RenderRobotsTXT(config.BaseURL, buf) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if err := storage.Write("/robots.txt", "", buf); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } for _, sf := range cc.StaticFiles {
@@ -247,16 +251,16 @@ src := joinSource(sf)
log.Debug("copying static file", "sf", sf, "src", src) err = copyFile(storage, src, sf) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } } return nil } -func BuildSite(options *Options, cfg *config.Config, log *log.Logger) errors.E { +func BuildSite(options *Options, cfg *config.Config, log *log.Logger) error { if cfg == nil { - return errors.New("config is nil") + return fault.New("config is nil") } return build(options, cfg, log)
M internal/builder/template/template.gointernal/builder/template/template.go
@@ -12,9 +12,10 @@ "go.alanpearce.eu/homestead/internal/content"
"go.alanpearce.eu/homestead/templates" "github.com/PuerkitoBio/goquery" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "github.com/antchfx/xmlquery" "github.com/antchfx/xpath" - "gitlab.com/tozd/go/errors" ) var (
@@ -25,16 +26,16 @@ "xhtml": "http://www.w3.org/1999/xhtml",
} ) -func RenderRobotsTXT(baseURL config.URL, w io.Writer) errors.E { +func RenderRobotsTXT(baseURL config.URL, w io.Writer) error { tpl, err := template.ParseFS(templates.Files, "robots.tmpl") if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } err = tpl.Execute(w, map[string]any{ "BaseURL": baseURL, }) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } return nil
@@ -45,7 +46,7 @@ title string,
config *config.Config, posts []*content.Post, specific string, -) (io.WriterTo, errors.E) { +) (io.WriterTo, error) { buf := &bytes.Buffer{} datetime := posts[0].Date.UTC()
@@ -65,7 +66,7 @@
for i, post := range posts { html, err := post.RenderString() if err != nil { - return nil, errors.WithMessage(err, "could not render post") + return nil, fault.Wrap(err, fmsg.With("could not render post")) } feed.Entries[i] = &atom.FeedEntry{ Title: post.Title,
@@ -82,44 +83,44 @@ }
} enc := xml.NewEncoder(buf) if err := enc.Encode(feed); err != nil { - return nil, errors.WithStack(err) + return nil, fault.Wrap(err) } return buf, nil } -func CopyFile(filename string, w io.Writer) errors.E { +func CopyFile(filename string, w io.Writer) error { f, err := templates.Files.Open(filename) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } defer f.Close() if _, err := io.Copy(w, f); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } return nil } -func GetFeedStyleHash(r io.Reader) (string, errors.E) { +func GetFeedStyleHash(r io.Reader) (string, error) { doc, err := xmlquery.Parse(r) if err != nil { - return "", errors.WithStack(err) + return "", fault.Wrap(err) } expr, err := xpath.CompileWithNS("//xhtml:style", nsMap) if err != nil { - return "", errors.WithMessage(err, "could not parse XPath") + return "", fault.Wrap(err, fmsg.With("could not parse XPath")) } style := xmlquery.QuerySelector(doc, expr) return Hash(style.InnerText()), nil } -func GetHTMLStyleHash(r io.Reader) (string, errors.E) { +func GetHTMLStyleHash(r io.Reader) (string, error) { doc, err := goquery.NewDocumentFromReader(r) if err != nil { - return "", errors.WithStack(err) + return "", fault.Wrap(err) } html := doc.Find("head > style").Text()
M internal/calendar/calendar.gointernal/calendar/calendar.go
@@ -2,6 +2,7 @@ package calendar
import ( "context" + "errors" "fmt" "io" "io/fs"
@@ -10,8 +11,9 @@ "os"
"slices" "time" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" ical "github.com/arran4/golang-ical" - "gitlab.com/tozd/go/errors" "go.alanpearce.eu/x/log" "go.alanpearce.eu/homestead/internal/cache"
@@ -71,7 +73,7 @@ }
stat, err := cache.Root.Stat(Filename) if err != nil && !errors.Is(err, fs.ErrNotExist) { - return false, errors.WithMessage(err, "could not stat calendar file") + return false, fault.Wrap(err, fmsg.With("could not stat calendar file")) } return stat != nil && time.Since(stat.ModTime()) < Refresh && stat.Size() > 0, nil
@@ -99,52 +101,52 @@ c.Calendar, err = ical.ParseCalendar(f)
if err != nil { c.log.Warn("error parsing calendar", "error", err) - return errors.WithMessage(err, "could not parse calendar") + return fault.Wrap(err, fmsg.With("could not parse calendar")) } return err } -func (c *Calendar) open() (*os.File, errors.E) { +func (c *Calendar) open() (*os.File, error) { f, err := cache.Root.Open(Filename) if err != nil { - return nil, errors.WithMessage(err, "could not open calendar file") + return nil, fault.Wrap(err, fmsg.With("could not open calendar file")) } return f, nil } -func (c *Calendar) fetch(ctx context.Context) errors.E { +func (c *Calendar) fetch(ctx context.Context) error { c.log.Debug("fetching calendar", "url", c.opts.URL.String()) f, err := cache.Root.OpenFile(Filename, os.O_RDWR|os.O_CREATE, 0o600) if err != nil { - return errors.WithMessage(err, "could not create temp file") + return fault.Wrap(err, fmsg.With("could not create temp file")) } defer f.Close() req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.opts.URL.String(), nil) if err != nil { - return errors.WithMessage(err, "could not create request") + return fault.Wrap(err, fmsg.With("could not create request")) } res, err := c.client.Do(req) if err != nil { - return errors.WithMessage(err, "could not fetch calendar") + return fault.Wrap(err, fmsg.With("could not fetch calendar")) } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return errors.New(fmt.Sprintf("unexpected status code %d", res.StatusCode)) + return fault.New(fmt.Sprintf("unexpected status code %d", res.StatusCode)) } if _, err := io.Copy(f, res.Body); err != nil { - return errors.WithMessage(err, "could not write calendar to file") + return fault.Wrap(err, fmsg.With("could not write calendar to file")) } err = f.Sync() if err != nil { - return errors.WithMessage(err, "could not sync file") + return fault.Wrap(err, fmsg.With("could not sync file")) } return nil
@@ -152,7 +154,7 @@ }
func (c *Calendar) EventsBetween(from time.Time, to time.Time) ([]*Busy, error) { if c.Calendar == nil { - return nil, errors.New("calendar not initialised") + return nil, fault.New("calendar not initialised") } in := c.Busys()
@@ -235,7 +237,7 @@ cd := &CalendarDate{Date: date}
evs, err := c.EventsBetween(date.Add(1*time.Second), date.EndOfDay().Time) if err != nil { - return nil, errors.WithMessage(err, "could not get events") + return nil, fault.Wrap(err, fmsg.With("could not get events")) } for _, ev := range evs {
M internal/config/config.gointernal/config/config.go
@@ -1,6 +1,7 @@
package config import ( + "fmt" "io/fs" "net/url" "path/filepath"
@@ -9,7 +10,8 @@
"go.alanpearce.eu/x/log" "github.com/BurntSushi/toml" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" ) type Taxonomy struct {
@@ -38,7 +40,7 @@
func (u *URL) UnmarshalText(text []byte) (err error) { u.URL, err = url.Parse(string(text)) - return errors.WithMessagef(err, "could not parse URL %s", string(text)) + return fault.Wrap(err, fmsg.With(fmt.Sprintf("could not parse URL %s", string(text)))) } type Timezone struct {
@@ -48,7 +50,7 @@
func (t *Timezone) UnmarshalText(text []byte) (err error) { t.Location, err = time.LoadLocation(string(text)) - return errors.WithMessagef(err, "could not parse timezone %s", string(text)) + return fault.Wrap(err, fmsg.With(fmt.Sprintf("could not parse timezone %s", string(text)))) } type Config struct {
@@ -73,7 +75,7 @@ Menu []MenuItem
RelMe []MenuItem `toml:"rel_me"` } -func GetConfig(dir string, log *log.Logger) (*Config, errors.E) { +func GetConfig(dir string, log *log.Logger) (*Config, error) { config := &Config{} filename := filepath.Join(dir, "config.toml") log.Debug("reading config", "filename", filename)
@@ -81,12 +83,12 @@ _, err := toml.DecodeFile(filename, config)
if err != nil { switch t := err.(type) { case *fs.PathError: - return nil, errors.WithMessage(t, "could not read configuration") + return nil, fault.Wrap(t, fmsg.With("could not read configuration")) case *toml.ParseError: - return nil, errors.WithMessage(t, t.ErrorWithUsage()) + return nil, fault.Wrap(t, fmsg.With(t.ErrorWithUsage())) } - return nil, errors.WithMessage(err, "config error") + return nil, fault.Wrap(err, fmsg.With("config error")) } return config, nil
M internal/content/posts.gointernal/content/posts.go
@@ -2,6 +2,7 @@ package content
import ( "bytes" + "fmt" "io" "io/fs" "os"
@@ -15,9 +16,10 @@ "go.alanpearce.eu/homestead/internal/markdown"
"go.alanpearce.eu/homestead/internal/vcs" "go.alanpearce.eu/x/log" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "github.com/adrg/frontmatter" mapset "github.com/deckarep/golang-set/v2" - "gitlab.com/tozd/go/errors" ) var SkipList = []string{
@@ -70,7 +72,10 @@ fp := filepath.Join(cc.config.Root, filename)
url := path.Join("/", postURLReplacer.Replace(filename)) + "/" cs, err := cc.config.Repo.GetFileLog(filename) if err != nil { - return nil, errors.WithMessagef(err, "could not get commit log for file %s", filename) + return nil, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not get commit log for file %s", filename)), + ) } post := &Post{ Input: filename,
@@ -93,12 +98,15 @@ "index.md", "",
".md", "", ) -func (cc *Collection) GetPage(filename string) (*Post, errors.E) { +func (cc *Collection) GetPage(filename string) (*Post, error) { fp := filepath.Join(cc.config.Root, filename) url := path.Join("/", pageURLReplacer.Replace(filename)) cs, err := cc.config.Repo.GetFileLog(filename) if err != nil { - return nil, errors.WithMessagef(err, "could not get commit log for file %s", filename) + return nil, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not get commit log for file %s", filename)), + ) } post := &Post{ Input: filename,
@@ -120,20 +128,17 @@
return post, nil } -func parse(fp string, post *Post) errors.E { +func parse(fp string, post *Post) error { content, err := os.Open(fp) if err != nil { - return errors.WithMessagef(err, "could not open post %s", fp) + return fault.Wrap(err, fmsg.With(fmt.Sprintf("could not open post %s", fp))) } defer content.Close() post.content, err = frontmatter.Parse(content, post.PostMatter) if err != nil { - return errors.WithMessagef( - err, - "could not parse front matter of post %s", - fp, - ) + return fault.Wrap(err, fmsg.With(fmt.Sprintf("could not parse front matter of post %s", + fp))) } return nil
@@ -144,10 +149,10 @@ func (p *Post) Render(w io.Writer) error {
return markdown.Convert(p.content, w) } -func (p *Post) RenderString() (string, errors.E) { +func (p *Post) RenderString() (string, error) { var buf bytes.Buffer if err := p.Render(&buf); err != nil { - return "", errors.WithMessage(err, "could not convert markdown content") + return "", fault.Wrap(err, fmsg.With("could not convert markdown content")) } return buf.String(), nil
@@ -190,7 +195,7 @@
return nil } -func NewContentCollection(config *Config, log *log.Logger) (*Collection, errors.E) { +func NewContentCollection(config *Config, log *log.Logger) (*Collection, error) { cc := &Collection{ Posts: []*Post{}, Tags: mapset.NewSet[string](),
@@ -219,7 +224,7 @@ return b.Date.Compare(a.Date)
}) if err != nil { - return nil, errors.WithMessage(err, "could not walk directory") + return nil, fault.Wrap(err, fmsg.With("could not walk directory")) } return cc, nil
M internal/events/file.gointernal/events/file.go
@@ -1,6 +1,7 @@
package events import ( + "fmt" "io/fs" "maps" "os"
@@ -11,8 +12,9 @@ "time"
"go.alanpearce.eu/x/log" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "github.com/fsnotify/fsnotify" - "gitlab.com/tozd/go/errors" ) var (
@@ -28,10 +30,10 @@ log *log.Logger
*fsnotify.Watcher } -func NewFileWatcher(logger *log.Logger, dirs ...string) (*FileWatcher, errors.E) { +func NewFileWatcher(logger *log.Logger, dirs ...string) (*FileWatcher, error) { fsn, err := fsnotify.NewWatcher() if err != nil { - return nil, errors.WithMessage(err, "could not create file watcher") + return nil, fault.Wrap(err, fmsg.With("could not create file watcher")) } fw := &FileWatcher{
@@ -42,7 +44,10 @@
for _, dir := range dirs { err = fw.AddRecursive(dir) if err != nil { - return nil, errors.WithMessagef(err, "could not add directory %s to file watcher", dir) + return nil, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not add directory %s to file watcher", dir)), + ) } }
@@ -64,11 +69,11 @@ func (fw *FileWatcher) ignored(pathname string) bool {
return slices.ContainsFunc(ignores, fw.matches(path.Base(pathname))) } -func (fw *FileWatcher) AddRecursive(from string) errors.E { +func (fw *FileWatcher) AddRecursive(from string) error { fw.log.Debug("walking directory tree", "root", from) err := filepath.WalkDir(from, func(path string, entry fs.DirEntry, err error) error { if err != nil { - return errors.WithMessagef(err, "could not walk directory %s", path) + return fault.Wrap(err, fmsg.With(fmt.Sprintf("could not walk directory %s", path))) } if entry.IsDir() { if entry.Name() == ".git" {
@@ -78,21 +83,24 @@ return fs.SkipDir
} fw.log.Debug("adding directory to watcher", "path", path) if err = fw.Add(path); err != nil { - return errors.WithMessagef(err, "could not add directory %s to watcher", path) + return fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not add directory %s to watcher", path)), + ) } } return nil }) - return errors.WithMessage(err, "error walking directory tree") + return fault.Wrap(err, fmsg.With("error walking directory tree")) } -func (fw *FileWatcher) GetLatestRunID() (uint64, errors.E) { +func (fw *FileWatcher) GetLatestRunID() (uint64, error) { return 0, nil } -func (fw *FileWatcher) Subscribe() (<-chan Event, errors.E) { +func (fw *FileWatcher) Subscribe() (<-chan Event, error) { var timer *time.Timer events := make(chan Event, 1)
M internal/events/redis.gointernal/events/redis.go
@@ -7,8 +7,9 @@ "fmt"
"strconv" "time" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "github.com/redis/go-redis/v9" - "gitlab.com/tozd/go/errors" "go.alanpearce.eu/x/log" "go.uber.org/zap" )
@@ -37,7 +38,7 @@ client *redis.Client
log *log.Logger } -func NewRedisListener(opts *RedisOptions, log *log.Logger) (*RedisListener, errors.E) { +func NewRedisListener(opts *RedisOptions, log *log.Logger) (*RedisListener, error) { clientConfig := &redis.Options{ Addr: opts.Address, Username: opts.Username,
@@ -68,18 +69,18 @@ log: log,
}, nil } -func (rl *RedisListener) GetLatestRunID() (uint64, errors.E) { +func (rl *RedisListener) GetLatestRunID() (uint64, error) { ctx, cancel := context.WithTimeout(context.TODO(), 2*time.Second) defer cancel() payload, err := rl.client.Get(ctx, key).Result() if err != nil { - return fallbackRunID, errors.WithMessage(err, "could not get latest run ID") + return fallbackRunID, fault.Wrap(err, fmsg.With("could not get latest run ID")) } runID, err := strconv.ParseUint(payload, 10, 64) if err != nil { - return fallbackRunID, errors.WithMessage(err, "could not parse latest run ID") + return fallbackRunID, fault.Wrap(err, fmsg.With("could not parse latest run ID")) } rl.log.Debug("redis response", "payload", payload, "run_id", runID)
@@ -92,7 +93,7 @@ func getKeyspaceName(key string) string {
return fmt.Sprintf("__keyspace@%d__:%s", db, key) } -func (rl *RedisListener) Subscribe() (<-chan Event, errors.E) { +func (rl *RedisListener) Subscribe() (<-chan Event, error) { events := make(chan Event, 1) ctx := context.TODO() channel := getKeyspaceName(key)
M internal/events/update.gointernal/events/update.go
@@ -2,7 +2,6 @@ package events
import ( "github.com/fsnotify/fsnotify" - "gitlab.com/tozd/go/errors" ) type CIEvent struct {
@@ -19,6 +18,6 @@ FSEvent
} type Listener interface { - GetLatestRunID() (uint64, errors.E) - Subscribe() (<-chan Event, errors.E) + GetLatestRunID() (uint64, error) + Subscribe() (<-chan Event, error) }
M internal/fetcher/fetcher.gointernal/fetcher/fetcher.go
@@ -2,6 +2,8 @@ package fetcher
import ( "context" + "errors" + "fmt" "io" "io/fs" "math"
@@ -13,8 +15,9 @@ "strconv"
"strings" "time" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "github.com/google/renameio/v2" - "gitlab.com/tozd/go/errors" "go.alanpearce.eu/homestead/internal/config" "go.alanpearce.eu/homestead/internal/events" "go.alanpearce.eu/x/log"
@@ -46,35 +49,35 @@ updater: options.Listener,
} } -func (f *Fetcher) getArtefacts(run uint64) errors.E { +func (f *Fetcher) getArtefacts(run uint64) error { runID := strconv.FormatUint(run, 10) f.log.Debug("getting artefacts", "run_id", runID) err := os.MkdirAll(filepath.Join(f.options.Root, runID), 0o750) if err != nil { - return errors.WithMessage(err, "could not create directory") + return fault.Wrap(err, fmsg.With("could not create directory")) } for _, file := range files { err := f.getFile(runID, file) if err != nil { - return errors.WithMessage(err, "could not fetch file") + return fault.Wrap(err, fmsg.With("could not fetch file")) } } f.current = run err = renameio.Symlink(runID, filepath.Join(f.options.Root, "current")) if err != nil { - return errors.WithMessage(err, "could not create/update symlink") + return fault.Wrap(err, fmsg.With("could not create/update symlink")) } return nil } -func (f *Fetcher) checkFolder() errors.E { +func (f *Fetcher) checkFolder() error { contents, err := os.ReadDir(f.options.Root) if err != nil { - return errors.WithMessage(err, "could not read root directory") + return fault.Wrap(err, fmsg.With("could not read root directory")) } var badFiles []string for _, f := range contents {
@@ -85,18 +88,18 @@ }
} if len(badFiles) > 0 { - return errors.WithStack( - errors.Basef("unexpected files in root directory: %s", strings.Join(badFiles, ", ")), + return fault.Wrap( + fault.Newf("unexpected files in root directory: %s", strings.Join(badFiles, ", ")), ) } return nil } -func (f *Fetcher) CleanOldRevisions() errors.E { +func (f *Fetcher) CleanOldRevisions() error { contents, err := os.ReadDir(f.options.Root) if err != nil { - return errors.WithMessage(err, "could not read root directory") + return fault.Wrap(err, fmsg.With("could not read root directory")) } for _, file := range contents { name := file.Name()
@@ -106,12 +109,15 @@ }
if numericFilename.MatchString(name) { v, err := strconv.ParseUint(name, 10, 64) if err != nil { - return errors.WithMessagef(err, "could not parse numeric filename %s", name) + return fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not parse numeric filename %s", name)), + ) } if v < f.current-1 { err := os.RemoveAll(filepath.Join(f.options.Root, name)) if err != nil { - return errors.WithMessage(err, "could not remove folder") + return fault.Wrap(err, fmsg.With("could not remove folder")) } } }
@@ -128,7 +134,7 @@ }
}() } -func (f *Fetcher) getFile(runID, basename string) errors.E { +func (f *Fetcher) getFile(runID, basename string) error { filename := filepath.Join(f.options.Root, runID, basename) url := f.options.FetchURL.JoinPath(runID, basename).String()
@@ -136,7 +142,7 @@ f.log.Debug("getting file", "filename", filename, "url", url)
file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0o600) if err != nil { - return errors.WithMessage(err, "could not open file") + return fault.Wrap(err, fmsg.With("could not open file")) } defer file.Close()
@@ -145,40 +151,43 @@ defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { - return errors.WithMessage(err, "could not create request") + return fault.Wrap(err, fmsg.With("could not create request")) } res, err := http.DefaultClient.Do(req) if err != nil { - return errors.WithMessage(err, "could not issue request") + return fault.Wrap(err, fmsg.With("could not issue request")) } _, err = io.Copy(file, res.Body) if err != nil { - return errors.WithMessage(err, "could not write file") + return fault.Wrap(err, fmsg.With("could not write file")) } err = file.Sync() if err != nil { - return errors.WithMessage(err, "could not sync file") + return fault.Wrap(err, fmsg.With("could not sync file")) } return nil } -func (f *Fetcher) getCurrentVersion() (uint64, errors.E) { +func (f *Fetcher) getCurrentVersion() (uint64, error) { target, err := os.Readlink(filepath.Join(f.options.Root, "current")) if err != nil && errors.Is(err, fs.ErrNotExist) { - return 0, errors.WithMessage(err, "could not stat current link") + return 0, fault.Wrap(err, fmsg.With("could not stat current link")) } f.current, err = strconv.ParseUint(target, 10, 64) if err != nil { - return 0, errors.WithMessagef(err, "unexpected symlink target (current -> %s)", target) + return 0, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("unexpected symlink target (current -> %s)", target)), + ) } return f.current, nil } -func (f *Fetcher) initialiseStorage() (uint64, errors.E) { +func (f *Fetcher) initialiseStorage() (uint64, error) { latest, err := f.updater.GetLatestRunID() if err != nil { f.log.Warn("could not get latest run ID, using fallback", "error", err)
@@ -190,7 +199,7 @@
if latest > f.current { err = f.getArtefacts(latest) if err != nil { - return latest, errors.WithMessage(err, "could not fetch artefacts") + return latest, fault.Wrap(err, fmsg.With("could not fetch artefacts")) } return latest, nil
@@ -199,7 +208,7 @@
return f.current, nil } -func (f *Fetcher) Subscribe() (<-chan string, errors.E) { +func (f *Fetcher) Subscribe() (<-chan string, error) { err := f.checkFolder() if err != nil { return nil, err
@@ -250,10 +259,10 @@
return ch, nil } -func (f *Fetcher) connect(root string, ch chan string) errors.E { +func (f *Fetcher) connect(root string, ch chan string) error { updates, err := f.updater.Subscribe() if err != nil { - return errors.WithMessage(err, "could not subscribe to updates") + return fault.Wrap(err, fmsg.With("could not subscribe to updates")) } go func() {
M internal/file/file.gointernal/file/file.go
@@ -1,18 +1,20 @@
package file import ( + "errors" "io" "io/fs" "os" "path/filepath" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" ) -func Stat(path string) (fs.FileInfo, errors.E) { +func Stat(path string) (fs.FileInfo, error) { stat, err := os.Stat(path) if err != nil && !errors.Is(err, fs.ErrNotExist) { - return nil, errors.WithStack(err) + return nil, fault.Wrap(err) } return stat, nil
@@ -27,45 +29,45 @@
return stat != nil } -func Copy(src, dest string) errors.E { +func Copy(src, dest string) error { stat, err := os.Stat(src) if err != nil { - return errors.WithMessage(err, "could not stat source file") + return fault.Wrap(err, fmsg.With("could not stat source file")) } sf, err := os.Open(src) if err != nil { - return errors.WithMessage(err, "could not open source file for reading") + return fault.Wrap(err, fmsg.With("could not open source file for reading")) } defer sf.Close() df, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE, stat.Mode()) if err != nil { - return errors.WithMessage(err, "could not open destination file for writing") + return fault.Wrap(err, fmsg.With("could not open destination file for writing")) } defer df.Close() if _, err := io.Copy(df, sf); err != nil { - return errors.WithMessage(err, "could not copy") + return fault.Wrap(err, fmsg.With("could not copy")) } err = df.Sync() if err != nil { - return errors.WithMessage(err, "could not call fsync") + return fault.Wrap(err, fmsg.With("could not call fsync")) } return nil } -func CleanDir(dir string) errors.E { +func CleanDir(dir string) error { files, err := os.ReadDir(dir) if err != nil { - return errors.WithMessage(errors.WithStack(err), "could not read directory") + return fault.Wrap(fault.Wrap(err), fmsg.With("could not read directory")) } for _, file := range files { err = errors.Join(err, os.RemoveAll(filepath.Join(dir, file.Name()))) } - return errors.WithStack(err) + return fault.Wrap(err) }
M internal/markdown/markdown.gointernal/markdown/markdown.go
@@ -3,11 +3,11 @@
import ( "io" + "github.com/Southclaws/fault" fences "github.com/stefanfritsch/goldmark-fences" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" htmlrenderer "github.com/yuin/goldmark/renderer/html" - "gitlab.com/tozd/go/errors" ) var markdown = goldmark.New(
@@ -22,6 +22,6 @@ &fences.Extender{},
), ) -func Convert(content []byte, w io.Writer) errors.E { - return errors.WithStack(markdown.Convert(content, w)) +func Convert(content []byte, w io.Writer) error { + return fault.Wrap(markdown.Convert(content, w)) }
M internal/multibuf/writecloser.gointernal/multibuf/writecloser.go
@@ -3,7 +3,7 @@
import ( "io" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" ) type WriteCloser struct {
@@ -32,5 +32,5 @@ lastErr = err
} } - return errors.WithStack(lastErr) + return fault.Wrap(lastErr) }
M internal/multifile/compress.gointernal/multifile/compress.go
@@ -1,10 +1,11 @@
package multifile import ( + "errors" "io" "os" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" ) type CompressWriter struct {
@@ -22,12 +23,12 @@
func (cw *CompressWriter) Write(p []byte) (int, error) { n, err := cw.Writer.Write(p) if err != nil { - return 0, errors.WithStack(err) + return 0, fault.Wrap(err) } return n, nil } func (cw *CompressWriter) Close() error { - return errors.WithStack(errors.Join(cw.Writer.Close(), cw.File.Close())) + return fault.Wrap(errors.Join(cw.Writer.Close(), cw.File.Close())) }
M internal/multifile/multifile.gointernal/multifile/multifile.go
@@ -1,11 +1,12 @@
package multifile import ( + "errors" "io" "os" "time" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" ) type MultiFile struct {
@@ -39,14 +40,14 @@ lastErr = err
} } - return errors.WithStack(lastErr) + return fault.Wrap(lastErr) } func (mf *MultiFile) Name() string { return mf.files[0].Name() } -func (mf *MultiFile) Chtimes(mtime time.Time) errors.E { +func (mf *MultiFile) Chtimes(mtime time.Time) error { var lastErr error for _, f := range mf.files { err := os.Chtimes(f.Name(), mtime, mtime)
@@ -55,5 +56,5 @@ lastErr = errors.Join(lastErr, err)
} } - return errors.WithStack(lastErr) + return fault.Wrap(lastErr) }
M internal/publisher/app.gointernal/publisher/app.go
@@ -3,7 +3,8 @@
import ( "net/http" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "go.hacdias.com/indielib/indieauth" "go.alanpearce.eu/homestead/internal/config"
@@ -26,7 +27,7 @@ siteSettings templates.SiteSettings
*server.App } -func New(opts *Options, log *log.Logger) (*App, errors.E) { +func New(opts *Options, log *log.Logger) (*App, error) { var err error app := &App{ log: log,
@@ -45,7 +46,7 @@ }
err = indieauth.IsValidProfileURL(opts.BaseURL.String()) if err != nil { - return nil, errors.WithMessage(err, "invalid base URL") + return nil, fault.Wrap(err, fmsg.With("invalid base URL")) } mux := ihttp.NewServeMux()
M internal/server/server.gointernal/server/server.go
@@ -2,6 +2,7 @@ package server
import ( "context" + "errors" "fmt" "net/http" "time"
@@ -9,7 +10,8 @@
"github.com/osdevisnot/sorvor/pkg/livereload" "go.alanpearce.eu/x/log" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" ) var (
@@ -49,7 +51,7 @@ wrappedHandler.ServeHTTP(w, r)
}) } -func New(options *Options, log *log.Logger) (*Server, errors.E) { +func New(options *Options, log *log.Logger) (*Server, error) { return &Server{ mux: http.NewServeMux(), log: log,
@@ -57,9 +59,9 @@ options: options,
}, nil } -func (s *Server) HostApp(app *App) errors.E { +func (s *Server) HostApp(app *App) error { if app.Domain == "" { - return errors.New("app needs a domain") + return fault.New("app needs a domain") } s.options.Domains = append(s.options.Domains, app.Domain) s.mux.Handle(app.Domain+"/", app.Handler)
@@ -77,7 +79,7 @@ }
s.mux.Handle("/", app.Handler) } -func (s *Server) Start() errors.E { +func (s *Server) Start() error { var lh http.Handler if s.options.Development { lh = wrapHandlerWithLogging(s.mux, s.log)
@@ -110,7 +112,7 @@ Handler: top,
} if err := s.serveTCP(); !errors.Is(err, http.ErrServerClosed) { - return errors.WithMessage(err, "error creating/closing server") + return fault.Wrap(err, fmsg.With("error creating/closing server")) } return nil
M internal/server/tcp.gointernal/server/tcp.go
@@ -4,11 +4,11 @@ import (
"net" "strconv" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" "go.alanpearce.eu/x/listenfd" ) -func (s *Server) serveTCP() errors.E { +func (s *Server) serveTCP() error { addr := joinHostPort(s.options.ListenAddress, s.options.Port) s.log.Debug( "fallback listener",
@@ -17,10 +17,10 @@ addr,
) l, err := listenfd.GetListener(0, addr, s.log.Named("tcp.listenfd")) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } - return errors.WithStack(s.server.Serve(l)) + return fault.Wrap(s.server.Serve(l)) } func joinHostPort(host string, port int) string {
M internal/stats/goatcounter/count.gointernal/stats/goatcounter/count.go
@@ -8,7 +8,8 @@ "io"
"net/http" "time" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "go.alanpearce.eu/homestead/internal/config" "go.alanpearce.eu/x/log" )
@@ -69,7 +70,7 @@ gc.log.Warn("could not log page view", "error", err)
} } -func (gc *Goatcounter) count(userReq *http.Request, title string) errors.E { +func (gc *Goatcounter) count(userReq *http.Request, title string) error { body, err := json.Marshal(&countBody{ NoSessions: true, Hits: []hit{
@@ -84,7 +85,7 @@ },
}, }) if err != nil { - return errors.WithMessage(err, "could not marshal JSON") + return fault.Wrap(err, fmsg.With("could not marshal JSON")) } go func(body []byte) {
M internal/storage/file.gointernal/storage/file.go
@@ -5,7 +5,8 @@ "io"
"strings" "time" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "go.alanpearce.eu/homestead/internal/buffer" "go.alanpearce.eu/homestead/internal/builder/template" )
@@ -29,14 +30,14 @@
return encs } -func (f *File) CalculateStyleHash() (err errors.E) { +func (f *File) CalculateStyleHash() (err error) { buf := f.Encodings["identity"] if buf == nil { - return errors.New("buffer not initialised") + return fault.New("buffer not initialised") } if _, err := buf.Seek(0, io.SeekStart); err != nil { - return errors.WithMessage(err, "could not seek buffer") + return fault.Wrap(err, fmsg.With("could not seek buffer")) } mime, _, _ := strings.Cut(f.ContentType, ";")
@@ -44,13 +45,13 @@ switch mime {
case "text/html": f.StyleHash, err = template.GetHTMLStyleHash(buf) if err != nil { - return errors.WithMessage(err, "could not calculate HTML style hash") + return fault.Wrap(err, fmsg.With("could not calculate HTML style hash")) } default: return } if _, err := buf.Seek(0, io.SeekStart); err != nil { - return errors.WithMessage(err, "could not seek buffer") + return fault.Wrap(err, fmsg.With("could not seek buffer")) } return
M internal/storage/files/file.gointernal/storage/files/file.go
@@ -1,6 +1,7 @@
package files import ( + "errors" "fmt" "hash/fnv" "io"
@@ -9,7 +10,8 @@ "os"
"path/filepath" "strings" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "go.alanpearce.eu/homestead/internal/buffer" "go.alanpearce.eu/homestead/internal/storage" )
@@ -20,25 +22,25 @@ "gzip": ".gz",
"zstd": ".zstd", } -func (r *Reader) OpenFile(path string, filename string) (*storage.File, errors.E) { +func (r *Reader) OpenFile(path string, filename string) (*storage.File, error) { f, err := os.Open(filename) if err != nil { - return nil, errors.WithMessage(err, "could not open file for reading") + return nil, fault.Wrap(err, fmsg.With("could not open file for reading")) } defer f.Close() stat, err := f.Stat() if err != nil { - return nil, errors.WithMessage(err, "could not stat file") + return nil, fault.Wrap(err, fmsg.With("could not stat file")) } buf := new(buffer.Buffer) if _, err := f.WriteTo(buf); err != nil { - return nil, errors.WithMessage(err, "could not read file") + return nil, fault.Wrap(err, fmsg.With("could not read file")) } etag, err := etag(buf) if err != nil { - return nil, errors.WithMessage(err, "could not calculate etag") + return nil, fault.Wrap(err, fmsg.With("could not calculate etag")) } file := &storage.File{
@@ -53,7 +55,7 @@ }
err = file.CalculateStyleHash() if err != nil { - return nil, errors.WithStack(err) + return nil, fault.Wrap(err) } for enc, suffix := range encodings {
@@ -63,11 +65,17 @@ if errors.Is(err, os.ErrNotExist) {
continue } - return nil, errors.WithMessagef(err, "could not stat file %s", filename+suffix) + return nil, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not stat file %s", filename+suffix)), + ) } bytes, err := os.ReadFile(filename + suffix) if err != nil { - return nil, errors.WithMessagef(err, "could not read file %s", filename+suffix) + return nil, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not read file %s", filename+suffix)), + ) } buf := buffer.NewBuffer(bytes) file.Encodings[enc] = buf
@@ -76,10 +84,10 @@
return file, nil } -func etag(f io.Reader) (string, errors.E) { +func etag(f io.Reader) (string, error) { hash := fnv.New64a() if _, err := io.Copy(hash, f); err != nil { - return "", errors.WithMessage(err, "could not hash file") + return "", fault.Wrap(err, fmsg.With("could not hash file")) } return fmt.Sprintf(`W/"%x"`, hash.Sum(nil)), nil
M internal/storage/files/reader.gointernal/storage/files/reader.go
@@ -1,6 +1,7 @@
package files import ( + "fmt" "io/fs" "path/filepath" "strings"
@@ -8,7 +9,8 @@
"go.alanpearce.eu/homestead/internal/storage" "go.alanpearce.eu/x/log" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" ) type Reader struct {
@@ -17,23 +19,23 @@ log *log.Logger
files map[string]*storage.File } -func NewReader(path string, log *log.Logger) (*Reader, errors.E) { +func NewReader(path string, log *log.Logger) (*Reader, error) { r := &Reader{ root: path, log: log, files: make(map[string]*storage.File), } if err := r.registerContentFiles(); err != nil { - return nil, errors.WithMessagef(err, "registering content files") + return nil, fault.Wrap(err, fmsg.With("registering content files")) } return r, nil } -func (r *Reader) registerFile(urlpath string, filepath string) errors.E { +func (r *Reader) registerFile(urlpath string, filepath string) error { file, err := r.OpenFile(urlpath, filepath) if err != nil { - return errors.WithMessagef(err, "could not register file %s", filepath) + return fault.Wrap(err, fmsg.With(fmt.Sprintf("could not register file %s", filepath))) } r.files[urlpath] = file
@@ -41,10 +43,10 @@
return nil } -func (r *Reader) registerContentFiles() errors.E { +func (r *Reader) registerContentFiles() error { err := filepath.WalkDir(r.root, func(filePath string, f fs.DirEntry, err error) error { if err != nil { - return errors.WithMessagef(err, "failed to access path %s", filePath) + return fault.Wrap(err, fmsg.With(fmt.Sprintf("failed to access path %s", filePath))) } if f.IsDir() { return nil
@@ -52,7 +54,10 @@ }
relPath, err := filepath.Rel(r.root, filePath) if err != nil { - return errors.WithMessagef(err, "failed to make path relative, path: %s", filePath) + return fault.Wrap( + err, + fmsg.With(fmt.Sprintf("failed to make path relative, path: %s", filePath)), + ) } urlPath := fileNameToPathName("/" + relPath)
@@ -66,13 +71,13 @@
return r.registerFile(urlPath, filePath) }) if err != nil { - return errors.WithMessage(err, "could not walk directory") + return fault.Wrap(err, fmsg.With("could not walk directory")) } return nil } -func (r *Reader) GetFile(urlPath string) (*storage.File, errors.E) { +func (r *Reader) GetFile(urlPath string) (*storage.File, error) { return r.files[urlPath], nil }
M internal/storage/files/writer.gointernal/storage/files/writer.go
@@ -12,9 +12,10 @@ "go.alanpearce.eu/homestead/internal/multifile"
"go.alanpearce.eu/homestead/internal/storage" "go.alanpearce.eu/x/log" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "github.com/andybalholm/brotli" "github.com/klauspost/compress/zstd" - "gitlab.com/tozd/go/errors" ) const (
@@ -32,7 +33,7 @@ type Options struct {
Compress bool } -func NewWriter(outputDirectory string, logger *log.Logger, opts *Options) (*Files, errors.E) { +func NewWriter(outputDirectory string, logger *log.Logger, opts *Options) (*Files, error) { return &Files{ outputDirectory: outputDirectory, options: opts,
@@ -40,49 +41,49 @@ log: logger,
}, nil } -func (f *Files) OpenRead(filename string) (io.ReadCloser, errors.E) { +func (f *Files) OpenRead(filename string) (io.ReadCloser, error) { file, err := os.Open(f.join(filename)) if err != nil { - return nil, errors.WithStack(err) + return nil, fault.Wrap(err) } return file, nil } -func (f *Files) OpenWrite(filename string) (io.WriteCloser, errors.E) { +func (f *Files) OpenWrite(filename string) (io.WriteCloser, error) { return openFileWrite(f.join(filename)) } -func (f *Files) WritePost(post *content.Post, content *buffer.Buffer) errors.E { +func (f *Files) WritePost(post *content.Post, content *buffer.Buffer) error { fd, err := f.write(post.URL, content) if err != nil { return err } if err := fd.Close(); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if mf, isMultifile := fd.(*multifile.MultiFile); isMultifile { err = mf.Chtimes(post.Date) } else { - err = errors.WithStack(os.Chtimes(fd.Name(), post.Date, post.Date)) + err = fault.Wrap(os.Chtimes(fd.Name(), post.Date, post.Date)) } if err != nil { - return errors.WithMessage(err, "could not set file times") + return fault.Wrap(err, fmsg.With("could not set file times")) } return nil } -func (f *Files) Write(pathname string, _ string, content *buffer.Buffer) errors.E { +func (f *Files) Write(pathname string, _ string, content *buffer.Buffer) error { fd, err := f.write(pathname, content) if err != nil { return err } if err := fd.Close(); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } return nil
@@ -95,39 +96,39 @@ Encodings: map[string]*buffer.Buffer{},
} } -func (f *Files) WriteFile(file *storage.File, content *buffer.Buffer) errors.E { +func (f *Files) WriteFile(file *storage.File, content *buffer.Buffer) error { return f.Write(file.Path, file.Title, content) } -func (f *Files) write(pathname string, content *buffer.Buffer) (multifile.FileLike, errors.E) { +func (f *Files) write(pathname string, content *buffer.Buffer) (multifile.FileLike, error) { filename := pathNameToFileName(pathname) err := f.Mkdirp(filepath.Dir(filename)) if err != nil { - return nil, errors.WithMessage(err, "could not create directory") + return nil, fault.Wrap(err, fmsg.With("could not create directory")) } fd, err := f.OpenFileAndVariants(filename) if err != nil { - return nil, errors.WithMessagef(err, "could not open output file") + return nil, fault.Wrap(err, fmsg.With("could not open output file")) } if _, err := fd.Write(content.Bytes()); err != nil { - return nil, errors.WithMessage(err, "could not write output file") + return nil, fault.Wrap(err, fmsg.With("could not write output file")) } return fd, nil } -func openFileWrite(filename string) (*os.File, errors.E) { +func openFileWrite(filename string) (*os.File, error) { f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600) if err != nil { - return nil, errors.WithMessage(err, "could not open output file") + return nil, fault.Wrap(err, fmsg.With("could not open output file")) } return f, nil } -func openFileGz(filename string) (*multifile.CompressWriter, errors.E) { +func openFileGz(filename string) (*multifile.CompressWriter, error) { filenameGz := filename + ".gz" f, err := openFileWrite(filenameGz) if err != nil {
@@ -137,13 +138,13 @@ var w io.WriteCloser
var baseErr error w, baseErr = gzip.NewWriterLevel(f, gzipLevel) if baseErr != nil { - return nil, errors.WithStack(baseErr) + return nil, fault.Wrap(baseErr) } return multifile.NewCompressWriter(f, w), err } -func openFileBrotli(filename string) (*multifile.CompressWriter, errors.E) { +func openFileBrotli(filename string) (*multifile.CompressWriter, error) { filenameBrotli := filename + ".br" f, err := openFileWrite(filenameBrotli) if err != nil {
@@ -153,7 +154,7 @@
return multifile.NewCompressWriter(f, brotli.NewWriterLevel(f, brotliLevel)), nil } -func openFileZstd(filename string) (*multifile.CompressWriter, errors.E) { +func openFileZstd(filename string) (*multifile.CompressWriter, error) { f, err := openFileWrite(filename + ".zstd") if err != nil { return nil, err
@@ -163,13 +164,13 @@ var w io.WriteCloser
var baseErr error w, baseErr = zstd.NewWriter(f) if baseErr != nil { - return nil, errors.WithStack(baseErr) + return nil, fault.Wrap(baseErr) } return multifile.NewCompressWriter(f, w), nil } -func multiOpenFile(filename string) (*multifile.MultiFile, errors.E) { +func multiOpenFile(filename string) (*multifile.MultiFile, error) { r, err := openFileWrite(filename) if err != nil { return nil, err
@@ -190,7 +191,7 @@
return multifile.NewMultiFile(r, gz, br, zst), nil } -func (f *Files) OpenFileAndVariants(filename string) (multifile.FileLike, errors.E) { +func (f *Files) OpenFileAndVariants(filename string) (multifile.FileLike, error) { if f.options.Compress { return multiOpenFile(f.join(filename)) }
@@ -198,10 +199,10 @@
return openFileWrite(f.join(filename)) } -func (f *Files) Mkdirp(dir string) errors.E { +func (f *Files) Mkdirp(dir string) error { err := os.MkdirAll(f.join(dir), 0o750) if err != nil { - return errors.WithMessage(err, "could not create directory") + return fault.Wrap(err, fmsg.With("could not create directory")) } return nil
M internal/storage/interface.gointernal/storage/interface.go
@@ -1,22 +1,21 @@
package storage import ( - "gitlab.com/tozd/go/errors" "go.alanpearce.eu/homestead/internal/buffer" "go.alanpearce.eu/homestead/internal/content" ) type Reader interface { - GetFile(path string) (*File, errors.E) + GetFile(path string) (*File, error) CanonicalisePath(path string) (string, bool) } type Writer interface { - Mkdirp(path string) errors.E + Mkdirp(path string) error NewFileFromPost(post *content.Post) *File - Write(pathname string, title string, content *buffer.Buffer) errors.E - WritePost(post *content.Post, content *buffer.Buffer) errors.E - WriteFile(file *File, content *buffer.Buffer) errors.E + Write(pathname string, title string, content *buffer.Buffer) error + WritePost(post *content.Post, content *buffer.Buffer) error + WriteFile(file *File, content *buffer.Buffer) error }
M internal/storage/sqlite/reader.gointernal/storage/sqlite/reader.go
@@ -5,7 +5,8 @@ "database/sql"
"strings" "time" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "go.alanpearce.eu/homestead/internal/buffer" "go.alanpearce.eu/homestead/internal/storage" "go.alanpearce.eu/x/log"
@@ -20,7 +21,7 @@ checkPath *sql.Stmt
} } -func NewReader(db *sql.DB, log *log.Logger) (*Reader, errors.E) { +func NewReader(db *sql.DB, log *log.Logger) (*Reader, error) { r := &Reader{ log: log, db: db,
@@ -44,7 +45,7 @@ WHERE
url.path = ? `) if err != nil { - return nil, errors.WithMessage(err, "preparing select statement") + return nil, fault.Wrap(err, fmsg.With("preparing select statement")) } r.queries.checkPath, err = r.db.Prepare(`
@@ -55,13 +56,13 @@ WHERE path = ?
) AS differs `) if err != nil { - return nil, errors.WithMessage(err, "preparing check path statement") + return nil, fault.Wrap(err, fmsg.With("preparing check path statement")) } return r, nil } -func (r *Reader) GetFile(filename string) (*storage.File, errors.E) { +func (r *Reader) GetFile(filename string) (*storage.File, error) { file := &storage.File{ Encodings: make(map[string]*buffer.Buffer, 1), }
@@ -72,7 +73,7 @@
r.log.Debug("querying db for file", "filename", filename) rows, err := r.queries.getFile.Query(filename) if err != nil { - return nil, errors.WithMessage(err, "querying database") + return nil, fault.Wrap(err, fmsg.With("querying database")) } defer rows.Close()
@@ -89,7 +90,7 @@ &encoding,
&content, ) if err != nil { - return nil, errors.WithMessage(err, "querying database") + return nil, fault.Wrap(err, fmsg.With("querying database")) } file.LastModified = time.Unix(unixTime, 0)
@@ -99,7 +100,7 @@ if count == 0 {
return nil, nil } if err := rows.Err(); err != nil { - return nil, errors.WithMessage(err, "error iterating rows") + return nil, fault.Wrap(err, fmsg.With("error iterating rows")) } return file, nil
M internal/storage/sqlite/writer.gointernal/storage/sqlite/writer.go
@@ -18,7 +18,8 @@ "go.alanpearce.eu/homestead/internal/content"
"go.alanpearce.eu/homestead/internal/storage" "go.alanpearce.eu/x/log" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" _ "modernc.org/sqlite" // import registers db/SQL driver )
@@ -40,7 +41,7 @@ type Options struct {
Compress bool } -func OpenDB(dbPath string) (*sql.DB, errors.E) { +func OpenDB(dbPath string) (*sql.DB, error) { db, err := sql.Open( "sqlite", fmt.Sprintf(
@@ -51,13 +52,13 @@ 16*1024*1024,
), ) if err != nil { - return nil, errors.WithStack(err) + return nil, fault.Wrap(err) } return db, nil } -func NewWriter(db *sql.DB, logger *log.Logger, opts *Options) (*Writer, errors.E) { +func NewWriter(db *sql.DB, logger *log.Logger, opts *Options) (*Writer, error) { _, err := db.Exec(` CREATE TABLE IF NOT EXISTS url ( url_id INTEGER PRIMARY KEY,
@@ -90,7 +91,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS file_content
ON content (file_id, encoding); `) if err != nil { - return nil, errors.WithMessage(err, "creating tables") + return nil, fault.Wrap(err, fmsg.With("creating tables")) } w := &Writer{
@@ -101,7 +102,7 @@ }
w.queries.insertURL, err = db.Prepare(`INSERT INTO url (path) VALUES (?)`) if err != nil { - return nil, errors.WithMessage(err, "preparing insert URL statement") + return nil, fault.Wrap(err, fmsg.With("preparing insert URL statement")) } w.queries.insertFile, err = db.Prepare(`
@@ -109,7 +110,7 @@ INSERT INTO file (url_id, content_type, last_modified, etag, style_hash, title)
VALUES (:url_id, :content_type, :last_modified, :etag, :style_hash, :title) `) if err != nil { - return nil, errors.WithMessage(err, "preparing insert file statement") + return nil, fault.Wrap(err, fmsg.With("preparing insert file statement")) } w.queries.insertContent, err = db.Prepare(`
@@ -117,31 +118,31 @@ INSERT INTO content (file_id, encoding, body)
VALUES (:file_id, :encoding, :body) `) if err != nil { - return nil, errors.WithMessage(err, "preparing insert content statement") + return nil, fault.Wrap(err, fmsg.With("preparing insert content statement")) } return w, nil } -func (s *Writer) Mkdirp(string) errors.E { +func (s *Writer) Mkdirp(string) error { return nil } -func (s *Writer) storeURL(path string) (int64, errors.E) { +func (s *Writer) storeURL(path string) (int64, error) { r, err := s.queries.insertURL.Exec(path) if err != nil { - return 0, errors.WithMessagef(err, "inserting URL %s into database", path) + return 0, fault.Wrap(err, fmsg.With(fmt.Sprintf("inserting URL %s into database", path))) } id, err := r.LastInsertId() if err != nil { - return 0, errors.WithStack(err) + return 0, fault.Wrap(err) } return id, nil } -func (s *Writer) storeFile(urlID int64, file *storage.File) (int64, errors.E) { +func (s *Writer) storeFile(urlID int64, file *storage.File) (int64, error) { if file.ContentType == "" { file.ContentType = http.DetectContentType(file.Encodings["identity"].Bytes()) s.log.Warn(
@@ -161,40 +162,40 @@ sql.Named("style_hash", file.StyleHash),
sql.Named("title", file.Title), ) if err != nil { - return 0, errors.WithMessage(err, "inserting file into database") + return 0, fault.Wrap(err, fmsg.With("inserting file into database")) } id, err := r.LastInsertId() if err != nil { - return 0, errors.WithStack(err) + return 0, fault.Wrap(err) } return id, nil } -func (s *Writer) storeEncoding(fileID int64, encoding string, data []byte) errors.E { +func (s *Writer) storeEncoding(fileID int64, encoding string, data []byte) error { _, err := s.queries.insertContent.Exec( sql.Named("file_id", fileID), sql.Named("encoding", encoding), sql.Named("body", data), ) if err != nil { - return errors.WithMessagef( + return fault.Wrap( err, - "inserting encoding into database file_id: %d encoding: %s", - fileID, - encoding, + fmsg.With(fmt.Sprintf("inserting encoding into database file_id: %d encoding: %s", + fileID, + encoding)), ) } return nil } -func etag(content []byte) (string, errors.E) { +func etag(content []byte) (string, error) { hash := fnv.New64a() _, err := hash.Write(content) if err != nil { - return "", errors.WithStack(err) + return "", fault.Wrap(err) } return fmt.Sprintf(`W/"%x"`, hash.Sum(nil)), nil
@@ -215,13 +216,13 @@
return file } -func (s *Writer) WritePost(post *content.Post, content *buffer.Buffer) errors.E { +func (s *Writer) WritePost(post *content.Post, content *buffer.Buffer) error { s.log.Debug("storing post", "title", post.Title) return s.WriteFile(s.NewFileFromPost(post), content) } -func (s *Writer) Write(pathname string, title string, content *buffer.Buffer) errors.E { +func (s *Writer) Write(pathname string, title string, content *buffer.Buffer) error { file := &storage.File{ Title: title, Path: pathname,
@@ -232,12 +233,12 @@
return s.WriteFile(file, content) } -func (s *Writer) WriteFile(file *storage.File, content *buffer.Buffer) errors.E { +func (s *Writer) WriteFile(file *storage.File, content *buffer.Buffer) error { s.log.Debug("storing content", "pathname", file.Path) urlID, err := s.storeURL(file.Path) if err != nil { - return errors.WithMessage(err, "storing URL") + return fault.Wrap(err, fmsg.With("storing URL")) } if file.Encodings == nil {
@@ -252,18 +253,18 @@
if file.Etag == "" { file.Etag, err = etag(content.Bytes()) if err != nil { - return errors.WithMessage(err, "could not calculate file etag") + return fault.Wrap(err, fmsg.With("could not calculate file etag")) } } err = file.CalculateStyleHash() if err != nil { - return errors.WithMessage(err, "calculating file hash") + return fault.Wrap(err, fmsg.With("calculating file hash")) } fileID, err := s.storeFile(urlID, file) if err != nil { - return errors.WithMessage(err, "storing file") + return fault.Wrap(err, fmsg.With("storing file")) } err = s.storeEncoding(fileID, "identity", content.Bytes())
@@ -275,7 +276,7 @@ if s.options.Compress {
for _, enc := range encodings { compressed, err := compress(enc, content) if err != nil { - return errors.WithMessage(err, "compressing file") + return fault.Wrap(err, fmsg.With("compressing file")) } err = s.storeEncoding(fileID, enc, compressed.Bytes())
@@ -289,7 +290,7 @@
return nil } -func compress(encoding string, content *buffer.Buffer) (*buffer.Buffer, errors.E) { +func compress(encoding string, content *buffer.Buffer) (*buffer.Buffer, error) { var w io.WriteCloser compressed := new(buffer.Buffer) switch encoding {
@@ -301,16 +302,16 @@ case "zstd":
var err error w, err = zstd.NewWriter(compressed) if err != nil { - return nil, errors.WithMessage(err, "could not create zstd writer") + return nil, fault.Wrap(err, fmsg.With("could not create zstd writer")) } } defer w.Close() if err := content.SeekStart(); err != nil { - return nil, errors.WithMessage(err, "seeking to start of content buffer") + return nil, fault.Wrap(err, fmsg.With("seeking to start of content buffer")) } if _, err := io.Copy(w, content); err != nil { - return nil, errors.WithMessage(err, "compressing file") + return nil, fault.Wrap(err, fmsg.With("compressing file")) } return compressed, nil
M internal/vcs/filelog.gointernal/vcs/filelog.go
@@ -1,14 +1,16 @@
package vcs import ( + "fmt" "net/url" "regexp" "strings" "time" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" - "gitlab.com/tozd/go/errors" ) const hashLength = 7
@@ -34,7 +36,7 @@ func (r *Repository) makeCommitURL(hash string) *url.URL {
return r.remoteURL.JoinPath("commit", hash) } -func (r *Repository) GetFileLog(filename string) ([]*Commit, errors.E) { +func (r *Repository) GetFileLog(filename string) ([]*Commit, error) { var fl object.CommitIter var err error fl, err = r.repo.Log(&git.LogOptions{
@@ -42,7 +44,10 @@ Order: git.LogOrderCommitterTime,
FileName: &filename, }) if err != nil { - return nil, errors.WithMessagef(err, "could not get git log for file %s", filename) + return nil, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not get git log for file %s", filename)), + ) } defer fl.Close()
@@ -67,7 +72,10 @@
return nil }) if err != nil { - return nil, errors.WithMessagef(err, "could not iterate over commits for file %s", filename) + return nil, fault.Wrap( + err, + fmsg.With(fmt.Sprintf("could not iterate over commits for file %s", filename)), + ) } return cs, nil
M internal/vcs/repository.gointernal/vcs/repository.go
@@ -1,15 +1,16 @@
package vcs import ( + "errors" "os" "go.alanpearce.eu/homestead/internal/config" "go.alanpearce.eu/homestead/internal/file" "go.alanpearce.eu/x/log" + "github.com/Southclaws/fault" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" - "gitlab.com/tozd/go/errors" ) type Options struct {
@@ -24,7 +25,7 @@ log *log.Logger
remoteURL config.URL } -func CloneOrOpen(cfg *Options, log *log.Logger) (*Repository, bool, errors.E) { +func CloneOrOpen(cfg *Options, log *log.Logger) (*Repository, bool, error) { var r *git.Repository var err error exists := file.Exists(cfg.LocalPath)
@@ -37,7 +38,7 @@ } else {
r, err = git.PlainOpen(cfg.LocalPath) } if err != nil { - return nil, exists, errors.WithStack(err) + return nil, exists, fault.Wrap(err) } return &Repository{
@@ -47,7 +48,7 @@ repo: r,
}, exists, nil } -func (r *Repository) Update(rev string) (bool, errors.E) { +func (r *Repository) Update(rev string) (bool, error) { r.log.Info("updating repository", "from", r.HeadSHA()) err := r.repo.Fetch(&git.FetchOptions{ Prune: true,
@@ -59,18 +60,18 @@
return true, nil } - return false, errors.WithStack(err) + return false, fault.Wrap(err) } rem, err := r.repo.Remote("origin") if err != nil { - return false, errors.WithStack(err) + return false, fault.Wrap(err) } refs, err := rem.List(&git.ListOptions{ Timeout: 5, }) if err != nil { - return false, errors.WithStack(err) + return false, fault.Wrap(err) } var hash plumbing.Hash
@@ -88,14 +89,14 @@ }
wt, err := r.repo.Worktree() if err != nil { - return false, errors.WithStack(err) + return false, fault.Wrap(err) } err = wt.Checkout(&git.CheckoutOptions{ Hash: hash, Force: true, }) if err != nil { - return false, errors.WithStack(err) + return false, fault.Wrap(err) } r.log.Info("updated to", "rev", hash)
@@ -103,10 +104,10 @@
return true, r.Clean(wt) } -func (r *Repository) Clean(wt *git.Worktree) errors.E { +func (r *Repository) Clean(wt *git.Worktree) error { st, err := wt.Status() if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } if !st.IsClean() {
@@ -114,7 +115,7 @@ err = wt.Clean(&git.CleanOptions{
Dir: true, }) if err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } }
M internal/website/website.gointernal/website/website.go
@@ -9,7 +9,8 @@ "slices"
"sync" "time" - "gitlab.com/tozd/go/errors" + "github.com/Southclaws/fault" + "github.com/Southclaws/fault/fmsg" "go.alanpearce.eu/homestead/internal/calendar" "go.alanpearce.eu/homestead/internal/config" "go.alanpearce.eu/homestead/internal/events"
@@ -77,7 +78,7 @@
func New( opts *Options, log *log.Logger, -) (*Website, errors.E) { +) (*Website, error) { website := &Website{ log: log, App: &server.App{
@@ -87,7 +88,7 @@ }
err := prepareRootDirectory(opts.Root) if err != nil { - return nil, errors.WithMessage(err, "could not prepare root directory") + return nil, fault.Wrap(err, fmsg.With("could not prepare root directory")) } var listener events.Listener
@@ -99,7 +100,7 @@ log.Debug("using file watcher")
listener, err = events.NewFileWatcher(log.Named("events"), "website") } if err != nil { - return nil, errors.WithMessage(err, "could not create update listener") + return nil, fault.Wrap(err, fmsg.With("could not create update listener")) } var cfg *config.Config
@@ -111,7 +112,7 @@ Listener: listener,
}) roots, err := fetcher.Subscribe() if err != nil { - return nil, errors.WithMessage(err, "could not set up fetcher") + return nil, fault.Wrap(err, fmsg.With("could not set up fetcher")) } if opts.Development {
@@ -217,11 +218,11 @@
return website, nil } -func prepareRootDirectory(root string) errors.E { +func prepareRootDirectory(root string) error { if !file.Exists(root) { err := os.MkdirAll(root, 0o750) if err != nil { - return errors.WithMessage(err, "could not create root directory") + return fault.Wrap(err, fmsg.With("could not create root directory")) } }
M main.gomain.go
@@ -2,6 +2,7 @@ package main
import ( "context" + "errors" "fmt" "os" "os/signal"
@@ -13,7 +14,6 @@ "go.alanpearce.eu/x/log"
"github.com/ardanlabs/conf/v3" "github.com/osdevisnot/sorvor/pkg/livereload" - "gitlab.com/tozd/go/errors" ) type Options struct {
M templates/layout.gotemplates/layout.go
@@ -3,8 +3,8 @@
import ( "io" + "github.com/Southclaws/fault" "github.com/alanpearce/htmlformat" - "gitlab.com/tozd/go/errors" "go.alanpearce.eu/homestead/internal/config" g "go.alanpearce.eu/gomponents"
@@ -123,7 +123,7 @@ pw.CloseWithError(doc.Render(pw))
}() if err := htmlformat.Document(w, pr); err != nil { - return errors.WithStack(err) + return fault.Wrap(err) } return nil