mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-07-02 09:47:46 +00:00
Merge pull request #1550 from linuxdataflow/feat/pls/gcs-support
Add support for GCS.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
version: "2"
|
||||
run:
|
||||
timeout: 5m
|
||||
linters:
|
||||
settings:
|
||||
staticcheck:
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -41,6 +42,17 @@ func createTestConfig() *os.File {
|
||||
jsonString, err := json.Marshal(gin.H{
|
||||
"architectures": []string{},
|
||||
"enableMetricsEndpoint": true,
|
||||
"S3PublishEndpoints": map[string]map[string]string{
|
||||
"test-s3": {
|
||||
"region": "us-east-1",
|
||||
"bucket": "bucket-s3",
|
||||
},
|
||||
},
|
||||
"GcsPublishEndpoints": map[string]map[string]string{
|
||||
"test-gcs": {
|
||||
"bucket": "bucket-gcs",
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -173,3 +185,27 @@ func (s *APISuite) TestTruthy(c *C) {
|
||||
c.Check(truthy(-1), Equals, true)
|
||||
c.Check(truthy(gin.H{}), Equals, true)
|
||||
}
|
||||
|
||||
func (s *APISuite) TestGetS3Endpoints(c *C) {
|
||||
response, err := s.HTTPRequest("GET", "/api/s3", nil)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(response.Code, Equals, 200)
|
||||
|
||||
var endpoints []string
|
||||
err = json.Unmarshal(response.Body.Bytes(), &endpoints)
|
||||
c.Assert(err, IsNil)
|
||||
sort.Strings(endpoints)
|
||||
c.Check(endpoints, DeepEquals, []string{"test-s3"})
|
||||
}
|
||||
|
||||
func (s *APISuite) TestGetGCSEndpoints(c *C) {
|
||||
response, err := s.HTTPRequest("GET", "/api/gcs", nil)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(response.Code, Equals, 200)
|
||||
|
||||
var endpoints []string
|
||||
err = json.Unmarshal(response.Body.Bytes(), &endpoints)
|
||||
c.Assert(err, IsNil)
|
||||
sort.Strings(endpoints)
|
||||
c.Check(endpoints, DeepEquals, []string{"test-gcs"})
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Summary GCS buckets
|
||||
// @Description **Get list of GCS buckets**
|
||||
// @Description
|
||||
// @Description List configured GCS buckets.
|
||||
// @Tags Status
|
||||
// @Produce json
|
||||
// @Success 200 {array} string "List of GCS buckets"
|
||||
// @Router /api/gcs [get]
|
||||
func apiGCSList(c *gin.Context) {
|
||||
keys := []string{}
|
||||
for k := range context.Config().GCSPublishRoots {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
c.JSON(200, keys)
|
||||
}
|
||||
@@ -177,6 +177,7 @@ func Router(c *ctx.AptlyContext) http.Handler {
|
||||
|
||||
{
|
||||
api.GET("/s3", apiS3List)
|
||||
api.GET("/gcs", apiGCSList)
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/aptly-dev/aptly/database/goleveldb"
|
||||
"github.com/aptly-dev/aptly/deb"
|
||||
"github.com/aptly-dev/aptly/files"
|
||||
"github.com/aptly-dev/aptly/gcs"
|
||||
"github.com/aptly-dev/aptly/http"
|
||||
"github.com/aptly-dev/aptly/pgp"
|
||||
"github.com/aptly-dev/aptly/s3"
|
||||
@@ -437,6 +438,20 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto
|
||||
if err != nil {
|
||||
Fatal(err)
|
||||
}
|
||||
} else if strings.HasPrefix(name, "gcs:") {
|
||||
params, ok := context.config().GCSPublishRoots[name[4:]]
|
||||
if !ok {
|
||||
Fatal(fmt.Errorf("published GCS storage %v not configured", name[4:]))
|
||||
}
|
||||
|
||||
var err error
|
||||
publishedStorage, err = gcs.NewPublishedStorage(
|
||||
params.Bucket, params.Prefix, params.CredentialsFile, params.ServiceAccountJSON,
|
||||
params.Project, params.Endpoint, params.ACL, params.StorageClass, params.EncryptionKey,
|
||||
params.DisableMultiDel, params.Debug)
|
||||
if err != nil {
|
||||
Fatal(err)
|
||||
}
|
||||
} else if strings.HasPrefix(name, "swift:") {
|
||||
params, ok := context.config().SwiftPublishRoots[name[6:]]
|
||||
if !ok {
|
||||
|
||||
Vendored
+52
@@ -256,6 +256,58 @@ s3_publish_endpoints:
|
||||
# # Enables detailed request/response dump for each S3 operation
|
||||
# debug: false
|
||||
|
||||
# GCS Endpoint Support
|
||||
#
|
||||
# aptly can be configured to publish repositories directly to Google Cloud
|
||||
# Storage. First, publishing endpoints should be described in the aptly
|
||||
# configuration file. Each endpoint has a name and associated settings.
|
||||
#
|
||||
# In order to publish to GCS, specify endpoint as `gcs:endpoint-name:` before
|
||||
# publishing prefix on the command line, e.g.:
|
||||
#
|
||||
# `aptly publish snapshot wheezy-main gcs:test:`
|
||||
#
|
||||
gcs_publish_endpoints:
|
||||
# # Endpoint Name
|
||||
# test:
|
||||
# # Bucket name
|
||||
# bucket: test-bucket
|
||||
# # Prefix (optional)
|
||||
# # publishing under specified prefix in the bucket, defaults to
|
||||
# # no prefix (bucket root)
|
||||
# prefix: ""
|
||||
# # Credentials File (optional)
|
||||
# # Path to a service account credentials JSON file
|
||||
# credentials_file: ""
|
||||
# # Service Account JSON (optional)
|
||||
# # Inline service account credentials JSON payload
|
||||
# service_account_json: ""
|
||||
# # Project (optional)
|
||||
# # Quota project used for GCS requests
|
||||
# project: ""
|
||||
# # Endpoint (optional)
|
||||
# # Override the GCS endpoint (e.g. for staging or a fake server);
|
||||
# # leave empty to use the default GCS endpoint
|
||||
# endpoint: ""
|
||||
# # Default ACLs (optional)
|
||||
# # assign ACL to published files:
|
||||
# # * private (default)
|
||||
# # * public-read (public repository)
|
||||
# # * none (don't set ACL)
|
||||
# acl: private
|
||||
# # Storage Class (optional)
|
||||
# # GCS storage class, e.g. `STANDARD`
|
||||
# storage_class: STANDARD
|
||||
# # Encryption Key (optional)
|
||||
# # Customer-supplied encryption key (32-byte AES-256 key)
|
||||
# encryption_key: ""
|
||||
# # Disable MultiDel (optional)
|
||||
# # Kept for parity with S3 settings; GCS deletes are one-by-one
|
||||
# disable_multidel: false
|
||||
# # Debug (optional)
|
||||
# # Enables detailed logs for each GCS operation
|
||||
# debug: false
|
||||
|
||||
# Swift Endpoint Support
|
||||
#
|
||||
# aptly can publish a repository directly to OpenStack Swift.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
// Package gcs handles publishing to Google Cloud Storage.
|
||||
package gcs
|
||||
@@ -0,0 +1,12 @@
|
||||
package gcs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
// Launch gocheck tests.
|
||||
func Test(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
||||
+422
@@ -0,0 +1,422 @@
|
||||
package gcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
"github.com/aptly-dev/aptly/aptly"
|
||||
"github.com/aptly-dev/aptly/utils"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/api/iterator"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
// PublishedStorage abstracts published files hosted on GCS.
|
||||
type PublishedStorage struct {
|
||||
client *storage.Client
|
||||
bucket *storage.BucketHandle
|
||||
bucketName string
|
||||
prefix string
|
||||
acl string
|
||||
storageClass string
|
||||
encryptionKey string
|
||||
disableMultiDel bool
|
||||
debug bool
|
||||
pathCache map[string]string
|
||||
}
|
||||
|
||||
var (
|
||||
_ aptly.PublishedStorage = (*PublishedStorage)(nil)
|
||||
)
|
||||
|
||||
// NewPublishedStorage creates a GCS-backed published storage.
|
||||
func NewPublishedStorage(bucket, prefix, credentialsFile, serviceAccountJSON,
|
||||
project, endpoint, defaultACL, storageClass, encryptionKey string,
|
||||
disableMultiDel, debug bool) (*PublishedStorage, error) {
|
||||
|
||||
ctx := context.TODO()
|
||||
opts := make([]option.ClientOption, 0, 4)
|
||||
|
||||
if endpoint != "" {
|
||||
opts = append(opts, option.WithEndpoint(endpoint), option.WithoutAuthentication())
|
||||
} else if credentialsFile != "" {
|
||||
opts = append(opts, option.WithAuthCredentialsFile(option.ServiceAccount, credentialsFile))
|
||||
} else if serviceAccountJSON != "" {
|
||||
opts = append(opts, option.WithAuthCredentialsJSON(option.ServiceAccount, []byte(serviceAccountJSON)))
|
||||
}
|
||||
|
||||
if project != "" {
|
||||
opts = append(opts, option.WithQuotaProject(project))
|
||||
}
|
||||
|
||||
// When pointing at a non-production endpoint (an explicit override or the
|
||||
// STORAGE_EMULATOR_HOST hook the GCS Go client honours natively), force
|
||||
// JSON reads. The default XML download API uses virtual-host-style URLs
|
||||
// (https://<bucket>.storage.googleapis.com/...) that emulators and most
|
||||
// dev/staging endpoints can't serve under a single listener; the JSON API
|
||||
// uses path-based URLs that work the same against real GCS or an emulator.
|
||||
if endpoint != "" || os.Getenv("STORAGE_EMULATOR_HOST") != "" {
|
||||
opts = append(opts, storage.WithJSONReads())
|
||||
}
|
||||
|
||||
client, err := storage.NewClient(ctx, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &PublishedStorage{
|
||||
client: client,
|
||||
bucket: client.Bucket(bucket),
|
||||
bucketName: bucket,
|
||||
prefix: prefix,
|
||||
acl: defaultACL,
|
||||
storageClass: storageClass,
|
||||
encryptionKey: encryptionKey,
|
||||
disableMultiDel: disableMultiDel,
|
||||
debug: debug,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (g *PublishedStorage) String() string {
|
||||
return fmt.Sprintf("GCS: %s/%s", g.bucketName, g.prefix)
|
||||
}
|
||||
|
||||
// MkDir creates directory recursively under public path.
|
||||
func (g *PublishedStorage) MkDir(_ string) error {
|
||||
// no-op for GCS
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *PublishedStorage) objectPath(path string) string {
|
||||
return filepath.Join(g.prefix, path)
|
||||
}
|
||||
|
||||
func (g *PublishedStorage) objectHandle(path string) *storage.ObjectHandle {
|
||||
obj := g.bucket.Object(g.objectPath(path))
|
||||
if g.encryptionKey != "" {
|
||||
obj = obj.Key([]byte(g.encryptionKey))
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
// PutFile puts file into published storage at specified path.
|
||||
func (g *PublishedStorage) PutFile(path string, sourceFilename string) error {
|
||||
source, err := os.Open(sourceFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = source.Close() }()
|
||||
|
||||
if g.debug {
|
||||
log.Debug().Msgf("GCS: PutFile '%s'", path)
|
||||
}
|
||||
|
||||
err = g.putFile(path, source, "")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("error uploading %s to %s", sourceFilename, g))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *PublishedStorage) applyACL(obj *storage.ObjectHandle) error {
|
||||
switch g.acl {
|
||||
case "", "none", "private":
|
||||
return nil
|
||||
case "public-read":
|
||||
return obj.ACL().Set(context.TODO(), storage.AllUsers, storage.RoleReader)
|
||||
default:
|
||||
return fmt.Errorf("unsupported GCS ACL value: %s", g.acl)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *PublishedStorage) putFile(path string, source io.Reader, sourceMD5 string) error {
|
||||
obj := g.objectHandle(path)
|
||||
writer := obj.NewWriter(context.TODO())
|
||||
|
||||
if g.storageClass != "" {
|
||||
writer.StorageClass = g.storageClass
|
||||
}
|
||||
if sourceMD5 != "" {
|
||||
writer.Metadata = map[string]string{"Md5": sourceMD5}
|
||||
}
|
||||
|
||||
if _, err := io.Copy(writer, source); err != nil {
|
||||
_ = writer.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := writer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return g.applyACL(obj)
|
||||
}
|
||||
|
||||
func (g *PublishedStorage) getMD5(path string) (string, error) {
|
||||
attrs, err := g.objectHandle(path).Attrs(context.TODO())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if attrs.Metadata != nil {
|
||||
if md5, ok := attrs.Metadata["Md5"]; ok && md5 != "" {
|
||||
return strings.ToLower(md5), nil
|
||||
}
|
||||
}
|
||||
|
||||
return strings.ToLower(hex.EncodeToString(attrs.MD5)), nil
|
||||
}
|
||||
|
||||
// Remove removes single file under public path.
|
||||
func (g *PublishedStorage) Remove(path string) error {
|
||||
if g.debug {
|
||||
log.Debug().Msgf("GCS: Remove '%s'", path)
|
||||
}
|
||||
|
||||
err := g.objectHandle(path).Delete(context.TODO())
|
||||
if err != nil {
|
||||
if err == storage.ErrObjectNotExist {
|
||||
return nil
|
||||
}
|
||||
|
||||
var apiErr *googleapi.Error
|
||||
if errors.As(err, &apiErr) && apiErr.Code == 404 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.Wrap(err, fmt.Sprintf("error deleting %s from %s", path, g))
|
||||
}
|
||||
|
||||
delete(g.pathCache, path)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveDirs removes directory structure under public path.
|
||||
func (g *PublishedStorage) RemoveDirs(path string, _ aptly.Progress) error {
|
||||
filelist, _, err := g.internalFilelist(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if g.debug {
|
||||
log.Debug().Msgf("GCS: RemoveDirs '%s'", path)
|
||||
}
|
||||
|
||||
for _, file := range filelist {
|
||||
objPath := filepath.Join(path, file)
|
||||
if err := g.Remove(objPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_ = g.disableMultiDel
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LinkFromPool links package file from pool to dist's pool location.
|
||||
func (g *PublishedStorage) LinkFromPool(publishedPrefix, publishedRelPath, fileName string, sourcePool aptly.PackagePool,
|
||||
sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error {
|
||||
|
||||
publishedDirectory := filepath.Join(publishedPrefix, publishedRelPath)
|
||||
relPath := filepath.Join(publishedDirectory, fileName)
|
||||
poolPath := filepath.Join(g.prefix, relPath)
|
||||
|
||||
if g.pathCache == nil {
|
||||
paths, md5s, err := g.internalFilelist(filepath.Join(publishedPrefix, "pool"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error caching paths under prefix")
|
||||
}
|
||||
|
||||
g.pathCache = make(map[string]string, len(paths))
|
||||
for i := range paths {
|
||||
g.pathCache[filepath.Join(publishedPrefix, "pool", paths[i])] = md5s[i]
|
||||
}
|
||||
}
|
||||
|
||||
destinationMD5, exists := g.pathCache[relPath]
|
||||
sourceMD5 := strings.ToLower(sourceChecksums.MD5)
|
||||
|
||||
if exists {
|
||||
if sourceMD5 == "" {
|
||||
return fmt.Errorf("unable to compare object, MD5 checksum missing")
|
||||
}
|
||||
|
||||
if len(destinationMD5) != 32 {
|
||||
var err error
|
||||
destinationMD5, err = g.getMD5(relPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("error verifying MD5 for %s: %s", g, poolPath))
|
||||
}
|
||||
g.pathCache[relPath] = destinationMD5
|
||||
}
|
||||
|
||||
if destinationMD5 == sourceMD5 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !force {
|
||||
return fmt.Errorf("error putting file to %s: file already exists and is different: %s", poolPath, g)
|
||||
}
|
||||
}
|
||||
|
||||
source, err := sourcePool.Open(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = source.Close() }()
|
||||
|
||||
if g.debug {
|
||||
log.Debug().Msgf("GCS: LinkFromPool '%s'", relPath)
|
||||
}
|
||||
|
||||
err = g.putFile(relPath, source, sourceMD5)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("error uploading %s to %s: %s", sourcePath, g, poolPath))
|
||||
}
|
||||
|
||||
g.pathCache[relPath] = sourceMD5
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Filelist returns list of files under prefix.
|
||||
func (g *PublishedStorage) Filelist(prefix string) ([]string, error) {
|
||||
paths, _, err := g.internalFilelist(prefix)
|
||||
return paths, err
|
||||
}
|
||||
|
||||
func (g *PublishedStorage) internalFilelist(prefix string) ([]string, []string, error) {
|
||||
paths := make([]string, 0, 1024)
|
||||
md5s := make([]string, 0, 1024)
|
||||
|
||||
fullPrefix := filepath.Join(g.prefix, prefix)
|
||||
if fullPrefix != "" {
|
||||
fullPrefix += "/"
|
||||
}
|
||||
|
||||
it := g.bucket.Objects(context.TODO(), &storage.Query{Prefix: fullPrefix})
|
||||
for {
|
||||
attrs, err := it.Next()
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, errors.WithMessagef(err, "error listing under prefix %s in %s", fullPrefix, g)
|
||||
}
|
||||
|
||||
path := attrs.Name
|
||||
if fullPrefix != "" {
|
||||
path = strings.TrimPrefix(path, fullPrefix)
|
||||
}
|
||||
paths = append(paths, path)
|
||||
|
||||
if attrs.Metadata != nil {
|
||||
if md5, ok := attrs.Metadata["Md5"]; ok && md5 != "" {
|
||||
md5s = append(md5s, strings.ToLower(md5))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
md5s = append(md5s, strings.ToLower(hex.EncodeToString(attrs.MD5)))
|
||||
}
|
||||
|
||||
return paths, md5s, nil
|
||||
}
|
||||
|
||||
// RenameFile renames (moves) file.
|
||||
func (g *PublishedStorage) RenameFile(oldName, newName string) error {
|
||||
src := g.objectHandle(oldName)
|
||||
dst := g.objectHandle(newName)
|
||||
|
||||
if g.debug {
|
||||
log.Debug().Msgf("GCS: RenameFile %s -> %s", oldName, newName)
|
||||
}
|
||||
|
||||
_, err := dst.CopierFrom(src).Run(context.TODO())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error copying %s -> %s in %s: %s", oldName, newName, g, err)
|
||||
}
|
||||
|
||||
err = g.applyACL(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return g.Remove(oldName)
|
||||
}
|
||||
|
||||
// SymLink creates a copy of src file and stores link information in metadata.
|
||||
func (g *PublishedStorage) SymLink(src string, dst string) error {
|
||||
source := g.objectHandle(src)
|
||||
dest := g.objectHandle(dst)
|
||||
|
||||
if g.debug {
|
||||
log.Debug().Msgf("GCS: SymLink %s -> %s", src, dst)
|
||||
}
|
||||
|
||||
_, err := dest.CopierFrom(source).Run(context.TODO())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error symlinking %s -> %s in %s: %s", src, dst, g, err)
|
||||
}
|
||||
|
||||
_, err = dest.Update(context.TODO(), storage.ObjectAttrsToUpdate{
|
||||
Metadata: map[string]string{"SymLink": src},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error updating symlink metadata %s -> %s in %s: %s", src, dst, g, err)
|
||||
}
|
||||
|
||||
return g.applyACL(dest)
|
||||
}
|
||||
|
||||
// HardLink uses symlink functionality as hard links do not exist on object stores.
|
||||
func (g *PublishedStorage) HardLink(src string, dst string) error {
|
||||
if g.debug {
|
||||
log.Debug().Msgf("GCS: HardLink %s -> %s", src, dst)
|
||||
}
|
||||
|
||||
return g.SymLink(src, dst)
|
||||
}
|
||||
|
||||
// FileExists returns true if path exists.
|
||||
func (g *PublishedStorage) FileExists(path string) (bool, error) {
|
||||
_, err := g.objectHandle(path).Attrs(context.TODO())
|
||||
if err != nil {
|
||||
if err == storage.ErrObjectNotExist {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var apiErr *googleapi.Error
|
||||
if errors.As(err, &apiErr) && apiErr.Code == 404 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ReadLink returns symbolic link target from metadata.
|
||||
func (g *PublishedStorage) ReadLink(path string) (string, error) {
|
||||
attrs, err := g.objectHandle(path).Attrs(context.TODO())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return attrs.Metadata["SymLink"], nil
|
||||
}
|
||||
@@ -0,0 +1,530 @@
|
||||
package gcs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
"github.com/fsouza/fake-gcs-server/fakestorage"
|
||||
. "gopkg.in/check.v1"
|
||||
|
||||
"github.com/aptly-dev/aptly/files"
|
||||
"github.com/aptly-dev/aptly/utils"
|
||||
)
|
||||
|
||||
type PublishedStorageSuite struct {
|
||||
srv *fakestorage.Server
|
||||
prevEmulatorHost string
|
||||
prevEmulatorHostSet bool
|
||||
storage, prefixedStorage *PublishedStorage
|
||||
noSuchBucketStorage *PublishedStorage
|
||||
}
|
||||
|
||||
var _ = Suite(&PublishedStorageSuite{})
|
||||
|
||||
func (s *PublishedStorageSuite) SetUpTest(c *C) {
|
||||
var err error
|
||||
s.srv, err = fakestorage.NewServerWithOptions(fakestorage.Options{
|
||||
Scheme: "http",
|
||||
Host: "127.0.0.1",
|
||||
})
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(s.srv, NotNil)
|
||||
|
||||
s.srv.CreateBucketWithOpts(fakestorage.CreateBucketOpts{Name: "test"})
|
||||
|
||||
// The cloud.google.com/go/storage client honors STORAGE_EMULATOR_HOST and
|
||||
// will route all requests (including media uploads) to the fake server.
|
||||
s.prevEmulatorHost, s.prevEmulatorHostSet = os.LookupEnv("STORAGE_EMULATOR_HOST")
|
||||
c.Assert(os.Setenv("STORAGE_EMULATOR_HOST", s.srv.URL()), IsNil)
|
||||
|
||||
s.storage, err = NewPublishedStorage("test", "", "", "", "", "", "", "", "", false, false)
|
||||
c.Assert(err, IsNil)
|
||||
s.prefixedStorage, err = NewPublishedStorage("test", "lala", "", "", "", "", "", "", "", false, false)
|
||||
c.Assert(err, IsNil)
|
||||
s.noSuchBucketStorage, err = NewPublishedStorage("no-bucket", "", "", "", "", "", "", "", "", false, false)
|
||||
c.Assert(err, IsNil)
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TearDownTest(c *C) {
|
||||
if s.prevEmulatorHostSet {
|
||||
_ = os.Setenv("STORAGE_EMULATOR_HOST", s.prevEmulatorHost)
|
||||
} else {
|
||||
_ = os.Unsetenv("STORAGE_EMULATOR_HOST")
|
||||
}
|
||||
s.srv.Stop()
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) GetFile(c *C, path string) []byte {
|
||||
r, err := s.storage.bucket.Object(path).NewReader(context.TODO())
|
||||
c.Assert(err, IsNil)
|
||||
defer func() { _ = r.Close() }()
|
||||
|
||||
body, err := io.ReadAll(r)
|
||||
c.Assert(err, IsNil)
|
||||
return body
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) AssertNoFile(c *C, path string) {
|
||||
_, err := s.storage.bucket.Object(path).Attrs(context.TODO())
|
||||
c.Assert(errors.Is(err, storage.ErrObjectNotExist), Equals, true)
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) PutFile(c *C, path string, data []byte) {
|
||||
w := s.storage.bucket.Object(path).NewWriter(context.TODO())
|
||||
_, err := w.Write(data)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(w.Close(), IsNil)
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestString(c *C) {
|
||||
c.Check(s.storage.String(), Equals, "GCS: test/")
|
||||
c.Check(s.prefixedStorage.String(), Equals, "GCS: test/lala")
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestMkDir(c *C) {
|
||||
c.Check(s.storage.MkDir("anything"), IsNil)
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestApplyACLNoOpModes(c *C) {
|
||||
for _, acl := range []string{"", "none", "private"} {
|
||||
st := &PublishedStorage{acl: acl}
|
||||
c.Check(st.applyACL(nil), IsNil)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestApplyACLUnsupported(c *C) {
|
||||
st := &PublishedStorage{acl: "bucket-owner-full-control"}
|
||||
err := st.applyACL(nil)
|
||||
c.Assert(err, NotNil)
|
||||
c.Check(err, ErrorMatches, "unsupported GCS ACL value: bucket-owner-full-control")
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestPutFile(c *C) {
|
||||
dir := c.MkDir()
|
||||
err := os.WriteFile(filepath.Join(dir, "a"), []byte("welcome to gcs!"), 0644)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.storage.PutFile("a/b.txt", filepath.Join(dir, "a"))
|
||||
c.Check(err, IsNil)
|
||||
c.Check(s.GetFile(c, "a/b.txt"), DeepEquals, []byte("welcome to gcs!"))
|
||||
|
||||
err = s.prefixedStorage.PutFile("a/b.txt", filepath.Join(dir, "a"))
|
||||
c.Check(err, IsNil)
|
||||
c.Check(s.GetFile(c, "lala/a/b.txt"), DeepEquals, []byte("welcome to gcs!"))
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestPutFileMissingSource(c *C) {
|
||||
err := s.storage.PutFile("a/b.txt", filepath.Join(c.MkDir(), "does-not-exist"))
|
||||
c.Check(err, ErrorMatches, ".*no such file or directory.*")
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestFilelist(c *C) {
|
||||
paths := []string{"a", "b", "c", "testa", "test/a", "test/b", "lala/a", "lala/b", "lala/c"}
|
||||
for _, path := range paths {
|
||||
s.PutFile(c, path, []byte("test"))
|
||||
}
|
||||
|
||||
list, err := s.storage.Filelist("")
|
||||
c.Check(err, IsNil)
|
||||
sort.Strings(list)
|
||||
c.Check(list, DeepEquals, []string{"a", "b", "c", "lala/a", "lala/b", "lala/c", "test/a", "test/b", "testa"})
|
||||
|
||||
list, err = s.storage.Filelist("test")
|
||||
c.Check(err, IsNil)
|
||||
sort.Strings(list)
|
||||
c.Check(list, DeepEquals, []string{"a", "b"})
|
||||
|
||||
list, err = s.storage.Filelist("test2")
|
||||
c.Check(err, IsNil)
|
||||
c.Check(list, DeepEquals, []string{})
|
||||
|
||||
list, err = s.prefixedStorage.Filelist("")
|
||||
c.Check(err, IsNil)
|
||||
sort.Strings(list)
|
||||
c.Check(list, DeepEquals, []string{"a", "b", "c"})
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestRemove(c *C) {
|
||||
s.PutFile(c, "a/b", []byte("test"))
|
||||
|
||||
err := s.storage.Remove("a/b")
|
||||
c.Check(err, IsNil)
|
||||
|
||||
s.AssertNoFile(c, "a/b")
|
||||
|
||||
s.PutFile(c, "lala/xyz", []byte("test"))
|
||||
|
||||
err = s.prefixedStorage.Remove("xyz")
|
||||
c.Check(err, IsNil)
|
||||
|
||||
s.AssertNoFile(c, "lala/xyz")
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestRemoveMissing(c *C) {
|
||||
c.Check(s.storage.Remove("does/not/exist"), IsNil)
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestRemoveDirs(c *C) {
|
||||
paths := []string{"a", "b", "c", "testa", "test/a", "test/b", "lala/a", "lala/b", "lala/c"}
|
||||
for _, path := range paths {
|
||||
s.PutFile(c, path, []byte("test"))
|
||||
}
|
||||
|
||||
err := s.storage.RemoveDirs("test", nil)
|
||||
c.Check(err, IsNil)
|
||||
|
||||
list, err := s.storage.Filelist("")
|
||||
c.Check(err, IsNil)
|
||||
sort.Strings(list)
|
||||
c.Check(list, DeepEquals, []string{"a", "b", "c", "lala/a", "lala/b", "lala/c", "testa"})
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestRenameFile(c *C) {
|
||||
s.PutFile(c, "src", []byte("payload"))
|
||||
|
||||
err := s.storage.RenameFile("src", "dst")
|
||||
c.Check(err, IsNil)
|
||||
|
||||
c.Check(s.GetFile(c, "dst"), DeepEquals, []byte("payload"))
|
||||
s.AssertNoFile(c, "src")
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestSymLink(c *C) {
|
||||
s.PutFile(c, "a/b", []byte("test"))
|
||||
|
||||
err := s.storage.SymLink("a/b", "a/b.link")
|
||||
c.Check(err, IsNil)
|
||||
|
||||
link, err := s.storage.ReadLink("a/b.link")
|
||||
c.Check(err, IsNil)
|
||||
c.Check(link, Equals, "a/b")
|
||||
|
||||
c.Check(s.GetFile(c, "a/b.link"), DeepEquals, []byte("test"))
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestHardLink(c *C) {
|
||||
s.PutFile(c, "a/b", []byte("test"))
|
||||
|
||||
err := s.storage.HardLink("a/b", "a/b.hard")
|
||||
c.Check(err, IsNil)
|
||||
|
||||
link, err := s.storage.ReadLink("a/b.hard")
|
||||
c.Check(err, IsNil)
|
||||
c.Check(link, Equals, "a/b")
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestFileExists(c *C) {
|
||||
s.PutFile(c, "a/b", []byte("test"))
|
||||
|
||||
exists, err := s.storage.FileExists("a/b")
|
||||
c.Check(err, IsNil)
|
||||
c.Check(exists, Equals, true)
|
||||
|
||||
exists, err = s.storage.FileExists("a/b.invalid")
|
||||
c.Check(err, IsNil)
|
||||
c.Check(exists, Equals, false)
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestObjectPath(c *C) {
|
||||
st := &PublishedStorage{prefix: "root"}
|
||||
c.Check(st.objectPath("dists/stable/Release"), Equals, filepath.Join("root", "dists/stable/Release"))
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestLinkFromPool(c *C) {
|
||||
root := c.MkDir()
|
||||
pool := files.NewPackagePool(root, false)
|
||||
cs := files.NewMockChecksumStorage()
|
||||
|
||||
tmpFile1 := filepath.Join(c.MkDir(), "mars-invaders_1.03.deb")
|
||||
c.Assert(os.WriteFile(tmpFile1, []byte("Contents"), 0644), IsNil)
|
||||
cksum1 := utils.ChecksumInfo{MD5: "c1df1da7a1ce305a3b60af9d5733ac1d"}
|
||||
|
||||
tmpFile2 := filepath.Join(c.MkDir(), "mars-invaders_1.03.deb")
|
||||
c.Assert(os.WriteFile(tmpFile2, []byte("Spam"), 0644), IsNil)
|
||||
cksum2 := utils.ChecksumInfo{MD5: "e9dfd31cc505d51fc26975250750deab"}
|
||||
|
||||
tmpFile3 := filepath.Join(c.MkDir(), "netboot/boot.img.gz")
|
||||
_ = os.MkdirAll(filepath.Dir(tmpFile3), 0777)
|
||||
c.Assert(os.WriteFile(tmpFile3, []byte("Contents"), 0644), IsNil)
|
||||
cksum3 := utils.ChecksumInfo{MD5: "c1df1da7a1ce305a3b60af9d5733ac1d"}
|
||||
|
||||
src1, err := pool.Import(tmpFile1, "mars-invaders_1.03.deb", &cksum1, true, cs)
|
||||
c.Assert(err, IsNil)
|
||||
src2, err := pool.Import(tmpFile2, "mars-invaders_1.03.deb", &cksum2, true, cs)
|
||||
c.Assert(err, IsNil)
|
||||
src3, err := pool.Import(tmpFile3, "netboot/boot.img.gz", &cksum3, true, cs)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
// first link from pool
|
||||
err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents"))
|
||||
|
||||
// duplicate link from pool (same MD5 → no-op)
|
||||
err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents"))
|
||||
|
||||
// link from pool with conflict, no force
|
||||
err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, false)
|
||||
c.Check(err, ErrorMatches, ".*file already exists and is different.*")
|
||||
c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents"))
|
||||
|
||||
// link from pool with conflict and force
|
||||
err = s.storage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src2, cksum2, true)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(s.GetFile(c, "pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Spam"))
|
||||
|
||||
// for prefixed storage:
|
||||
err = s.prefixedStorage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, src1, cksum1, false)
|
||||
c.Check(err, IsNil)
|
||||
|
||||
// 2nd link from pool, providing wrong path for source file:
|
||||
// should hit the path cache and skip upload (which would otherwise fail).
|
||||
err = s.prefixedStorage.LinkFromPool("", filepath.Join("pool", "main", "m/mars-invaders"), "mars-invaders_1.03.deb", pool, "wrong-looks-like-pathcache-doesnt-work", cksum1, false)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(s.GetFile(c, "lala/pool/main/m/mars-invaders/mars-invaders_1.03.deb"), DeepEquals, []byte("Contents"))
|
||||
|
||||
// link from pool with nested file name
|
||||
err = s.storage.LinkFromPool("", "dists/jessie/non-free/installer-i386/current/images", "netboot/boot.img.gz", pool, src3, cksum3, false)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(s.GetFile(c, "dists/jessie/non-free/installer-i386/current/images/netboot/boot.img.gz"), DeepEquals, []byte("Contents"))
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestLinkFromPoolMissingMD5(c *C) {
|
||||
publishedPrefix := "repo"
|
||||
publishedRelPath := "pool/main/a/aptly"
|
||||
fileName := "pkg.deb"
|
||||
relPath := filepath.Join(filepath.Join(publishedPrefix, publishedRelPath), fileName)
|
||||
|
||||
st := &PublishedStorage{pathCache: map[string]string{relPath: "0123456789abcdef0123456789abcdef"}}
|
||||
|
||||
err := st.LinkFromPool(publishedPrefix, publishedRelPath, fileName, nil, "", utils.ChecksumInfo{}, false)
|
||||
c.Assert(err, NotNil)
|
||||
c.Check(err, ErrorMatches, "unable to compare object, MD5 checksum missing")
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestLinkFromPoolDifferentMD5NoForce(c *C) {
|
||||
publishedPrefix := "repo"
|
||||
publishedRelPath := "pool/main/a/aptly"
|
||||
fileName := "pkg.deb"
|
||||
relPath := filepath.Join(filepath.Join(publishedPrefix, publishedRelPath), fileName)
|
||||
|
||||
st := &PublishedStorage{pathCache: map[string]string{relPath: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}}
|
||||
|
||||
err := st.LinkFromPool(publishedPrefix, publishedRelPath, fileName, nil, "", utils.ChecksumInfo{MD5: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}, false)
|
||||
c.Assert(err, NotNil)
|
||||
c.Check(err, ErrorMatches, ".*file already exists and is different.*")
|
||||
}
|
||||
|
||||
func (s *PublishedStorageSuite) TestLinkFromPoolSameMD5NoUpload(c *C) {
|
||||
publishedPrefix := "repo"
|
||||
publishedRelPath := "pool/main/a/aptly"
|
||||
fileName := "pkg.deb"
|
||||
relPath := filepath.Join(filepath.Join(publishedPrefix, publishedRelPath), fileName)
|
||||
|
||||
st := &PublishedStorage{pathCache: map[string]string{relPath: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}}
|
||||
|
||||
err := st.LinkFromPool(publishedPrefix, publishedRelPath, fileName, nil, "", utils.ChecksumInfo{MD5: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}, false)
|
||||
c.Check(err, IsNil)
|
||||
}
|
||||
|
||||
// putWithMetadata uploads an object with arbitrary metadata directly via the
|
||||
// storage client, bypassing the production putFile path. Used to seed objects
|
||||
// that exercise getMD5 / metadata-handling branches.
|
||||
func (s *PublishedStorageSuite) putWithMetadata(c *C, path string, data []byte, metadata map[string]string) {
|
||||
w := s.storage.bucket.Object(path).NewWriter(context.TODO())
|
||||
w.Metadata = metadata
|
||||
_, err := w.Write(data)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(w.Close(), IsNil)
|
||||
}
|
||||
|
||||
// TestLinkFromPoolShortCachedMD5 exercises the LinkFromPool branch where the
|
||||
// path cache holds a non-32-char checksum (so getMD5 must be called to fetch
|
||||
// the real MD5 from object attrs), and along the way covers getMD5 plus the
|
||||
// Md5-metadata branch in internalFilelist.
|
||||
func (s *PublishedStorageSuite) TestLinkFromPoolShortCachedMD5(c *C) {
|
||||
root := c.MkDir()
|
||||
pool := files.NewPackagePool(root, false)
|
||||
cs := files.NewMockChecksumStorage()
|
||||
|
||||
tmpFile := filepath.Join(c.MkDir(), "mars-invaders_1.03.deb")
|
||||
c.Assert(os.WriteFile(tmpFile, []byte("Contents"), 0644), IsNil)
|
||||
cksum := utils.ChecksumInfo{MD5: "c1df1da7a1ce305a3b60af9d5733ac1d"}
|
||||
|
||||
src, err := pool.Import(tmpFile, "mars-invaders_1.03.deb", &cksum, true, cs)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
// Seed the bucket with a short Md5 metadata value so internalFilelist
|
||||
// returns it (covering the metadata branch) and LinkFromPool then has to
|
||||
// re-fetch via getMD5 because len != 32.
|
||||
relPath := filepath.Join("pool/main/m/mars-invaders", "mars-invaders_1.03.deb")
|
||||
s.putWithMetadata(c, relPath, []byte("Contents"), map[string]string{"Md5": "short"})
|
||||
|
||||
// force=true so the conflict (the seeded "short" md5 will never match
|
||||
// sourceMD5 once getMD5 normalises) resolves into a fresh upload rather
|
||||
// than an error — what matters here is that we traverse the getMD5 +
|
||||
// short-cache + internalFilelist md5-metadata branches.
|
||||
err = s.storage.LinkFromPool("", "pool/main/m/mars-invaders", "mars-invaders_1.03.deb", pool, src, cksum, true)
|
||||
c.Check(err, IsNil)
|
||||
}
|
||||
|
||||
// TestLinkFromPoolMissingSource covers the source-pool open error path.
|
||||
func (s *PublishedStorageSuite) TestLinkFromPoolMissingSource(c *C) {
|
||||
pool := files.NewPackagePool(c.MkDir(), false)
|
||||
|
||||
err := s.storage.LinkFromPool("", "pool/x", "y.deb", pool, "non-existent-pool-key", utils.ChecksumInfo{MD5: "33333333333333333333333333333333"}, false)
|
||||
c.Check(err, ErrorMatches, ".*no such file or directory.*")
|
||||
}
|
||||
|
||||
// TestPutFilePublicReadACL covers the applyACL public-read branch and the
|
||||
// ACL().Set call against the fake server.
|
||||
func (s *PublishedStorageSuite) TestPutFilePublicReadACL(c *C) {
|
||||
st, err := NewPublishedStorage("test", "", "", "", "", "", "public-read", "", "", false, false)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
dir := c.MkDir()
|
||||
src := filepath.Join(dir, "f")
|
||||
c.Assert(os.WriteFile(src, []byte("hello"), 0644), IsNil)
|
||||
|
||||
c.Check(st.PutFile("a/b.txt", src), IsNil)
|
||||
c.Check(s.GetFile(c, "a/b.txt"), DeepEquals, []byte("hello"))
|
||||
}
|
||||
|
||||
// TestPutFileUnsupportedACL covers the default (error) branch of applyACL
|
||||
// when invoked from the production putFile flow.
|
||||
func (s *PublishedStorageSuite) TestPutFileUnsupportedACL(c *C) {
|
||||
st, err := NewPublishedStorage("test", "", "", "", "", "", "bucket-owner-full-control", "", "", false, false)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
dir := c.MkDir()
|
||||
src := filepath.Join(dir, "f")
|
||||
c.Assert(os.WriteFile(src, []byte("hello"), 0644), IsNil)
|
||||
|
||||
err = st.PutFile("a/b.txt", src)
|
||||
c.Assert(err, NotNil)
|
||||
c.Check(err, ErrorMatches, ".*unsupported GCS ACL value.*")
|
||||
}
|
||||
|
||||
// TestPutFileWithStorageClass covers the storageClass branch in putFile.
|
||||
func (s *PublishedStorageSuite) TestPutFileWithStorageClass(c *C) {
|
||||
st, err := NewPublishedStorage("test", "", "", "", "", "", "", "NEARLINE", "", false, false)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
dir := c.MkDir()
|
||||
src := filepath.Join(dir, "f")
|
||||
c.Assert(os.WriteFile(src, []byte("hi"), 0644), IsNil)
|
||||
|
||||
c.Check(st.PutFile("a/b.txt", src), IsNil)
|
||||
|
||||
attrs, err := s.storage.bucket.Object("a/b.txt").Attrs(context.TODO())
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(attrs.StorageClass, Equals, "NEARLINE")
|
||||
}
|
||||
|
||||
// TestRemoveDirsNoSuchBucket covers the internalFilelist error path inside
|
||||
// RemoveDirs (and the iterator error branch in internalFilelist itself).
|
||||
func (s *PublishedStorageSuite) TestRemoveDirsNoSuchBucket(c *C) {
|
||||
err := s.noSuchBucketStorage.RemoveDirs("a/b", nil)
|
||||
c.Check(err, ErrorMatches, ".*error listing under prefix.*")
|
||||
}
|
||||
|
||||
// TestFilelistNoSuchBucket also covers the iterator error path.
|
||||
func (s *PublishedStorageSuite) TestFilelistNoSuchBucket(c *C) {
|
||||
_, err := s.noSuchBucketStorage.Filelist("")
|
||||
c.Check(err, ErrorMatches, ".*error listing under prefix.*")
|
||||
}
|
||||
|
||||
// TestRemoveCacheEviction verifies that a successful Remove evicts the entry
|
||||
// from pathCache (covers the delete(g.pathCache, ...) line).
|
||||
func (s *PublishedStorageSuite) TestRemoveCacheEviction(c *C) {
|
||||
s.PutFile(c, "a/b", []byte("test"))
|
||||
|
||||
s.storage.pathCache = map[string]string{"a/b": "deadbeefdeadbeefdeadbeefdeadbeef"}
|
||||
c.Check(s.storage.Remove("a/b"), IsNil)
|
||||
_, present := s.storage.pathCache["a/b"]
|
||||
c.Check(present, Equals, false)
|
||||
}
|
||||
|
||||
// TestDebugMode exercises the if-debug log branches across the main verbs.
|
||||
func (s *PublishedStorageSuite) TestDebugMode(c *C) {
|
||||
st, err := NewPublishedStorage("test", "", "", "", "", "", "", "", "", false, true)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
dir := c.MkDir()
|
||||
src := filepath.Join(dir, "f")
|
||||
c.Assert(os.WriteFile(src, []byte("dbg"), 0644), IsNil)
|
||||
|
||||
c.Check(st.PutFile("d/a", src), IsNil)
|
||||
c.Check(st.RenameFile("d/a", "d/b"), IsNil)
|
||||
c.Check(st.SymLink("d/b", "d/b.link"), IsNil)
|
||||
c.Check(st.HardLink("d/b", "d/b.hard"), IsNil)
|
||||
c.Check(st.Remove("d/b"), IsNil)
|
||||
c.Check(st.RemoveDirs("d", nil), IsNil)
|
||||
|
||||
pool := files.NewPackagePool(c.MkDir(), false)
|
||||
cs := files.NewMockChecksumStorage()
|
||||
tmp := filepath.Join(c.MkDir(), "x.deb")
|
||||
c.Assert(os.WriteFile(tmp, []byte("Contents"), 0644), IsNil)
|
||||
cksum := utils.ChecksumInfo{MD5: "c1df1da7a1ce305a3b60af9d5733ac1d"}
|
||||
srcKey, err := pool.Import(tmp, "x.deb", &cksum, true, cs)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(st.LinkFromPool("", "pool/x", "x.deb", pool, srcKey, cksum, false), IsNil)
|
||||
}
|
||||
|
||||
// TestObjectHandleWithEncryptionKey covers the encryptionKey branch in
|
||||
// objectHandle. fsouza doesn't enforce CSEK headers but we just need to walk
|
||||
// the code path.
|
||||
func (s *PublishedStorageSuite) TestObjectHandleWithEncryptionKey(c *C) {
|
||||
st := &PublishedStorage{
|
||||
bucket: s.storage.bucket,
|
||||
bucketName: "test",
|
||||
encryptionKey: "0123456789abcdef0123456789abcdef",
|
||||
}
|
||||
c.Check(st.objectHandle("a/b"), NotNil)
|
||||
}
|
||||
|
||||
// TestReadLinkMissing covers the Attrs-error return in ReadLink.
|
||||
func (s *PublishedStorageSuite) TestReadLinkMissing(c *C) {
|
||||
_, err := s.storage.ReadLink("does/not/exist")
|
||||
c.Check(err, ErrorMatches, ".*object doesn't exist.*")
|
||||
}
|
||||
|
||||
// TestFileExistsNoSuchBucket exercises FileExists' wrapped-googleapi-404 path.
|
||||
func (s *PublishedStorageSuite) TestFileExistsNoSuchBucket(c *C) {
|
||||
exists, err := s.noSuchBucketStorage.FileExists("a/b")
|
||||
c.Check(err, IsNil)
|
||||
c.Check(exists, Equals, false)
|
||||
}
|
||||
|
||||
// TestNewPublishedStorageWithEndpoint exercises the endpoint-injection branch
|
||||
// in NewPublishedStorage (the production knob, separate from the env-var path).
|
||||
func (s *PublishedStorageSuite) TestNewPublishedStorageWithEndpoint(c *C) {
|
||||
saved := os.Getenv("STORAGE_EMULATOR_HOST")
|
||||
c.Assert(os.Unsetenv("STORAGE_EMULATOR_HOST"), IsNil)
|
||||
defer func() { _ = os.Setenv("STORAGE_EMULATOR_HOST", saved) }()
|
||||
|
||||
st, err := NewPublishedStorage("test", "", "", "", "", s.srv.URL()+"/storage/v1/", "", "", "", false, false)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
_, err = st.Filelist("")
|
||||
c.Check(err, IsNil)
|
||||
}
|
||||
|
||||
// TestNewPublishedStorageWithProject covers the project!="" → WithQuotaProject
|
||||
// branch. WithQuotaProject is incompatible with WithEndpoint, so this test
|
||||
// relies on the STORAGE_EMULATOR_HOST env var (still set from SetUpTest) for
|
||||
// fake-server routing.
|
||||
func (s *PublishedStorageSuite) TestNewPublishedStorageWithProject(c *C) {
|
||||
st, err := NewPublishedStorage("test", "", "", "", "fake-project", "", "", "", "", false, false)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
_, err = st.Filelist("")
|
||||
c.Check(err, IsNil)
|
||||
}
|
||||
@@ -13,7 +13,7 @@ require (
|
||||
github.com/h2non/filetype v1.1.3
|
||||
github.com/jlaffaye/ftp v0.2.0 // indirect
|
||||
github.com/kjk/lzma v0.0.0-20120628231508-2a7c55cad4a2
|
||||
github.com/klauspost/compress v1.17.9
|
||||
github.com/klauspost/compress v1.18.2
|
||||
github.com/klauspost/pgzip v1.2.5
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
@@ -32,17 +32,27 @@ require (
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d
|
||||
github.com/ugorji/go/codec v1.2.11
|
||||
github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/sys v0.39.0
|
||||
golang.org/x/term v0.38.0
|
||||
golang.org/x/time v0.5.0
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
golang.org/x/crypto v0.47.0 // indirect
|
||||
golang.org/x/sys v0.40.0
|
||||
golang.org/x/term v0.39.0
|
||||
golang.org/x/time v0.14.0
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
|
||||
)
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.25.1 // indirect
|
||||
cloud.google.com/go v0.123.0 // indirect
|
||||
cloud.google.com/go/auth v0.18.1 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.3 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.3 // indirect
|
||||
cloud.google.com/go/pubsub/v2 v2.4.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
@@ -64,11 +74,18 @@ require (
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/cloudflare/circl v1.6.3 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
@@ -79,11 +96,17 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/renameio/v2 v2.0.0 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.11 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.17.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.2 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
@@ -93,29 +116,44 @@ require (
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/pkg/xattr v0.4.12 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.59.1 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.15 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.39.0 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/net v0.48.0 // indirect
|
||||
golang.org/x/net v0.49.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/text v0.32.0 // indirect
|
||||
golang.org/x/tools v0.39.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
golang.org/x/tools v0.40.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect
|
||||
google.golang.org/grpc v1.79.3 // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.60.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1
|
||||
github.com/ProtonMail/go-crypto v1.4.0
|
||||
@@ -124,11 +162,13 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.46
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.3
|
||||
github.com/aws/smithy-go v1.24.2
|
||||
github.com/fsouza/fake-gcs-server v1.53.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.0
|
||||
github.com/swaggo/swag v1.16.3
|
||||
go.etcd.io/etcd/client/v3 v3.5.15
|
||||
golang.org/x/oauth2 v0.34.0
|
||||
golang.org/x/oauth2 v0.35.0
|
||||
google.golang.org/api v0.266.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
|
||||
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
|
||||
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
|
||||
cloud.google.com/go/auth v0.18.1 h1:IwTEx92GFUo2pJ6Qea0EU3zYvKnTAeRCODxfA/G5UWs=
|
||||
cloud.google.com/go/auth v0.18.1/go.mod h1:GfTYoS9G3CWpRA3Va9doKN9mjPGRS+v41jmZAhBzbrA=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
|
||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc=
|
||||
cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU=
|
||||
cloud.google.com/go/logging v1.13.1 h1:O7LvmO0kGLaHY/gq8cV7T0dyp6zJhYAOtZPX4TF3QtY=
|
||||
cloud.google.com/go/logging v1.13.1/go.mod h1:XAQkfkMBxQRjQek96WLPNze7vsOmay9H5PqfsNYDqvw=
|
||||
cloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8=
|
||||
cloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk=
|
||||
cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE=
|
||||
cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI=
|
||||
cloud.google.com/go/pubsub/v2 v2.4.0 h1:oMKNiBQpXImRWnHYla9uSU66ZzByZwBSCJOEs/pTKVg=
|
||||
cloud.google.com/go/pubsub/v2 v2.4.0/go.mod h1:2lS/XQKq5qtOMs6kHBK+WX1ytUC36kLl2ig3zqsGUx8=
|
||||
cloud.google.com/go/storage v1.60.0 h1:oBfZrSOCimggVNz9Y/bXY35uUcts7OViubeddTTVzQ8=
|
||||
cloud.google.com/go/storage v1.60.0/go.mod h1:q+5196hXfejkctrnx+VYU8RKQr/L3c0cBIlrjmiAKE0=
|
||||
cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U=
|
||||
cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s=
|
||||
github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI=
|
||||
github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8=
|
||||
@@ -14,8 +37,17 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1 h1:cf+OIKbkmMHBaC3u7
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1/go.mod h1:ap1dmS6vQKJxSMNiGJcq4QuUQkOynyD93gLw6MDF7ek=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55 h1:jbGlDKdzAZ92NzK65hUP98ri0/r50vVVvmZsFP/nIqo=
|
||||
github.com/DisposaBoy/JsonConfigReader v0.0.0-20171218180944-5ea4d0ddac55/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/ProtonMail/go-crypto v1.4.0 h1:Zq/pbM3F5DFgJiMouxEdSVY44MVoQNEKp5d5QxIQceQ=
|
||||
@@ -69,6 +101,7 @@ github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4=
|
||||
github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheggaaa/pb v1.0.25 h1:tFpebHTkI7QZx1q1rWGOKhbunhZ3fMaxTvHDWn1bH/4=
|
||||
@@ -79,22 +112,45 @@ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583j
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w=
|
||||
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fsouza/fake-gcs-server v1.53.1 h1:/gjEYut23/MMhe4daYJ5yIBGPUmLAYupgITuoWG3+jI=
|
||||
github.com/fsouza/fake-gcs-server v1.53.1/go.mod h1:kF+DadfinC7mlc1/2d/ZDHS9VyUk1hTcXJ6VwLSlzfM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||
@@ -103,6 +159,11 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
@@ -133,29 +194,55 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
|
||||
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
|
||||
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.11 h1:vAe81Msw+8tKUxi2Dqh/NZMz7475yUvmRIkXr4oN2ao=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.11/go.mod h1:RFV7MUdlb7AgEq2v7FmMCfeSMCllAzWxFgRdusoGks8=
|
||||
github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc=
|
||||
github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY=
|
||||
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
|
||||
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@@ -175,11 +262,13 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kjk/lzma v0.0.0-20120628231508-2a7c55cad4a2 h1:TVZQgMi+I83S3rCuE65HnmDO6+wFPRi3n2LOzr+tr68=
|
||||
github.com/kjk/lzma v0.0.0-20120628231508-2a7c55cad4a2/go.mod h1:phT/jsRPBAEqjAibu1BurrabCBNTYiVI+zbmyCZJY6Q=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
|
||||
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM=
|
||||
github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw=
|
||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@@ -209,6 +298,12 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI=
|
||||
github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.98 h1:MeAVKjLVz+XJ28zFcuYyImNSAh8Mq725uNW4beRisi0=
|
||||
github.com/minio/minio-go/v7 v7.0.98/go.mod h1:cY0Y+W7yozf0mdIclrttzo1Iiu7mEf9y7nk2uXqMOvM=
|
||||
github.com/mkrautz/goar v0.0.0-20150919110319-282caa8bd9da h1:Iu5QFXIMK/YrHJ0NgUnK0rqYTTyb0ldt/rqNenAj39U=
|
||||
github.com/mkrautz/goar v0.0.0-20150919110319-282caa8bd9da/go.mod h1:NfnmoBY0gGkr3/NmI+DP/UXbZvOCurCUYAzOdYJjlOc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -239,17 +334,25 @@ github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
||||
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pkg/xattr v0.4.12 h1:rRTkSyFNTRElv6pkA3zpjHpQ90p/OdHQC1GmGh1aTjM=
|
||||
github.com/pkg/xattr v0.4.12/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
|
||||
github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0=
|
||||
github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
@@ -258,9 +361,11 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
|
||||
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
|
||||
github.com/saracen/walker v0.1.2 h1:/o1TxP82n8thLvmL4GpJXduYaRmJ7qXp8u9dSlV0zmo=
|
||||
@@ -273,6 +378,8 @@ github.com/smira/go-ftp-protocol v0.0.0-20140829150050-066b75c2b70d h1:rvtR4+9N2
|
||||
github.com/smira/go-ftp-protocol v0.0.0-20140829150050-066b75c2b70d/go.mod h1:Jm7yHrROA5tC42gyJ5EwiR8EWp0PUy0qOc4sE7Y8Uzo=
|
||||
github.com/smira/go-xz v0.1.0 h1:1zVLT1sITUKcWNysfHMLZWJ2Yh7yJfhREsgmUdK4zb0=
|
||||
github.com/smira/go-xz v0.1.0/go.mod h1:OmdEWnIIkuLzRLHGF4YtjDzF9VFUevEcP6YxDPRqVrs=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
@@ -286,8 +393,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
|
||||
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
||||
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
|
||||
@@ -296,6 +403,8 @@ github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
||||
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
|
||||
github.com/tinylib/msgp v1.6.1 h1:ESRv8eL3u+DNHUoSAAQRE50Hm162zqAnBoGv9PzScPY=
|
||||
github.com/tinylib/msgp v1.6.1/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
@@ -305,16 +414,28 @@ github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdms
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.einride.tech/aip v0.79.0 h1:19zdPlZzlUvxOA8syAFw4LkdJdXepzyTl6gt9XEeqdU=
|
||||
go.einride.tech/aip v0.79.0/go.mod h1:E8+wdTApA70odnpFzJgsGogHozC2JCIhFJBKPr8bVig=
|
||||
go.etcd.io/etcd/api/v3 v3.5.15 h1:3KpLJir1ZEBrYuV2v+Twaa/e2MdDCEZ/70H+lzEiwsk=
|
||||
go.etcd.io/etcd/api/v3 v3.5.15/go.mod h1:N9EhGzXq58WuMllgH9ZvnEr7SI9pS0k0+DHZezGp7jM=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.15 h1:fo0HpWz/KlHGMCC+YejpiCmyWDEuIpnTDzpJLB5fWlA=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.15/go.mod h1:mXDI4NAOwEiszrHCb0aqfAYNCrZP4e9hRca3d1YK8EU=
|
||||
go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4=
|
||||
go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 h1:5gn2urDL/FBnK8OkCfD1j3/ER79rUuTYmCvlXBKeYL8=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0/go.mod h1:0fBG6ZJxhqByfFZDwSwpZGzJU671HkwpWaNe2t4VUPI=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
@@ -323,12 +444,14 @@ go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2W
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
@@ -336,19 +459,28 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
|
||||
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
@@ -356,11 +488,13 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
|
||||
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -368,6 +502,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -385,37 +520,41 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
||||
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
|
||||
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
|
||||
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -423,10 +562,24 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/api v0.266.0 h1:hco+oNCf9y7DmLeAtHJi/uBAY7n/7XC9mZPxu1ROiyk=
|
||||
google.golang.org/api v0.266.0/go.mod h1:Jzc0+ZfLnyvXma3UtaTl023TdhZu6OMBP9tJ+0EmFD0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM=
|
||||
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20 h1:7ei4lp52gK1uSejlA8AZl5AJjeLUOHBQscRQZUgAcu0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260203192932-546029d2fa20/go.mod h1:ZdbssH/1SOVnjnDlXzxDHK2MCidiqXtbYccJNzNYPEE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 h1:Jr5R2J6F6qWyzINc+4AM8t5pfUz6beZpHp678GNrMbE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
@@ -434,11 +587,14 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -458,4 +614,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
+60
@@ -307,6 +307,66 @@ The legacy json configuration is still supported (and also supports comments):
|
||||
// }
|
||||
},
|
||||
|
||||
// GCS Endpoint Support
|
||||
//
|
||||
// aptly can be configured to publish repositories directly to Google Cloud
|
||||
// Storage\. First, publishing endpoints should be described in the aptly
|
||||
// configuration file\. Each endpoint has a name and associated settings\.
|
||||
//
|
||||
// In order to publish to GCS, specify endpoint as `gcs:endpoint\-name:` before
|
||||
// publishing prefix on the command line, e\.g\.:
|
||||
//
|
||||
// `aptly publish snapshot wheezy\-main gcs:test:`
|
||||
//
|
||||
"GcsPublishEndpoints": {
|
||||
// // Endpoint Name
|
||||
// "test": {
|
||||
|
||||
// // Bucket name
|
||||
// "bucket": "test\-bucket",
|
||||
|
||||
// // Prefix (optional)
|
||||
// // publishing under specified prefix in the bucket, defaults to
|
||||
// // no prefix (bucket root)
|
||||
// "prefix": "",
|
||||
|
||||
// // Credentials file (optional)
|
||||
// // Path to a service account credentials JSON file\. If omitted,
|
||||
// // Application Default Credentials are used\.
|
||||
// "credentialsFile": "",
|
||||
|
||||
// // Service Account JSON (optional)
|
||||
// // Inline service account credentials JSON content\.
|
||||
// "serviceAccountJSON": "",
|
||||
|
||||
// // Project (optional)
|
||||
// // Quota project to bill requests to\.
|
||||
// "project": "",
|
||||
|
||||
// // Default ACLs (optional)
|
||||
// // assign ACL to published files\. Useful values: `private` (default),
|
||||
// // `public\-read` (public repository), or `none` (don't set ACL)\.
|
||||
// "acl": "private",
|
||||
|
||||
// // Storage Class (optional)
|
||||
// // GCS storage class, e\.g\. `STANDARD`\.
|
||||
// "storageClass": "STANDARD",
|
||||
|
||||
// // Encryption Key (optional)
|
||||
// // Customer-supplied encryption key (32-byte AES-256 key) for object operations\.
|
||||
// "encryptionKey": "",
|
||||
|
||||
// // Disable MultiDel (optional)
|
||||
// // Kept for parity with S3 settings\.
|
||||
// // GCS deletes are currently performed one object at a time\.
|
||||
// "disableMultiDel": false,
|
||||
|
||||
// // Debug (optional)
|
||||
// // Enables detailed GCS operation logs
|
||||
// "debug": false
|
||||
// }
|
||||
},
|
||||
|
||||
// Swift Endpoint Support
|
||||
//
|
||||
// aptly could be configured to publish repository directly to OpenStack Swift\. First,
|
||||
|
||||
@@ -296,6 +296,66 @@ The legacy json configuration is still supported (and also supports comments):
|
||||
// }
|
||||
},
|
||||
|
||||
// GCS Endpoint Support
|
||||
//
|
||||
// aptly can be configured to publish repositories directly to Google Cloud
|
||||
// Storage. First, publishing endpoints should be described in the aptly
|
||||
// configuration file. Each endpoint has a name and associated settings.
|
||||
//
|
||||
// In order to publish to GCS, specify endpoint as `gcs:endpoint-name:` before
|
||||
// publishing prefix on the command line, e.g.:
|
||||
//
|
||||
// `aptly publish snapshot wheezy-main gcs:test:`
|
||||
//
|
||||
"GcsPublishEndpoints": {
|
||||
// // Endpoint Name
|
||||
// "test": {
|
||||
|
||||
// // Bucket name
|
||||
// "bucket": "test-bucket",
|
||||
|
||||
// // Prefix (optional)
|
||||
// // publishing under specified prefix in the bucket, defaults to
|
||||
// // no prefix (bucket root)
|
||||
// "prefix": "",
|
||||
|
||||
// // Credentials file (optional)
|
||||
// // Path to a service account credentials JSON file. If omitted,
|
||||
// // Application Default Credentials are used.
|
||||
// "credentialsFile": "",
|
||||
|
||||
// // Service Account JSON (optional)
|
||||
// // Inline service account credentials JSON content.
|
||||
// "serviceAccountJSON": "",
|
||||
|
||||
// // Project (optional)
|
||||
// // Quota project to bill requests to.
|
||||
// "project": "",
|
||||
|
||||
// // Default ACLs (optional)
|
||||
// // assign ACL to published files. Useful values: `private` (default),
|
||||
// // `public-read` (public repository), or `none` (don't set ACL).
|
||||
// "acl": "private",
|
||||
|
||||
// // Storage Class (optional)
|
||||
// // GCS storage class, e.g. `STANDARD`.
|
||||
// "storageClass": "STANDARD",
|
||||
|
||||
// // Encryption Key (optional)
|
||||
// // Customer-supplied encryption key (32-byte AES-256 key) for object operations.
|
||||
// "encryptionKey": "",
|
||||
|
||||
// // Disable MultiDel (optional)
|
||||
// // Kept for parity with S3 settings.
|
||||
// // GCS deletes are currently performed one object at a time.
|
||||
// "disableMultiDel": false,
|
||||
|
||||
// // Debug (optional)
|
||||
// // Enables detailed GCS operation logs
|
||||
// "debug": false
|
||||
// }
|
||||
},
|
||||
|
||||
// Swift Endpoint Support
|
||||
//
|
||||
// aptly could be configured to publish repository directly to OpenStack Swift. First,
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
from lib import BaseTest
|
||||
import os
|
||||
import uuid
|
||||
|
||||
try:
|
||||
from google.cloud import storage
|
||||
|
||||
gcs_project = os.environ.get('GCS_PROJECT')
|
||||
|
||||
if gcs_project:
|
||||
gcs_client = storage.Client(project=gcs_project)
|
||||
else:
|
||||
print('GCS tests disabled: GCS_PROJECT is not set')
|
||||
gcs_client = None
|
||||
except ImportError as e:
|
||||
print("GCS tests disabled: can't import google.cloud.storage", e)
|
||||
gcs_client = None
|
||||
except Exception as e:
|
||||
print('GCS tests disabled: unable to initialize GCS client', e)
|
||||
gcs_client = None
|
||||
|
||||
|
||||
class GCSTest(BaseTest):
|
||||
"""
|
||||
BaseTest + support for GCS
|
||||
"""
|
||||
|
||||
gcsOverrides = {}
|
||||
|
||||
def __init__(self) -> None:
|
||||
super(GCSTest, self).__init__()
|
||||
self.bucket_name = None
|
||||
self.bucket = None
|
||||
self.bucket_contents = None
|
||||
|
||||
def fixture_available(self):
|
||||
return super(GCSTest, self).fixture_available() and gcs_client is not None
|
||||
|
||||
def prepare(self):
|
||||
# GCS bucket names must be globally unique and lower-case.
|
||||
self.bucket_name = 'aptly-sys-test-' + str(uuid.uuid4()).replace('_', '-').lower()
|
||||
self.bucket = gcs_client.create_bucket(self.bucket_name)
|
||||
|
||||
self.configOverride = {
|
||||
'GcsPublishEndpoints': {
|
||||
'test1': {
|
||||
'bucket': self.bucket_name,
|
||||
'project': gcs_project,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
self.configOverride['GcsPublishEndpoints']['test1'].update(**self.gcsOverrides)
|
||||
|
||||
super(GCSTest, self).prepare()
|
||||
|
||||
def shutdown(self):
|
||||
if self.bucket is not None:
|
||||
for blob in self.bucket.list_blobs():
|
||||
blob.delete()
|
||||
self.bucket.delete(force=True)
|
||||
|
||||
super(GCSTest, self).shutdown()
|
||||
|
||||
def _normalize_path(self, path):
|
||||
if path.startswith('public/'):
|
||||
return path[7:]
|
||||
return path
|
||||
|
||||
def check_path(self, path):
|
||||
if self.bucket_contents is None:
|
||||
self.bucket_contents = [blob.name for blob in self.bucket.list_blobs()]
|
||||
|
||||
path = self._normalize_path(path)
|
||||
|
||||
if path in self.bucket_contents:
|
||||
return True
|
||||
|
||||
if not path.endswith('/'):
|
||||
path = path + '/'
|
||||
|
||||
for item in self.bucket_contents:
|
||||
if item.startswith(path):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def check_exists(self, path):
|
||||
if not self.check_path(path):
|
||||
raise Exception("path %s doesn't exist" % (path, ))
|
||||
|
||||
def check_not_exists(self, path):
|
||||
if self.check_path(path):
|
||||
raise Exception("path %s exists" % (path, ))
|
||||
|
||||
def read_file(self, path, mode=''):
|
||||
assert not mode
|
||||
|
||||
path = self._normalize_path(path)
|
||||
blob = self.bucket.blob(path)
|
||||
return blob.download_as_text()
|
||||
@@ -1,4 +1,5 @@
|
||||
azure-storage-blob
|
||||
google-cloud-storage
|
||||
boto
|
||||
requests==2.33.0
|
||||
requests-unixsocket
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
"skipBz2Publishing": false,
|
||||
"FileSystemPublishEndpoints": {},
|
||||
"S3PublishEndpoints": {},
|
||||
"GcsPublishEndpoints": {},
|
||||
"SwiftPublishEndpoints": {},
|
||||
"AzurePublishEndpoints": {},
|
||||
"packagePoolStorage": {}
|
||||
|
||||
@@ -33,6 +33,7 @@ skip_contents_publishing: false
|
||||
skip_bz2_publishing: false
|
||||
filesystem_publish_endpoints: {}
|
||||
s3_publish_endpoints: {}
|
||||
gcs_publish_endpoints: {}
|
||||
swift_publish_endpoints: {}
|
||||
azure_publish_endpoints: {}
|
||||
packagepool_storage: {}
|
||||
|
||||
@@ -256,6 +256,58 @@ s3_publish_endpoints:
|
||||
# # Enables detailed request/response dump for each S3 operation
|
||||
# debug: false
|
||||
|
||||
# GCS Endpoint Support
|
||||
#
|
||||
# aptly can be configured to publish repositories directly to Google Cloud
|
||||
# Storage. First, publishing endpoints should be described in the aptly
|
||||
# configuration file. Each endpoint has a name and associated settings.
|
||||
#
|
||||
# In order to publish to GCS, specify endpoint as `gcs:endpoint-name:` before
|
||||
# publishing prefix on the command line, e.g.:
|
||||
#
|
||||
# `aptly publish snapshot wheezy-main gcs:test:`
|
||||
#
|
||||
gcs_publish_endpoints:
|
||||
# # Endpoint Name
|
||||
# test:
|
||||
# # Bucket name
|
||||
# bucket: test-bucket
|
||||
# # Prefix (optional)
|
||||
# # publishing under specified prefix in the bucket, defaults to
|
||||
# # no prefix (bucket root)
|
||||
# prefix: ""
|
||||
# # Credentials File (optional)
|
||||
# # Path to a service account credentials JSON file
|
||||
# credentials_file: ""
|
||||
# # Service Account JSON (optional)
|
||||
# # Inline service account credentials JSON payload
|
||||
# service_account_json: ""
|
||||
# # Project (optional)
|
||||
# # Quota project used for GCS requests
|
||||
# project: ""
|
||||
# # Endpoint (optional)
|
||||
# # Override the GCS endpoint (e.g. for staging or a fake server);
|
||||
# # leave empty to use the default GCS endpoint
|
||||
# endpoint: ""
|
||||
# # Default ACLs (optional)
|
||||
# # assign ACL to published files:
|
||||
# # * private (default)
|
||||
# # * public-read (public repository)
|
||||
# # * none (don't set ACL)
|
||||
# acl: private
|
||||
# # Storage Class (optional)
|
||||
# # GCS storage class, e.g. `STANDARD`
|
||||
# storage_class: STANDARD
|
||||
# # Encryption Key (optional)
|
||||
# # Customer-supplied encryption key (32-byte AES-256 key)
|
||||
# encryption_key: ""
|
||||
# # Disable MultiDel (optional)
|
||||
# # Kept for parity with S3 settings; GCS deletes are one-by-one
|
||||
# disable_multidel: false
|
||||
# # Debug (optional)
|
||||
# # Enables detailed logs for each GCS operation
|
||||
# debug: false
|
||||
|
||||
# Swift Endpoint Support
|
||||
#
|
||||
# aptly can publish a repository directly to OpenStack Swift.
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
from gcs_lib import GCSTest
|
||||
|
||||
|
||||
def strip_processor(output):
|
||||
return '\n'.join(
|
||||
[
|
||||
l
|
||||
for l in output.split('\n')
|
||||
if not l.startswith(' ') and not l.startswith('Date:')
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class GCSPublish1Test(GCSTest):
|
||||
"""
|
||||
publish to GCS: from repo
|
||||
"""
|
||||
|
||||
fixtureCmds = [
|
||||
'aptly repo create -distribution=maverick local-repo',
|
||||
'aptly repo add local-repo ${files}',
|
||||
'aptly repo remove local-repo libboost-program-options-dev_1.62.0.1_i386',
|
||||
]
|
||||
runCmd = 'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec local-repo gcs:test1:'
|
||||
|
||||
def check(self):
|
||||
self.check_exists('public/dists/maverick/InRelease')
|
||||
self.check_exists('public/dists/maverick/Release')
|
||||
self.check_exists('public/dists/maverick/Release.gpg')
|
||||
|
||||
self.check_exists('public/dists/maverick/main/binary-i386/Packages')
|
||||
self.check_exists('public/dists/maverick/main/binary-i386/Packages.gz')
|
||||
self.check_exists('public/dists/maverick/main/binary-i386/Packages.bz2')
|
||||
self.check_exists('public/dists/maverick/main/source/Sources')
|
||||
self.check_exists('public/dists/maverick/main/source/Sources.gz')
|
||||
self.check_exists('public/dists/maverick/main/source/Sources.bz2')
|
||||
|
||||
self.check_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.dsc')
|
||||
self.check_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.diff.gz')
|
||||
self.check_exists('public/pool/main/p/pyspi/pyspi_0.6.1.orig.tar.gz')
|
||||
self.check_exists('public/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc')
|
||||
self.check_exists(
|
||||
'public/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb'
|
||||
)
|
||||
|
||||
# verify contents except sums/date chunks
|
||||
self.check_file_contents(
|
||||
'public/dists/maverick/Release', 'release', match_prepare=strip_processor
|
||||
)
|
||||
self.check_file_contents(
|
||||
'public/dists/maverick/main/source/Sources',
|
||||
'sources',
|
||||
match_prepare=lambda s: '\n'.join(sorted(s.split('\n'))),
|
||||
)
|
||||
self.check_file_contents(
|
||||
'public/dists/maverick/main/binary-i386/Packages',
|
||||
'binary',
|
||||
match_prepare=lambda s: '\n'.join(sorted(s.split('\n'))),
|
||||
)
|
||||
|
||||
|
||||
class GCSPublish2Test(GCSTest):
|
||||
"""
|
||||
publish to GCS: update after removing package from repo
|
||||
"""
|
||||
|
||||
fixtureCmds = [
|
||||
'aptly repo create -distribution=maverick local-repo',
|
||||
'aptly repo add local-repo ${files}/',
|
||||
'aptly repo remove local-repo libboost-program-options-dev_1.62.0.1_i386',
|
||||
'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec local-repo gcs:test1:',
|
||||
'aptly repo remove local-repo pyspi',
|
||||
]
|
||||
runCmd = 'aptly publish update -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec maverick gcs:test1:'
|
||||
|
||||
def check(self):
|
||||
self.check_exists('public/dists/maverick/InRelease')
|
||||
self.check_exists('public/dists/maverick/Release')
|
||||
self.check_exists('public/dists/maverick/Release.gpg')
|
||||
|
||||
self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.dsc')
|
||||
self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.diff.gz')
|
||||
self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1.orig.tar.gz')
|
||||
self.check_not_exists('public/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc')
|
||||
self.check_exists(
|
||||
'public/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb'
|
||||
)
|
||||
|
||||
|
||||
class GCSPublish3Test(GCSTest):
|
||||
"""
|
||||
publish to GCS: publish drop performs cleanup
|
||||
"""
|
||||
|
||||
fixtureCmds = [
|
||||
'aptly repo create local1',
|
||||
'aptly repo create local2',
|
||||
'aptly repo add local1 ${files}/libboost-program-options-dev_1.49.0.1_i386.deb',
|
||||
'aptly repo add local2 ${files}',
|
||||
'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=sq1 local1 gcs:test1:',
|
||||
'aptly publish repo -keyring=${files}/aptly.pub -secret-keyring=${files}/aptly.sec -distribution=sq2 local2 gcs:test1:',
|
||||
]
|
||||
runCmd = 'aptly publish drop sq2 gcs:test1:'
|
||||
|
||||
def check(self):
|
||||
self.check_exists('public/dists/sq1')
|
||||
self.check_not_exists('public/dists/sq2')
|
||||
self.check_exists('public/pool/main/')
|
||||
|
||||
self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.dsc')
|
||||
self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1-1.3.diff.gz')
|
||||
self.check_not_exists('public/pool/main/p/pyspi/pyspi_0.6.1.orig.tar.gz')
|
||||
self.check_not_exists('public/pool/main/p/pyspi/pyspi-0.6.1-1.3.stripped.dsc')
|
||||
self.check_exists(
|
||||
'public/pool/main/b/boost-defaults/libboost-program-options-dev_1.49.0.1_i386.deb'
|
||||
)
|
||||
@@ -62,6 +62,7 @@ type ConfigStructure struct { // nolint: maligned
|
||||
// Storage
|
||||
FileSystemPublishRoots map[string]FileSystemPublishRoot `json:"FileSystemPublishEndpoints" yaml:"filesystem_publish_endpoints"`
|
||||
S3PublishRoots map[string]S3PublishRoot `json:"S3PublishEndpoints" yaml:"s3_publish_endpoints"`
|
||||
GCSPublishRoots map[string]GCSPublishRoot `json:"GcsPublishEndpoints" yaml:"gcs_publish_endpoints"`
|
||||
SwiftPublishRoots map[string]SwiftPublishRoot `json:"SwiftPublishEndpoints" yaml:"swift_publish_endpoints"`
|
||||
AzurePublishRoots map[string]AzureEndpoint `json:"AzurePublishEndpoints" yaml:"azure_publish_endpoints"`
|
||||
PackagePoolStorage PackagePoolStorage `json:"packagePoolStorage" yaml:"packagepool_storage"`
|
||||
@@ -189,6 +190,21 @@ type S3PublishRoot struct {
|
||||
Debug bool `json:"debug" yaml:"debug"`
|
||||
}
|
||||
|
||||
// GCSPublishRoot describes single GCS publishing entry point
|
||||
type GCSPublishRoot struct {
|
||||
Bucket string `json:"bucket" yaml:"bucket"`
|
||||
Prefix string `json:"prefix" yaml:"prefix"`
|
||||
CredentialsFile string `json:"credentialsFile" yaml:"credentials_file"`
|
||||
ServiceAccountJSON string `json:"serviceAccountJSON" yaml:"service_account_json"`
|
||||
Project string `json:"project" yaml:"project"`
|
||||
Endpoint string `json:"endpoint" yaml:"endpoint"`
|
||||
ACL string `json:"acl" yaml:"acl"`
|
||||
StorageClass string `json:"storageClass" yaml:"storage_class"`
|
||||
EncryptionKey string `json:"encryptionKey" yaml:"encryption_key"`
|
||||
DisableMultiDel bool `json:"disableMultiDel" yaml:"disable_multidel"`
|
||||
Debug bool `json:"debug" yaml:"debug"`
|
||||
}
|
||||
|
||||
// SwiftPublishRoot describes single OpenStack Swift publishing entry point
|
||||
type SwiftPublishRoot struct {
|
||||
Container string `json:"container" yaml:"container"`
|
||||
@@ -239,6 +255,7 @@ var Config = ConfigStructure{
|
||||
PpaBaseURL: "http://ppa.launchpad.net",
|
||||
FileSystemPublishRoots: map[string]FileSystemPublishRoot{},
|
||||
S3PublishRoots: map[string]S3PublishRoot{},
|
||||
GCSPublishRoots: map[string]GCSPublishRoot{},
|
||||
SwiftPublishRoots: map[string]SwiftPublishRoot{},
|
||||
AzurePublishRoots: map[string]AzureEndpoint{},
|
||||
AsyncAPI: false,
|
||||
|
||||
@@ -49,6 +49,9 @@ func (s *ConfigSuite) TestSaveConfig(c *C) {
|
||||
Region: "us-east-1",
|
||||
Bucket: "repo"}}
|
||||
|
||||
s.config.GCSPublishRoots = map[string]GCSPublishRoot{"test": {
|
||||
Bucket: "repo"}}
|
||||
|
||||
s.config.SwiftPublishRoots = map[string]SwiftPublishRoot{"test": {
|
||||
Container: "repo"}}
|
||||
|
||||
@@ -132,6 +135,21 @@ func (s *ConfigSuite) TestSaveConfig(c *C) {
|
||||
" \"debug\": false\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"GcsPublishEndpoints\": {\n" +
|
||||
" \"test\": {\n" +
|
||||
" \"bucket\": \"repo\",\n" +
|
||||
" \"prefix\": \"\",\n" +
|
||||
" \"credentialsFile\": \"\",\n" +
|
||||
" \"serviceAccountJSON\": \"\",\n" +
|
||||
" \"project\": \"\",\n" +
|
||||
" \"endpoint\": \"\",\n" +
|
||||
" \"acl\": \"\",\n" +
|
||||
" \"storageClass\": \"\",\n" +
|
||||
" \"encryptionKey\": \"\",\n" +
|
||||
" \"disableMultiDel\": false,\n" +
|
||||
" \"debug\": false\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"SwiftPublishEndpoints\": {\n" +
|
||||
" \"test\": {\n" +
|
||||
" \"container\": \"repo\",\n" +
|
||||
@@ -275,6 +293,7 @@ func (s *ConfigSuite) TestSaveYAML2Config(c *C) {
|
||||
"skip_bz2_publishing: false\n" +
|
||||
"filesystem_publish_endpoints: {}\n" +
|
||||
"s3_publish_endpoints: {}\n" +
|
||||
"gcs_publish_endpoints: {}\n" +
|
||||
"swift_publish_endpoints: {}\n" +
|
||||
"azure_publish_endpoints: {}\n" +
|
||||
"packagepool_storage:\n" +
|
||||
@@ -352,6 +371,19 @@ s3_publish_endpoints:
|
||||
force_sigv2: true
|
||||
force_virtualhosted_style: true
|
||||
debug: true
|
||||
gcs_publish_endpoints:
|
||||
test:
|
||||
bucket: gcs-bucket
|
||||
prefix: pre-gcs
|
||||
credentials_file: /tmp/creds.json
|
||||
service_account_json: '{"type":"service_account"}'
|
||||
project: test-project
|
||||
endpoint: ""
|
||||
acl: public-read
|
||||
storage_class: STANDARD
|
||||
encryption_key: "12345678901234567890123456789012"
|
||||
disable_multidel: true
|
||||
debug: true
|
||||
swift_publish_endpoints:
|
||||
test:
|
||||
container: c1
|
||||
|
||||
Reference in New Issue
Block a user