* Don't rely on transparent decompression in sync list The current sync list code relies on the HTTP client library transparently decompressing the packages.gz file. This only works if the server provides the 'Content-Encoding: gzip" HTTP header, which has apparently changed recently. This patch explicitly decompresses the package list if no encoding information is provided by the server. Fixes: https://github.com/Jguer/yay/issues/2709 v2: added gzip closer and added error handling v3: blindly attempt to decompress, since the content encoding is stripped by the HTTP client when transparently decompressing. v4: also fix the fetch in command completion using common interface Signed-off-by: Edwin Peer <espeer@gmail.com> * fix failing tests, add fallback logging, add gz testcase * fix lint --------- Signed-off-by: Edwin Peer <espeer@gmail.com>
106 lines
2.4 KiB
Go
106 lines
2.4 KiB
Go
package completion
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/Jguer/yay/v12/pkg/db"
|
|
"github.com/Jguer/yay/v12/pkg/download"
|
|
"github.com/Jguer/yay/v12/pkg/text"
|
|
)
|
|
|
|
type PkgSynchronizer interface {
|
|
SyncPackages(...string) []db.IPackage
|
|
}
|
|
|
|
// Show provides completion info for shells.
|
|
func Show(ctx context.Context, httpClient download.HTTPRequestDoer,
|
|
dbExecutor PkgSynchronizer, aurURL, completionPath string, interval int, force bool, logger *text.Logger,
|
|
) error {
|
|
err := Update(ctx, httpClient, dbExecutor, aurURL, completionPath, interval, force, logger)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
in, err := os.OpenFile(completionPath, os.O_RDWR|os.O_CREATE, 0o644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer in.Close()
|
|
|
|
_, err = io.Copy(os.Stdout, in)
|
|
|
|
return err
|
|
}
|
|
|
|
// Update updates completion cache to be used by Complete.
|
|
func Update(ctx context.Context, httpClient download.HTTPRequestDoer,
|
|
dbExecutor PkgSynchronizer, aurURL, completionPath string, interval int, force bool, logger *text.Logger,
|
|
) error {
|
|
info, err := os.Stat(completionPath)
|
|
|
|
if os.IsNotExist(err) || (interval != -1 && time.Since(info.ModTime()).Hours() >= float64(interval*24)) || force {
|
|
errd := os.MkdirAll(filepath.Dir(completionPath), 0o755)
|
|
if errd != nil {
|
|
return errd
|
|
}
|
|
|
|
out, errf := os.Create(completionPath)
|
|
if errf != nil {
|
|
return errf
|
|
}
|
|
|
|
if createAURList(ctx, httpClient, aurURL, out, logger) != nil {
|
|
defer os.Remove(completionPath)
|
|
}
|
|
|
|
erra := createRepoList(dbExecutor, out)
|
|
|
|
out.Close()
|
|
|
|
return erra
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// createAURList creates a new completion file.
|
|
func createAURList(ctx context.Context, client download.HTTPRequestDoer, aurURL string, out io.Writer, logger *text.Logger) error {
|
|
scanner, err := download.GetPackageScanner(ctx, client, aurURL, logger)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer scanner.Close()
|
|
|
|
scanner.Scan()
|
|
|
|
for scanner.Scan() {
|
|
pkgName := scanner.Text()
|
|
if strings.HasPrefix(pkgName, "#") {
|
|
continue
|
|
}
|
|
|
|
if _, err := io.WriteString(out, pkgName+"\tAUR\n"); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// createRepoList appends Repo packages to completion cache.
|
|
func createRepoList(dbExecutor PkgSynchronizer, out io.Writer) error {
|
|
for _, pkg := range dbExecutor.SyncPackages() {
|
|
_, err := io.WriteString(out, pkg.Name()+"\t"+pkg.DB().Name()+"\n")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|