all repos — searchix @ 9015baf955c94a806c01b3dcd5648c8e68ad2685

Search engine for NixOS, nix-darwin, home-manager and NUR users

refactor: ensure errors have stack traces

Alan Pearce
commit

9015baf955c94a806c01b3dcd5648c8e68ad2685

parent

7bb77ff5729cc9434afee895a470fd3b4c12e6d1

M frontend/assets.gofrontend/assets.go
@@ -8,7 +8,7 @@ "hash/fnv"
"io" "io/fs" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) var Assets = &AssetCollection{
@@ -30,7 +30,7 @@ Stylesheets []*Asset
ByPath map[string]*Asset } -func newAsset(filename string) (*Asset, error) { +func newAsset(filename string) (*Asset, errors.E) { file, err := Files.Open(filename) if err != nil { return nil, errors.WithMessagef(err, "could not open file %s", filename)
@@ -51,7 +51,7 @@ Base64SHA256: base64.StdEncoding.EncodeToString(shasum.Sum(nil)),
}, nil } -func hashScripts() error { +func hashScripts() errors.E { scripts, err := fs.Glob(Files, "static/**.js") if err != nil { return errors.WithMessage(err, "could not glob files")
@@ -68,7 +68,7 @@
return nil } -func hashStyles() error { +func hashStyles() errors.E { styles, err := fs.Glob(Files, "static/**.css") if err != nil { return errors.WithMessage(err, "could not glob files")
@@ -85,7 +85,7 @@
return nil } -func Rehash() (err error) { +func Rehash() (err errors.E) { Assets.Scripts = []*Asset{} err = hashScripts() if err != nil {
M go.modgo.mod
@@ -15,9 +15,9 @@ github.com/getsentry/sentry-go v0.30.0
github.com/mitchellh/mapstructure v1.5.0 github.com/osdevisnot/sorvor v0.4.4 github.com/pelletier/go-toml/v2 v2.2.3 - github.com/pkg/errors v0.9.1 github.com/stoewer/go-strcase v1.3.0 github.com/yuin/goldmark v1.7.8 + gitlab.com/tozd/go/errors v0.10.0 go.alanpearce.eu/x v0.0.0-20241203124832-a29434dba11a go.uber.org/zap v1.27.0 golang.org/x/net v0.33.0
@@ -56,6 +56,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mschoch/smat v0.2.0 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/stretchr/testify v1.10.0 // indirect github.com/sykesm/zap-logfmt v0.0.4 // indirect
M go.sumgo.sum
@@ -140,6 +140,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +gitlab.com/tozd/go/errors v0.10.0 h1:A98kL+gaDvWnY6ZB/u8zP+sYaWsWUGBHeFMtamvW/74= +gitlab.com/tozd/go/errors v0.10.0/go.mod h1:q3Ugr0C8dCzMEkrzjjlV2qNsm9e0KvqBjwcbcjCpBe4= go.alanpearce.eu/x v0.0.0-20241203124832-a29434dba11a h1:NUv3AzGxwMVSq26takww8/nyl+sPO2BsESoVSU8G49U= go.alanpearce.eu/x v0.0.0-20241203124832-a29434dba11a/go.mod h1:FRM6J9HMQ/RV2Q5j+6RKBYWh/YNeEUriGSqDRchiHuQ= go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
M gomod2nix.tomlgomod2nix.toml
@@ -151,6 +151,9 @@ hash = "sha256-l5E2DVNyQLmMx8V1CrTQ+v55aC4rhjteOm4fNlND7UI="
[mod."github.com/yuin/goldmark"] version = "v1.7.8" hash = "sha256-SNJMPPiXkRDLVOldrHN0ErC3bUB2VoWaLDkd9zmMATw=" + [mod."gitlab.com/tozd/go/errors"] + version = "v0.10.0" + hash = "sha256-oW37KsieVKJOWk9ZXbGuQvuU4nyJCZzgYrTZHFkoCs4=" [mod."go.alanpearce.eu/x"] version = "v0.0.0-20241203124832-a29434dba11a" hash = "sha256-ojqWkz3VqeAOevFxOTO5S3acRItCA4pUrTaul887+x8="
M internal/components/markdown.templinternal/components/markdown.templ
@@ -5,9 +5,9 @@ "regexp"
"go.alanpearce.eu/searchix/internal/nix" + "context" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" - "context" "io" )
@@ -27,7 +27,7 @@ return text
} func markdown(text nix.Markdown) templ.Component { - return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) errors.E { err := md.Convert([]byte(text), w) return err
M internal/components/page.templinternal/components/page.templ
@@ -81,7 +81,7 @@ <script src={ s.URL } defer integrity={ "sha256-" + s.Base64SHA256 }></script>
} func Unsafe(html string) templ.Component { - return templ.ComponentFunc(func(_ context.Context, w io.Writer) (err error) { + return templ.ComponentFunc(func(_ context.Context, w io.Writer) (err errors.E) { _, err = io.WriteString(w, html) return })
M internal/config/config.gointernal/config/config.go
@@ -7,7 +7,7 @@ "os"
"time" "github.com/pelletier/go-toml/v2" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" "go.alanpearce.eu/x/log" )
@@ -103,7 +103,7 @@
return } -func GetConfig(filename string, log *log.Logger) (*Config, error) { +func GetConfig(filename string, log *log.Logger) (*Config, errors.E) { config := DefaultConfig if filename != "" { log.Debug("reading config", "filename", filename)
M internal/config/fetcher.gointernal/config/fetcher.go
@@ -4,6 +4,7 @@ import (
"fmt" "github.com/stoewer/go-strcase" + "gitlab.com/tozd/go/errors" ) type Fetcher int
@@ -37,7 +38,7 @@ return ChannelNixpkgs, nil
case "download": return Download, nil default: - return UnknownFetcher, fmt.Errorf("unsupported fetcher %s", name) + return UnknownFetcher, errors.Errorf("unsupported fetcher %s", name) } }
M internal/config/repository.gointernal/config/repository.go
@@ -3,6 +3,8 @@
import ( "fmt" "strings" + + "gitlab.com/tozd/go/errors" ) type RepoType int
@@ -28,12 +30,12 @@ return fmt.Sprintf("RepoType(%d)", f)
} } -func parseRepoType(name string) (RepoType, error) { +func parseRepoType(name string) (RepoType, errors.E) { switch strings.ToLower(name) { case "github": return GitHub, nil default: - return UnknownRepoType, fmt.Errorf("unsupported repo type %s", name) + return UnknownRepoType, errors.Errorf("unsupported repo type %s", name) } }
M internal/fetcher/channel.gointernal/fetcher/channel.go
@@ -14,7 +14,7 @@ "go.alanpearce.eu/searchix/internal/config"
"go.alanpearce.eu/searchix/internal/index" "go.alanpearce.eu/x/log" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) type ChannelFetcher struct {
@@ -26,7 +26,7 @@
func NewChannelFetcher( source *config.Source, logger *log.Logger, -) (*ChannelFetcher, error) { +) (*ChannelFetcher, errors.E) { switch source.Importer { case config.Options: return &ChannelFetcher{
@@ -34,14 +34,14 @@ Source: source,
Logger: logger, }, nil default: - return nil, fmt.Errorf("unsupported importer type %s", source.Importer) + return nil, errors.Errorf("unsupported importer type %s", source.Importer) } } func (i *ChannelFetcher) FetchIfNeeded( ctx context.Context, sourceMeta *index.SourceMeta, -) (f FetchedFiles, err error) { +) (*FetchedFiles, errors.E) { args := []string{ "--no-build-output", "--timeout",
@@ -58,12 +58,9 @@ }
i.Logger.Debug("nix-build command", "args", args) cmd := exec.CommandContext(ctx, "nix-build", args...) - var out []byte - out, err = cmd.Output() + out, err := cmd.Output() if err != nil { - err = errors.WithMessage(err, "failed to run nix-build (--dry-run)") - - return + return nil, errors.WithMessage(err, "failed to run nix-build (--dry-run)") } outPath := path.Join(strings.TrimSpace(string(out)), i.Source.OutputPath, "options.json")
@@ -80,14 +77,10 @@ }
file, err := os.Open(outPath) if err != nil { - err = errors.WithMessage(err, "failed to open options.json") - - return + return nil, errors.WithMessage(err, "failed to open options.json") } - f = FetchedFiles{ + return &FetchedFiles{ Options: file, - } - - return + }, nil }
M internal/fetcher/download.gointernal/fetcher/download.go
@@ -2,13 +2,12 @@ package fetcher
import ( "context" - "fmt" "net/url" "go.alanpearce.eu/searchix/internal/config" "go.alanpearce.eu/searchix/internal/index" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" "go.alanpearce.eu/x/log" )
@@ -21,7 +20,7 @@
func NewDownloadFetcher( source *config.Source, logger *log.Logger, -) (*DownloadFetcher, error) { +) (*DownloadFetcher, errors.E) { switch source.Importer { case config.Options: return &DownloadFetcher{
@@ -29,7 +28,7 @@ Source: source,
Logger: logger, }, nil default: - return nil, fmt.Errorf("unsupported importer type %s", source.Importer) + return nil, errors.Errorf("unsupported importer type %s", source.Importer) } }
@@ -41,20 +40,18 @@
func (i *DownloadFetcher) FetchIfNeeded( ctx context.Context, sourceMeta *index.SourceMeta, -) (f FetchedFiles, err error) { - var fetchURL string +) (*FetchedFiles, errors.E) { + f := &FetchedFiles{} sourceUpdated := sourceMeta.Updated for key, filename := range files { - fetchURL, err = url.JoinPath(i.Source.URL, filename) - if err != nil { - err = errors.WithMessagef( - err, + fetchURL, baseErr := url.JoinPath(i.Source.URL, filename) + if baseErr != nil { + return nil, errors.WithMessagef( + baseErr, "could not build URL with elements %s and %s", i.Source.URL, filename, ) - - return } i.Logger.Debug("preparing to fetch URL", "url", fetchURL)
@@ -63,7 +60,7 @@ body, mtime, err := fetchFileIfNeeded(ctx, i.Logger, sourceUpdated, fetchURL)
if err != nil { i.Logger.Warn("failed to fetch file", "url", fetchURL, "error", err) - return f, err + return nil, err } // don't bother to issue requests for the later files if mtime.Before(sourceUpdated) {
@@ -81,5 +78,5 @@ return f, errors.Errorf("unknown file kind %s", key)
} } - return + return f, nil }
M internal/fetcher/http.gointernal/fetcher/http.go
@@ -11,7 +11,7 @@
"go.alanpearce.eu/searchix/internal/config" "github.com/andybalholm/brotli" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" "go.alanpearce.eu/x/log" )
@@ -36,17 +36,20 @@ ctx context.Context,
log *log.Logger, mtime time.Time, url string, -) (body io.ReadCloser, newMtime time.Time, err error) { +) (io.ReadCloser, time.Time, errors.E) { + var newMtime time.Time var ifModifiedSince string if !mtime.IsZero() { ifModifiedSince = strings.Replace(mtime.UTC().Format(time.RFC1123), "UTC", "GMT", 1) } - req, err := http.NewRequestWithContext(ctx, "GET", url, http.NoBody) - if err != nil { - err = errors.WithMessagef(err, "could not create HTTP request for %s", url) - - return + req, baseErr := http.NewRequestWithContext(ctx, "GET", url, http.NoBody) + if baseErr != nil { + return nil, newMtime, errors.WithMessagef( + baseErr, + "could not create HTTP request for %s", + url, + ) } req.Header.Set("User-Agent", fmt.Sprintf("Searchix %s", config.Version))
@@ -54,21 +57,22 @@
if ifModifiedSince != "" { req.Header.Set("If-Modified-Since", ifModifiedSince) } - res, err := http.DefaultClient.Do(req) - if err != nil { - err = errors.WithMessagef(err, "could not make HTTP request to %s", url) - - return + res, baseErr := http.DefaultClient.Do(req) + if baseErr != nil { + return nil, newMtime, errors.WithMessagef(baseErr, "could not make HTTP request to %s", url) } + var body io.ReadCloser + var err errors.E switch res.StatusCode { case http.StatusNotModified: newMtime = mtime - return + return nil, newMtime, nil case http.StatusOK: - newMtime, err = time.Parse(time.RFC1123, res.Header.Get("Last-Modified")) - if err != nil { + var baseErr error + newMtime, baseErr = time.Parse(time.RFC1123, res.Header.Get("Last-Modified")) + if baseErr != nil { log.Warn( "could not parse Last-Modified header from response", "value",
@@ -84,11 +88,11 @@ body = newBrotliReader(res.Body)
case "", "identity", "gzip": body = res.Body default: - err = fmt.Errorf("cannot handle a body with content-encoding %s", ce) + err = errors.Errorf("cannot handle a body with content-encoding %s", ce) } default: - err = fmt.Errorf("got response code %d, don't know what to do", res.StatusCode) + err = errors.Errorf("got response code %d, don't know what to do", res.StatusCode) } - return + return body, newMtime, err }
M internal/fetcher/main.gointernal/fetcher/main.go
@@ -8,7 +8,7 @@ "go.alanpearce.eu/searchix/internal/config"
"go.alanpearce.eu/searchix/internal/index" "go.alanpearce.eu/x/log" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) type FetchedFiles struct {
@@ -18,13 +18,13 @@ Packages io.ReadCloser
} type Fetcher interface { - FetchIfNeeded(context.Context, *index.SourceMeta) (FetchedFiles, error) + FetchIfNeeded(context.Context, *index.SourceMeta) (*FetchedFiles, errors.E) } func New( source *config.Source, logger *log.Logger, -) (fetcher Fetcher, err error) { +) (fetcher Fetcher, err errors.E) { switch source.Fetcher { case config.ChannelNixpkgs: fetcher, err = NewNixpkgsChannelFetcher(source, logger)
M internal/fetcher/nixpkgs-channel.gointernal/fetcher/nixpkgs-channel.go
@@ -2,13 +2,12 @@ package fetcher
import ( "context" - "fmt" "net/url" "go.alanpearce.eu/searchix/internal/config" "go.alanpearce.eu/searchix/internal/index" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" "go.alanpearce.eu/x/log" )
@@ -17,7 +16,7 @@ Source *config.Source
Logger *log.Logger } -func makeChannelURL(channel string, subPath string) (string, error) { +func makeChannelURL(channel string, subPath string) (string, errors.E) { url, err := url.JoinPath("https://channels.nixos.org/", channel, subPath) return url, errors.WithMessagef(err, "error creating URL")
@@ -26,7 +25,7 @@
func NewNixpkgsChannelFetcher( source *config.Source, logger *log.Logger, -) (*NixpkgsChannelFetcher, error) { +) (*NixpkgsChannelFetcher, errors.E) { switch source.Importer { case config.Options, config.Packages: return &NixpkgsChannelFetcher{
@@ -34,7 +33,7 @@ Source: source,
Logger: logger, }, nil default: - return nil, fmt.Errorf("unsupported importer type %s", source.Importer) + return nil, errors.Errorf("unsupported importer type %s", source.Importer) } }
@@ -47,7 +46,7 @@
func (i *NixpkgsChannelFetcher) FetchIfNeeded( ctx context.Context, sourceMeta *index.SourceMeta, -) (f FetchedFiles, err error) { +) (f *FetchedFiles, err errors.E) { filesToFetch := make([]string, 2) filesToFetch[0] = revisionFilename
M internal/file/utils.gointernal/file/utils.go
@@ -5,10 +5,10 @@ "io"
"io/fs" "os" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) -func Mkdirp(dir string) error { +func Mkdirp(dir string) errors.E { err := os.MkdirAll(dir, os.ModeDir|os.ModePerm) if err != nil { return errors.WithMessagef(err, "could not create directory %s", dir)
@@ -17,27 +17,27 @@
return nil } -func NeedNotExist(err error) error { +func NeedNotExist(err error) errors.E { if err != nil && !errors.Is(err, fs.ErrNotExist) { - return err + return errors.WithStack(err) } return nil } -func StatIfExists(file string) (fs.FileInfo, error) { +func StatIfExists(file string) (fs.FileInfo, errors.E) { stat, err := os.Stat(file) return stat, NeedNotExist(err) } -func Exists(file string) (bool, error) { +func Exists(file string) (bool, errors.E) { stat, err := StatIfExists(file) return stat != nil, err } -func WriteToFile(path string, body io.Reader) error { +func WriteToFile(path string, body io.Reader) errors.E { file, err := os.Create(path) if err != nil { return errors.WithMessagef(err, "error creating file at %s", path)
M internal/importer/importer.gointernal/importer/importer.go
@@ -4,13 +4,14 @@ import (
"context" "sync" + "gitlab.com/tozd/go/errors" "go.alanpearce.eu/searchix/internal/index" "go.alanpearce.eu/searchix/internal/nix" "go.alanpearce.eu/x/log" ) type Processor interface { - Process(context.Context) (<-chan nix.Importable, <-chan error) + Process(context.Context) (<-chan nix.Importable, <-chan errors.E) } func process(
@@ -18,7 +19,7 @@ ctx context.Context,
indexer *index.WriteIndex, processor Processor, logger *log.Logger, -) (bool, error) { +) (bool, errors.E) { wg := sync.WaitGroup{} wg.Add(1)
@@ -28,7 +29,7 @@ wg.Add(1)
iErrs := indexer.Import(ctx, objects) var hadObjectErrors bool - var criticalError error + var criticalError errors.E go func() { for { select {
M internal/importer/main.gointernal/importer/main.go
@@ -14,7 +14,7 @@ "go.alanpearce.eu/searchix/internal/index"
"go.alanpearce.eu/searchix/internal/programs" "go.alanpearce.eu/x/log" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) func createSourceImporter(
@@ -23,8 +23,8 @@ log *log.Logger,
meta *index.Meta, indexer *index.WriteIndex, forceUpdate bool, -) func(*config.Source) error { - return func(source *config.Source) error { +) func(*config.Source) errors.E { + return func(source *config.Source) errors.E { logger := log.With( "name", source.Key,
@@ -165,7 +165,7 @@ func (imp *Importer) Start(
ctx context.Context, forceUpdate bool, onlyUpdateSources *[]string, -) error { +) errors.E { if len(imp.config.Importer.Sources) == 0 { imp.log.Info("No sources enabled")
M internal/importer/options.gointernal/importer/options.go
@@ -11,7 +11,7 @@ "go.alanpearce.eu/x/log"
"github.com/bcicen/jstream" "github.com/mitchellh/mapstructure" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) type nixValueJSON struct {
@@ -68,7 +68,7 @@ func NewOptionProcessor(
infile io.ReadCloser, source *config.Source, log *log.Logger, -) (*OptionIngester, error) { +) (*OptionIngester, errors.E) { i := OptionIngester{ dec: jstream.NewDecoder(infile, 1).EmitKV(), log: log,
@@ -94,9 +94,9 @@
return &i, nil } -func (i *OptionIngester) Process(ctx context.Context) (<-chan nix.Importable, <-chan error) { +func (i *OptionIngester) Process(ctx context.Context) (<-chan nix.Importable, <-chan errors.E) { results := make(chan nix.Importable) - errs := make(chan error) + errs := make(chan errors.E) go func() { defer i.infile.Close()
M internal/importer/package.gointernal/importer/package.go
@@ -14,7 +14,7 @@ "go.alanpearce.eu/x/log"
"github.com/bcicen/jstream" "github.com/mitchellh/mapstructure" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) type packageJSON struct {
@@ -69,7 +69,7 @@ infile io.ReadCloser,
source *config.Source, log *log.Logger, programsDB *programs.DB, -) (*PackageIngester, error) { +) (*PackageIngester, errors.E) { i := &PackageIngester{ dec: jstream.NewDecoder(infile, 2).EmitKV(), log: log,
@@ -116,9 +116,9 @@
return l } -func (i *PackageIngester) Process(ctx context.Context) (<-chan nix.Importable, <-chan error) { +func (i *PackageIngester) Process(ctx context.Context) (<-chan nix.Importable, <-chan errors.E) { results := make(chan nix.Importable) - errs := make(chan error) + errs := make(chan errors.E) if i.programs != nil { err := i.programs.Open()
@@ -135,7 +135,7 @@ defer close(errs)
outer: for mv := range i.dec.Stream() { - var err error + var err errors.E var programs []string select { case <-ctx.Done():
@@ -222,8 +222,7 @@ }
} i.pkg = packageJSON{} - err = i.ms.Decode(x) // stores in i.pkg - if err != nil { + if err := i.ms.Decode(x); err != nil { // stores in i.pkg errs <- errors.WithMessagef(err, "failed to decode package %#v", x) continue
M internal/importer/utils.gointernal/importer/utils.go
@@ -10,7 +10,7 @@ "go.alanpearce.eu/searchix/internal/config"
"go.alanpearce.eu/searchix/internal/nix" "github.com/bcicen/jstream" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) func ValueTypeToString(valueType jstream.ValueType) string {
@@ -34,7 +34,7 @@
return "very strange" } -func makeRepoURL(repo config.Repository, subPath string, line string) (string, error) { +func makeRepoURL(repo config.Repository, subPath string, line string) (string, errors.E) { switch repo.Type { case config.GitHub: ref := repo.Revision
@@ -55,7 +55,7 @@ )
} } -func MakeChannelLink(repo config.Repository, subPath string) (*nix.Link, error) { +func MakeChannelLink(repo config.Repository, subPath string) (*nix.Link, errors.E) { url, err := makeRepoURL(repo, subPath, "") if err != nil { return nil, err
@@ -67,7 +67,7 @@ URL: url,
}, nil } -func setRepoRevision(file io.ReadCloser, source *config.Source) error { +func setRepoRevision(file io.ReadCloser, source *config.Source) errors.E { if file != nil { defer file.Close() var str strings.Builder
M internal/index/index_meta.gointernal/index/index_meta.go
@@ -8,7 +8,7 @@
"go.alanpearce.eu/searchix/internal/file" "go.alanpearce.eu/x/log" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) const CurrentSchemaVersion = 3
@@ -31,7 +31,7 @@ log *log.Logger
data } -func createMeta(path string, log *log.Logger) (*Meta, error) { +func createMeta(path string, log *log.Logger) (*Meta, errors.E) { exists, err := file.Exists(path) if err != nil { return nil, errors.WithMessage(err, "could not check for existence of index metadata")
@@ -49,7 +49,7 @@ },
}, nil } -func openMeta(path string, log *log.Logger) (*Meta, error) { +func openMeta(path string, log *log.Logger) (*Meta, errors.E) { exists, err := file.Exists(path) if err != nil { return nil, errors.WithMessage(err, "could not check for existence of index metadata")
@@ -58,16 +58,16 @@ if !exists {
return createMeta(path, log) } - j, err := os.ReadFile(path) - if err != nil { - return nil, errors.WithMessage(err, "could not open index metadata file") + j, baseErr := os.ReadFile(path) + if baseErr != nil { + return nil, errors.WithMessage(baseErr, "could not open index metadata file") } meta := Meta{ path: path, log: log, } - err = json.Unmarshal(j, &meta.data) - if err != nil { + + if err := json.Unmarshal(j, &meta.data); err != nil { return nil, errors.WithMessage(err, "index metadata is corrupt, try replacing the index") }
@@ -88,7 +88,7 @@ )
} } -func (i *Meta) Save() error { +func (i *Meta) Save() errors.E { i.SchemaVersion = CurrentSchemaVersion j, err := json.Marshal(i.data) if err != nil {
M internal/index/indexer.gointernal/index/indexer.go
@@ -26,7 +26,7 @@ "github.com/blevesearch/bleve/v2/analysis/tokenizer/letter"
"github.com/blevesearch/bleve/v2/document" "github.com/blevesearch/bleve/v2/mapping" indexAPI "github.com/blevesearch/bleve_index_api" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) type WriteIndex struct {
@@ -36,16 +36,16 @@ Meta *Meta
} type BatchError struct { - error + errors.E } func (e *BatchError) Error() string { - return e.error.Error() + return e.E.Error() } var batchSize = 10_000 -func createIndexMapping() (mapping.IndexMapping, error) { +func createIndexMapping() (mapping.IndexMapping, errors.E) { indexMapping := bleve.NewIndexMapping() indexMapping.StoreDynamic = false indexMapping.IndexDynamic = false
@@ -124,7 +124,7 @@
return indexMapping, nil } -func createIndex(indexPath string, options *Options) (bleve.Index, error) { +func createIndex(indexPath string, options *Options) (bleve.Index, errors.E) { indexMapping, err := createIndexMapping() if err != nil { return nil, err
@@ -136,15 +136,15 @@ "PersisterNapTimeMSec": 1000,
"PersisterNapUnderNumFiles": 500, } } - idx, err := bleve.NewUsing( + idx, baseErr := bleve.NewUsing( indexPath, indexMapping, bleve.Config.DefaultIndexType, bleve.Config.DefaultKVStore, kvconfig, ) - if err != nil { - return nil, errors.WithMessagef(err, "unable to create index at path %s", indexPath) + if baseErr != nil { + return nil, errors.WithMessagef(baseErr, "unable to create index at path %s", indexPath) } return idx, nil
@@ -162,7 +162,7 @@ "sources",
"nixpkgs-programs.db", } -func deleteIndex(dataRoot string) error { +func deleteIndex(dataRoot string) errors.E { dir, err := os.ReadDir(dataRoot) if err != nil { return errors.WithMessagef(err, "could not read data directory %s", dataRoot)
@@ -195,8 +195,8 @@ func OpenOrCreate(
dataRoot string, force bool, options *Options, -) (*ReadIndex, *WriteIndex, bool, error) { - var err error +) (*ReadIndex, *WriteIndex, bool, errors.E) { + var err errors.E bleve.SetLog(zap.NewStdLog(options.Logger.Named("bleve").GetLogger())) indexPath := path.Join(dataRoot, indexBaseName)
@@ -231,9 +231,10 @@ return nil, nil, false, err
} } else { - idx, err = bleve.Open(indexPath) - if err != nil { - return nil, nil, exists, errors.WithMessagef(err, "could not open index at path %s", indexPath) + var baseErr error + idx, baseErr = bleve.Open(indexPath) + if baseErr != nil { + return nil, nil, exists, errors.WithMessagef(baseErr, "could not open index at path %s", indexPath) } meta, err = openMeta(metaPath, options.Logger)
@@ -260,16 +261,16 @@ exists,
nil } -func (i *WriteIndex) SaveMeta() error { +func (i *WriteIndex) SaveMeta() errors.E { return i.Meta.Save() } func (i *WriteIndex) Import( ctx context.Context, objects <-chan nix.Importable, -) <-chan error { - var err error - errs := make(chan error) +) <-chan errors.E { + var err errors.E + errs := make(chan errors.E) go func() { defer close(errs)
@@ -288,8 +289,7 @@ default:
} doc := document.NewDocument(nix.GetKey(obj)) - err = indexMapping.MapDocument(doc, obj) - if err != nil { + if err := indexMapping.MapDocument(doc, obj); err != nil { errs <- errors.WithMessagef(err, "could not map document for object: %s", obj.GetName()) continue
@@ -297,8 +297,7 @@ }
var data bytes.Buffer enc := gob.NewEncoder(&data) - err = enc.Encode(&obj) - if err != nil { + if err := enc.Encode(&obj); err != nil { errs <- errors.WithMessage(err, "could not store object in search index") continue
@@ -307,9 +306,7 @@ field := document.NewTextFieldWithIndexingOptions("_data", nil, data.Bytes(), indexAPI.StoreField)
newDoc := doc.AddField(field) // log.Debug("adding object to index", "name", opt.Name) - err = batch.IndexAdvanced(newDoc) - - if err != nil { + if err := batch.IndexAdvanced(newDoc); err != nil { errs <- errors.WithMessagef(err, "could not index object %s", obj.GetName()) continue
@@ -334,11 +331,11 @@
return errs } -func (i *WriteIndex) Flush(batch *bleve.Batch) error { +func (i *WriteIndex) Flush(batch *bleve.Batch) errors.E { size := batch.Size() if size == 0 { return &BatchError{ - error: errors.New("no documents to flush"), + E: errors.New("no documents to flush"), } } i.log.Debug("flushing batch", "size", size)
@@ -346,7 +343,7 @@
err := i.index.Batch(batch) if err != nil { return &BatchError{ - error: errors.WithMessagef(err, "could not flush batch"), + E: errors.WithMessagef(err, "could not flush batch"), } }
@@ -355,7 +352,7 @@
return nil } -func (i *WriteIndex) Close() (err error) { +func (i *WriteIndex) Close() (err errors.E) { if e := i.Meta.Save(); e != nil { // index needs to be closed anyway err = errors.WithMessage(e, "could not save metadata")
@@ -368,7 +365,7 @@
return err } -func (i *WriteIndex) DeleteBySource(source string) error { +func (i *WriteIndex) DeleteBySource(source string) errors.E { query := bleve.NewTermQuery(source) search := bleve.NewSearchRequest(query) search.Size = math.MaxInt
@@ -392,7 +389,7 @@ }
} err = i.Flush(batch) if err != nil { - return err + return errors.WithStack(err) } if uint64(search.Size) < results.Total {
M internal/index/search.gointernal/index/search.go
@@ -12,7 +12,7 @@
"github.com/blevesearch/bleve/v2" "github.com/blevesearch/bleve/v2/search" "github.com/blevesearch/bleve/v2/search/query" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) const DefaultPageSize = 100
@@ -33,7 +33,7 @@ log *log.Logger
meta *Meta } -func (index *ReadIndex) GetEnabledSources() ([]string, error) { +func (index *ReadIndex) GetEnabledSources() ([]string, errors.E) { facet := bleve.NewFacetRequest("Source", 100) query := bleve.NewMatchAllQuery() search := bleve.NewSearchRequest(query)
@@ -64,13 +64,13 @@
func (index *ReadIndex) search( ctx context.Context, request *bleve.SearchRequest, -) (*Result, error) { +) (*Result, errors.E) { request.Fields = []string{"_data", "Source"} bleveResult, err := index.index.SearchInContext(ctx, request) select { case <-ctx.Done(): - return nil, ctx.Err() + return nil, errors.WithStack(ctx.Err()) default: if err != nil { return nil, errors.WithMessage(err, "failed to execute search query")
@@ -104,7 +104,7 @@ source *config.Source,
keyword string, from int, pageSize int, -) (*Result, error) { +) (*Result, errors.E) { query := bleve.NewBooleanQuery() // match the user's query in any field ...
@@ -157,7 +157,7 @@ func (index *ReadIndex) GetDocument(
ctx context.Context, source *config.Source, id string, -) (*nix.Importable, error) { +) (*nix.Importable, errors.E) { key := nix.MakeKey(source, id) query := bleve.NewDocIDQuery([]string{key}) search := bleve.NewSearchRequest(query)
M internal/programs/programs.gointernal/programs/programs.go
@@ -7,7 +7,7 @@ "fmt"
"os/exec" "strings" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" "go.alanpearce.eu/searchix/internal/config" "go.alanpearce.eu/x/log" _ "modernc.org/sqlite" //nolint:blank-imports // sqlite driver needed for database/sql
@@ -26,7 +26,7 @@ func Instantiate(
ctx context.Context, source *config.Source, logger *log.Logger, -) (*DB, error) { +) (*DB, errors.E) { // nix-instantiate --eval --json -I nixpkgs=channel:nixos-unstable --expr 'toString <nixpkgs/programs.sqlite>' args := []string{ "--eval",
@@ -53,7 +53,7 @@ logger: logger,
}, nil } -func (p *DB) Open() error { +func (p *DB) Open() errors.E { var err error p.db, err = sql.Open("sqlite", p.Path) if err != nil {
@@ -96,7 +96,7 @@
return nil } -func (p *DB) Close() error { +func (p *DB) Close() errors.E { if err := p.db.Close(); err != nil { return errors.WithMessage(err, "failed to close sqlite database") }
@@ -104,7 +104,8 @@
return nil } -func (p *DB) GetPackagePrograms(ctx context.Context, pkg string) (programs []string, err error) { +func (p *DB) GetPackagePrograms(ctx context.Context, pkg string) ([]string, errors.E) { + programs := make([]string, 10) if p.db == nil { return nil, errors.New("database not open") }
@@ -127,5 +128,5 @@ if rerr != nil {
return nil, errors.WithMessage(rerr, "sql error") } - return + return programs, nil }
M internal/server/dev.gointernal/server/dev.go
@@ -8,7 +8,7 @@ "path/filepath"
"time" "github.com/fsnotify/fsnotify" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" "go.alanpearce.eu/x/log" )
@@ -17,7 +17,7 @@ watcher *fsnotify.Watcher
log *log.Logger } -func NewFileWatcher(log *log.Logger) (*FileWatcher, error) { +func NewFileWatcher(log *log.Logger) (*FileWatcher, errors.E) { watcher, err := fsnotify.NewWatcher() if err != nil { return nil, errors.WithMessage(err, "could not create watcher")
@@ -29,7 +29,7 @@ log,
}, nil } -func (i FileWatcher) AddRecursive(from string) error { +func (i FileWatcher) AddRecursive(from string) errors.E { i.log.Debug(fmt.Sprintf("watching files under %s", from)) err := filepath.WalkDir(from, func(path string, entry fs.DirEntry, err error) error { if err != nil {
M internal/server/logging.gointernal/server/logging.go
@@ -3,7 +3,7 @@
import ( "net/http" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" "go.alanpearce.eu/x/log" )
M internal/server/mux.gointernal/server/mux.go
@@ -25,7 +25,7 @@ "go.alanpearce.eu/searchix/internal/sentryhttp"
"go.alanpearce.eu/x/log" "github.com/osdevisnot/sorvor/pkg/livereload" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) type HTTPError struct {
@@ -65,7 +65,7 @@ cfg *config.Config,
index *search.ReadIndex, log *log.Logger, liveReload bool, -) (*http.ServeMux, error) { +) (*http.ServeMux, errors.E) { if cfg == nil { return nil, errors.New("cfg is nil") }
@@ -171,15 +171,16 @@ }
w.Header().Add("Cache-Control", "max-age=300") w.Header().Add("Vary", "Fetch") + var baseErr error if r.Header.Get("Fetch") == "true" { w.Header().Add("Content-Type", "text/html; charset=utf-8") - err = components.Results(tdata).Render(r.Context(), w) + baseErr = components.Results(tdata).Render(r.Context(), w) } else { - err = components.ResultsPage(tdata).Render(r.Context(), w) + baseErr = components.ResultsPage(tdata).Render(r.Context(), w) } - if err != nil { - log.Error("template error", "template", importerType, "error", err) - errorHandler(w, r, err.Error(), http.StatusInternalServerError) + if baseErr != nil { + log.Error("template error", "template", importerType, "error", baseErr) + errorHandler(w, r, baseErr.Error(), http.StatusInternalServerError) } } else { w.Header().Add("Cache-Control", "max-age=14400")
@@ -244,15 +245,16 @@ Source: source,
Sources: sources, Assets: frontend.Assets, } + var baseErr error if r.Header.Get("Fetch") == "true" { w.Header().Add("Content-Type", "text/html; charset=utf-8") - err = components.Detail(*doc).Render(r.Context(), w) + baseErr = components.Detail(*doc).Render(r.Context(), w) } else { - err = components.DetailPage(tdata, *doc).Render(r.Context(), w) + baseErr = components.DetailPage(tdata, *doc).Render(r.Context(), w) } - if err != nil { - log.Error("template error", "template", importerSingular, "error", err) - errorHandler(w, r, err.Error(), http.StatusInternalServerError) + if baseErr != nil { + log.Error("template error", "template", importerSingular, "error", baseErr) + errorHandler(w, r, baseErr.Error(), http.StatusInternalServerError) } } }
M internal/server/server.gointernal/server/server.go
@@ -11,7 +11,7 @@ "go.alanpearce.eu/searchix/internal/config"
"go.alanpearce.eu/searchix/internal/index" "go.alanpearce.eu/x/log" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" )
@@ -28,7 +28,7 @@ conf *config.Config,
index *index.ReadIndex, log *log.Logger, liveReload bool, -) (*Server, error) { +) (*Server, errors.E) { mux, err := NewMux(conf, index, log, liveReload) if err != nil { return nil, err
@@ -49,7 +49,7 @@ },
}, nil } -func (s *Server) Start() error { +func (s *Server) Start() errors.E { listenAddress := net.JoinHostPort(s.cfg.Web.ListenAddress, strconv.Itoa(s.cfg.Web.Port)) l, err := net.Listen("tcp", listenAddress) if err != nil {
M searchix.gosearchix.go
@@ -14,7 +14,7 @@ "go.alanpearce.eu/searchix/internal/server"
"go.alanpearce.eu/x/log" "github.com/getsentry/sentry-go" - "github.com/pkg/errors" + "gitlab.com/tozd/go/errors" ) func nextUTCOccurrenceOfTime(t config.LocalTime) time.Time {
@@ -44,7 +44,7 @@ LowMemory bool
Logger *log.Logger } -func (s *Server) SetupIndex(ctx context.Context, options *IndexOptions) error { +func (s *Server) SetupIndex(ctx context.Context, options *IndexOptions) errors.E { var i uint cfgEnabledSources := make([]string, len(s.cfg.Importer.Sources)) for key := range s.cfg.Importer.Sources {
@@ -139,7 +139,7 @@ readIndex *index.ReadIndex
writeIndex *index.WriteIndex } -func New(cfg *config.Config, log *log.Logger) (*Server, error) { +func New(cfg *config.Config, log *log.Logger) (*Server, errors.E) { err := sentry.Init(sentry.ClientOptions{ EnableTracing: true, TracesSampleRate: 1.0,
@@ -164,7 +164,7 @@ localHub *sentry.Hub,
) { const monitorSlug = "import" localHub.WithScope(func(scope *sentry.Scope) { - var err error + var err errors.E scope.SetContext("monitor", sentry.Context{"slug": monitorSlug}) monitorConfig := &sentry.MonitorConfig{ Schedule: sentry.IntervalSchedule(1, sentry.MonitorScheduleUnitDay),
@@ -219,8 +219,8 @@ }
}) } -func (s *Server) Start(ctx context.Context, liveReload bool) error { - var err error +func (s *Server) Start(ctx context.Context, liveReload bool) errors.E { + var err errors.E s.sv, err = server.New(s.cfg, s.readIndex, s.log.Named("server"), liveReload) if err != nil { return errors.Wrap(err, "error setting up server")