diff --git a/.golangci.yml b/.golangci.yml index fdf5289a..5fbfafb7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,18 +19,28 @@ linters-settings: goimports: local-prefixes: github.com/Jguer/yay/v11 gomnd: - settings: - mnd: - # don't include the "operation" and "assign" - checks: argument,case,condition,return + checks: + - argument + - case + - condition + - return + ignored-numbers: + - '0' + - '1' + - '2' + - '3' + ignored-functions: + - strings.SplitN govet: check-shadowing: true lll: line-length: 140 - maligned: - suggest-new: true misspell: locale: US + nolintlint: + allow-unused: false # report any unused nolint directives + require-explanation: false # don't require an explanation for nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped linters: # please, do not use `enable-all`: it's deprecated and will be removed soon. @@ -38,15 +48,19 @@ linters: disable-all: true enable: - bodyclose - - usestdlibvars - - deadcode - depguard + - dogsled - dupl - errcheck + - exportloopref + # - funlen # TOFIX - gochecknoinits + # - goconst # TOFIX - gocritic + # - gocyclo # TOFIX - gofmt - goimports + # - gomnd # TOFIX - goprintffuncname - gosec - gosimple @@ -55,28 +69,15 @@ linters: - lll - misspell - nakedret - - prealloc - - revive - - rowserrcheck + - noctx + - nolintlint - staticcheck - - structcheck - stylecheck - typecheck - unconvert - unparam - unused - - tenv - - varcheck - whitespace - - wsl - - godot - # - maligned - # - interfacer - # - nilerr - # - nlreturn - # - exhaustivestruct - # - errname - # - forbidigo run: go: '1.18' diff --git a/cmd.go b/cmd.go index 47414836..dcd3d96c 100644 --- a/cmd.go +++ b/cmd.go @@ -331,7 +331,7 @@ func handleUpgrade(ctx context.Context, config *settings.Configuration, dbExecutor db.Executor, cmdArgs *parser.Arguments, ) error { if cmdArgs.ExistsArg("i", "install") { - return installLocalPKGBUILD(ctx, cmdArgs, dbExecutor) + return installLocalPKGBUILD(ctx, config, cmdArgs, dbExecutor) } return config.Runtime.CmdBuilder.Show(config.Runtime.CmdBuilder.BuildPacmanCmd(ctx, diff --git a/local_install.go b/local_install.go index 853695cc..7a84868d 100644 --- a/local_install.go +++ b/local_install.go @@ -9,7 +9,6 @@ import ( "github.com/Jguer/yay/v11/pkg/db" "github.com/Jguer/yay/v11/pkg/dep" - "github.com/Jguer/yay/v11/pkg/metadata" "github.com/Jguer/yay/v11/pkg/settings" "github.com/Jguer/yay/v11/pkg/settings/parser" "github.com/Jguer/yay/v11/pkg/text" @@ -23,13 +22,11 @@ var ErrInstallRepoPkgs = errors.New(gotext.Get("error installing repo packages") func installLocalPKGBUILD( ctx context.Context, + config *settings.Configuration, cmdArgs *parser.Arguments, dbExecutor db.Executor, ) error { - aurCache, err := metadata.NewAURCache(filepath.Join(config.BuildDir, "aur.json")) - if err != nil { - return errors.Wrap(err, gotext.Get("failed to retrieve aur Cache")) - } + aurCache := config.Runtime.AURCache wd, err := os.Getwd() if err != nil { diff --git a/pkg/cmd/graph/main.go b/pkg/cmd/graph/main.go index c52a4c9f..d94bfbdd 100644 --- a/pkg/cmd/graph/main.go +++ b/pkg/cmd/graph/main.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "net/http" "os" "path/filepath" @@ -38,7 +39,7 @@ func handleCmd() error { return err } - aurCache, err := metadata.NewAURCache(filepath.Join(config.BuildDir, "aur.json")) + aurCache, err := metadata.NewAURCache(http.DefaultClient, filepath.Join(config.BuildDir, "aur.json")) if err != nil { return errors.Wrap(err, gotext.Get("failed to retrieve aur Cache")) } diff --git a/pkg/dep/depGraph.go b/pkg/dep/depGraph.go index d54af867..ddf9b9b4 100644 --- a/pkg/dep/depGraph.go +++ b/pkg/dep/depGraph.go @@ -90,7 +90,7 @@ var colorMap = map[Reason]string{ type Grapher struct { dbExecutor db.Executor - aurCache *metadata.AURCache + aurCache *metadata.AURCacheClient fullGraph bool // If true, the graph will include all dependencies including already installed ones or repo noConfirm bool w io.Writer // output writer @@ -98,7 +98,7 @@ type Grapher struct { providerCache map[string]*aur.Pkg } -func NewGrapher(dbExecutor db.Executor, aurCache *metadata.AURCache, +func NewGrapher(dbExecutor db.Executor, aurCache *metadata.AURCacheClient, fullGraph, noConfirm bool, output io.Writer, ) *Grapher { return &Grapher{ diff --git a/pkg/metadata/metadata_aur.go b/pkg/metadata/metadata_aur.go index 767b3cf6..7f9fb124 100644 --- a/pkg/metadata/metadata_aur.go +++ b/pkg/metadata/metadata_aur.go @@ -15,11 +15,12 @@ const ( cacheValidity = 1 * time.Hour ) -type AURCache struct { - cache []byte - cachePath string +type AURCacheClient struct { + httpClient HTTPRequestDoer + cachePath string + DebugLoggerFn func(a ...interface{}) + unmarshalledCache []interface{} - DebugLoggerFn func(a ...interface{}) } type AURQuery struct { @@ -28,29 +29,25 @@ type AURQuery struct { Contains bool // if true, search for packages containing the needle, not exact matches } -func NewAURCache(cachePath string) (*AURCache, error) { - aurCache, err := MakeOrReadCache(cachePath) - if err != nil { - return nil, err - } +// ClientOption allows setting custom parameters during construction. +type ClientOption func(*AURCacheClient) error - inputStruct, err := oj.Parse(aurCache) - if err != nil { - return nil, fmt.Errorf("aur metadata unable to parse cache: %w", err) - } - - return &AURCache{ - cache: aurCache, - cachePath: cachePath, - unmarshalledCache: inputStruct.([]interface{}), +func NewAURCache(httpClient HTTPRequestDoer, cachePath string, opts ...ClientOption) (*AURCacheClient, error) { + return &AURCacheClient{ + httpClient: httpClient, + cachePath: cachePath, }, nil } // needsUpdate checks if cachepath is older than 24 hours. -func (a *AURCache) needsUpdate() (bool, error) { +func (a *AURCacheClient) needsUpdate() (bool, error) { // check if cache is older than 24 hours info, err := os.Stat(a.cachePath) if err != nil { + if os.IsNotExist(err) { + return true, nil + } + return false, fmt.Errorf("unable to read cache: %w", err) } @@ -58,30 +55,7 @@ func (a *AURCache) needsUpdate() (bool, error) { } // Get returns a list of packages that provide the given search term. -func (a *AURCache) Get(ctx context.Context, query *AURQuery) ([]*aur.Pkg, error) { - update, err := a.needsUpdate() - if err != nil { - return nil, err - } - - if update { - if a.DebugLoggerFn != nil { - a.DebugLoggerFn("AUR Cache is out of date, updating") - } - - var makeErr error - if a.cache, makeErr = MakeCache(a.cachePath); makeErr != nil { - return nil, makeErr - } - - inputStruct, unmarshallErr := oj.Parse(a.cache) - if unmarshallErr != nil { - return nil, fmt.Errorf("aur metadata unable to parse cache: %w", unmarshallErr) - } - - a.unmarshalledCache = inputStruct.([]interface{}) - } - +func (a *AURCacheClient) Get(ctx context.Context, query *AURQuery) ([]*aur.Pkg, error) { found := make([]*aur.Pkg, 0, len(query.Needles)) if len(query.Needles) == 0 { return found, nil @@ -97,7 +71,49 @@ func (a *AURCache) Get(ctx context.Context, query *AURQuery) ([]*aur.Pkg, error) return found, nil } -func (a *AURCache) gojqGetBatch(ctx context.Context, query *AURQuery) ([]*aur.Pkg, error) { +func (a *AURCacheClient) cache(ctx context.Context) ([]interface{}, error) { + if a.unmarshalledCache != nil { + return a.unmarshalledCache, nil + } + + update, err := a.needsUpdate() + if err != nil { + return nil, err + } + + if update { + if a.DebugLoggerFn != nil { + a.DebugLoggerFn("AUR Cache is out of date, updating") + } + cache, makeErr := MakeCache(ctx, a.httpClient, a.cachePath) + if makeErr != nil { + return nil, makeErr + } + + inputStruct, unmarshallErr := oj.Parse(cache) + if unmarshallErr != nil { + return nil, fmt.Errorf("aur metadata unable to parse cache: %w", unmarshallErr) + } + + a.unmarshalledCache = inputStruct.([]interface{}) + } else { + aurCache, err := ReadCache(a.cachePath) + if err != nil { + return nil, err + } + + inputStruct, err := oj.Parse(aurCache) + if err != nil { + return nil, fmt.Errorf("aur metadata unable to parse cache: %w", err) + } + + a.unmarshalledCache = inputStruct.([]interface{}) + } + + return a.unmarshalledCache, nil +} + +func (a *AURCacheClient) gojqGetBatch(ctx context.Context, query *AURQuery) ([]*aur.Pkg, error) { pattern := ".[] | select(" for i, searchTerm := range query.Needles { @@ -130,8 +146,13 @@ func (a *AURCache) gojqGetBatch(ctx context.Context, query *AURQuery) ([]*aur.Pk return nil, fmt.Errorf("unable to parse query: %w", err) } + unmarshalledCache, errCache := a.cache(ctx) + if errCache != nil { + return nil, errCache + } + final := make([]*aur.Pkg, 0, len(query.Needles)) - iter := parsed.RunWithContext(ctx, a.unmarshalledCache) // or query.RunWithContext + iter := parsed.RunWithContext(ctx, unmarshalledCache) // or query.RunWithContext for pkgMap, ok := iter.Next(); ok; pkgMap, ok = iter.Next() { if err, ok := pkgMap.(error); ok { diff --git a/pkg/metadata/metadata_downloader.go b/pkg/metadata/metadata_downloader.go index 6069f6e6..81828b65 100644 --- a/pkg/metadata/metadata_downloader.go +++ b/pkg/metadata/metadata_downloader.go @@ -1,26 +1,15 @@ package metadata import ( + "context" "fmt" "io" "net/http" "os" ) -func MakeOrReadCache(cachePath string) ([]byte, error) { - cacheBytes, err := ReadCache(cachePath) - if err != nil { - return nil, err - } - - if len(cacheBytes) == 0 { - cacheBytes, err = MakeCache(cachePath) - if err != nil { - return nil, err - } - } - - return cacheBytes, nil +type HTTPRequestDoer interface { + Do(req *http.Request) (*http.Response, error) } func ReadCache(cachePath string) ([]byte, error) { @@ -46,8 +35,8 @@ func ReadCache(cachePath string) ([]byte, error) { // Download the metadata for aur packages. // create cache file // write to cache file. -func MakeCache(cachePath string) ([]byte, error) { - body, err := downloadAURMetadata() +func MakeCache(ctx context.Context, httpClient HTTPRequestDoer, cachePath string) ([]byte, error) { + body, err := downloadAURMetadata(ctx, httpClient) if err != nil { return nil, err } @@ -71,8 +60,13 @@ func MakeCache(cachePath string) ([]byte, error) { return s, err } -func downloadAURMetadata() (io.ReadCloser, error) { - resp, err := http.Get("https://aur.archlinux.org/packages-meta-ext-v1.json.gz") +func downloadAURMetadata(ctx context.Context, httpClient HTTPRequestDoer) (io.ReadCloser, error) { + req, err := http.NewRequestWithContext(ctx, "GET", "https://aur.archlinux.org/packages-meta-ext-v1.json.gz", http.NoBody) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + + resp, err := httpClient.Do(req) if err != nil { return nil, err } diff --git a/pkg/query/source.go b/pkg/query/source.go index 78bfe5dd..09b89427 100644 --- a/pkg/query/source.go +++ b/pkg/query/source.go @@ -39,12 +39,12 @@ type SourceQueryBuilder struct { singleLineResults bool aurClient aur.ClientInterface - aurCache *metadata.AURCache + aurCache *metadata.AURCacheClient } func NewSourceQueryBuilder( aurClient aur.ClientInterface, - aurCache *metadata.AURCache, + aurCache *metadata.AURCacheClient, sortBy string, targetMode parser.TargetMode, searchBy string, @@ -192,7 +192,7 @@ func filterAURResults(pkgS []string, results []aur.Pkg) []aur.Pkg { // queryAUR searches AUR and narrows based on subarguments. func queryAUR(ctx context.Context, - aurClient aur.ClientInterface, aurMetadata *metadata.AURCache, + aurClient aur.ClientInterface, aurMetadata *metadata.AURCacheClient, pkgS []string, searchBy string, newEngine bool, ) ([]aur.Pkg, error) { var ( diff --git a/pkg/settings/config.go b/pkg/settings/config.go index 1ae19fea..a912599b 100644 --- a/pkg/settings/config.go +++ b/pkg/settings/config.go @@ -291,7 +291,7 @@ func NewConfig(version string) (*Configuration, error) { var errAURCache error - newConfig.Runtime.AURCache, errAURCache = metadata.NewAURCache(filepath.Join(newConfig.BuildDir, "aur.json")) + newConfig.Runtime.AURCache, errAURCache = metadata.NewAURCache(newConfig.Runtime.HTTPClient, filepath.Join(newConfig.BuildDir, "aur.json")) if errAURCache != nil { return nil, errors.Wrap(errAURCache, gotext.Get("failed to retrieve aur Cache")) } diff --git a/pkg/settings/runtime.go b/pkg/settings/runtime.go index 8c6e907a..b7702c4e 100644 --- a/pkg/settings/runtime.go +++ b/pkg/settings/runtime.go @@ -29,6 +29,6 @@ type Runtime struct { HTTPClient *http.Client AURClient *aur.Client VoteClient *vote.Client - AURCache *metadata.AURCache + AURCache *metadata.AURCacheClient DBExecutor db.Executor } diff --git a/upgrade.go b/upgrade.go index f8440cfb..d4309ffe 100644 --- a/upgrade.go +++ b/upgrade.go @@ -37,7 +37,7 @@ func filterUpdateList(list []db.Upgrade, filter upgrade.Filter) []db.Upgrade { } // upList returns lists of packages to upgrade from each source. -func upList(ctx context.Context, aurCache *metadata.AURCache, +func upList(ctx context.Context, aurCache *metadata.AURCacheClient, warnings *query.AURWarnings, dbExecutor db.Executor, enableDowngrade bool, filter upgrade.Filter, ) (aurUp, repoUp upgrade.UpSlice, err error) { @@ -261,7 +261,7 @@ func sysupgradeTargets(ctx context.Context, dbExecutor db.Executor, // Targets for sys upgrade. func sysupgradeTargetsV2(ctx context.Context, - aurCache *metadata.AURCache, + aurCache *metadata.AURCacheClient, dbExecutor db.Executor, graph *topo.Graph[string, *dep.InstallInfo], enableDowngrade bool,