mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-07-15 11:57:59 +00:00
293 lines
7.8 KiB
Go
293 lines
7.8 KiB
Go
package jfrog
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/aptly-dev/aptly/aptly"
|
|
aptly_utils "github.com/aptly-dev/aptly/utils"
|
|
"github.com/jfrog/jfrog-client-go/artifactory"
|
|
"github.com/jfrog/jfrog-client-go/artifactory/auth"
|
|
"github.com/jfrog/jfrog-client-go/artifactory/services"
|
|
"github.com/jfrog/jfrog-client-go/artifactory/services/utils"
|
|
"github.com/jfrog/jfrog-client-go/config"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// PublishedStorage represents published repository on JFrog Artifactory
|
|
type PublishedStorage struct {
|
|
manager artifactory.ArtifactoryServicesManager
|
|
repository string
|
|
prefix string
|
|
plusWorkaround bool
|
|
}
|
|
|
|
// Check interface
|
|
var (
|
|
_ aptly.PublishedStorage = (*PublishedStorage)(nil)
|
|
)
|
|
|
|
func createPublishedStorageConfig(url, user, password, apiKey, accessToken string) (config.Config, error) {
|
|
artDetails := auth.NewArtifactoryDetails()
|
|
artDetails.SetUrl(url)
|
|
|
|
if user == "" {
|
|
user = os.Getenv("JFROG_USERNAME");
|
|
}
|
|
if password == "" {
|
|
password = os.Getenv("JFROG_PASSWORD");
|
|
}
|
|
if apiKey == "" {
|
|
apiKey = os.Getenv("JFROG_APIKEY");
|
|
}
|
|
if accessToken == "" {
|
|
accessToken = os.Getenv("JFROG_ACCESSTOKEN");
|
|
}
|
|
|
|
if user != "" && password != "" {
|
|
artDetails.SetUser(user)
|
|
artDetails.SetPassword(password)
|
|
} else if apiKey != "" {
|
|
artDetails.SetApiKey(apiKey)
|
|
} else if accessToken != "" {
|
|
artDetails.SetAccessToken(accessToken)
|
|
}
|
|
|
|
return config.NewConfigBuilder().
|
|
SetServiceDetails(artDetails).
|
|
SetDryRun(false).
|
|
Build()
|
|
}
|
|
|
|
// NewPublishedStorageRaw creates jfrog PublishedStorage from raw connection specs
|
|
func NewPublishedStorageRaw(
|
|
repository, url, user, password, apiKey, accessToken, prefix string,
|
|
plusWorkaround, debug bool,
|
|
) (*PublishedStorage, error) {
|
|
|
|
serviceConfig, err := createPublishedStorageConfig(url, user, password, apiKey, accessToken)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "error building jfrog client config")
|
|
}
|
|
|
|
manager, err := artifactory.New(serviceConfig)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "error creating jfrog manager")
|
|
}
|
|
|
|
return &PublishedStorage{
|
|
manager: manager,
|
|
repository: repository,
|
|
prefix: prefix,
|
|
plusWorkaround: plusWorkaround,
|
|
}, nil
|
|
}
|
|
|
|
// NewPublishedStorage creates published storage from aptly configuration struct
|
|
func NewPublishedStorage(
|
|
account string, root aptly_utils.JFrogPublishRoot,
|
|
) (*PublishedStorage, error) {
|
|
return NewPublishedStorageRaw(
|
|
root.Repository, root.URL, root.User, root.Password, root.APIKey, root.AccessToken,
|
|
root.Prefix, root.PlusWorkaround, root.Debug)
|
|
}
|
|
|
|
func (storage *PublishedStorage) String() string {
|
|
return fmt.Sprintf("jfrog:%s:%s", storage.repository, storage.prefix)
|
|
}
|
|
|
|
func (storage *PublishedStorage) MkDir(path string) error {
|
|
return nil
|
|
}
|
|
|
|
func (storage *PublishedStorage) PutFile(path string, sourceFilename string) error {
|
|
targetPath := filepath.Join(storage.repository, storage.prefix, path)
|
|
if storage.plusWorkaround {
|
|
targetPath = strings.Replace(targetPath, "+", "%2B", -1)
|
|
}
|
|
|
|
params := services.NewUploadParams()
|
|
params.Pattern = sourceFilename
|
|
params.Target = targetPath
|
|
params.Flat = true
|
|
|
|
_, _, err := storage.manager.UploadFiles(artifactory.UploadServiceOptions{}, params)
|
|
return err
|
|
}
|
|
|
|
func (storage *PublishedStorage) Remove(path string) error {
|
|
targetPath := filepath.Join(storage.repository, storage.prefix, path)
|
|
if storage.plusWorkaround {
|
|
targetPath = strings.Replace(targetPath, "+", "%2B", -1)
|
|
}
|
|
|
|
deleteParams := services.NewDeleteParams()
|
|
deleteParams.SetPattern(targetPath)
|
|
|
|
res, err := storage.manager.GetPathsToDelete(deleteParams)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() { _ = res.Close() }()
|
|
_, err = storage.manager.DeleteFiles(res)
|
|
return err
|
|
}
|
|
|
|
func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress) error {
|
|
return storage.Remove(path)
|
|
}
|
|
|
|
func (storage *PublishedStorage) LinkFromPool(publishedPrefix, publishedRelPath, fileName string, sourcePool aptly.PackagePool, sourcePath string, sourceMD5 aptly_utils.ChecksumInfo, force bool) error {
|
|
sourceFilename := sourcePath
|
|
cleanup := func() {}
|
|
|
|
if sourcePool != nil {
|
|
if localPool, ok := sourcePool.(aptly.LocalPackagePool); ok {
|
|
sourceFilename = localPool.FullPath(sourcePath)
|
|
} else {
|
|
src, err := sourcePool.Open(sourcePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() { _ = src.Close() }()
|
|
|
|
tmpFile, err := os.CreateTemp("", "aptly-jfrog-pool-*")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := io.Copy(tmpFile, src); err != nil {
|
|
_ = tmpFile.Close()
|
|
_ = os.Remove(tmpFile.Name())
|
|
return err
|
|
}
|
|
|
|
if err := tmpFile.Close(); err != nil {
|
|
_ = os.Remove(tmpFile.Name())
|
|
return err
|
|
}
|
|
|
|
sourceFilename = tmpFile.Name()
|
|
cleanup = func() {
|
|
_ = os.Remove(sourceFilename)
|
|
}
|
|
}
|
|
}
|
|
|
|
defer cleanup()
|
|
|
|
return storage.PutFile(filepath.Join(publishedPrefix, publishedRelPath, fileName), sourceFilename)
|
|
}
|
|
|
|
func (storage *PublishedStorage) Filelist(prefix string) ([]string, error) {
|
|
searchPattern := filepath.Join(storage.repository, storage.prefix, prefix, "*")
|
|
params := services.NewSearchParams()
|
|
params.Pattern = searchPattern
|
|
|
|
reader, err := storage.manager.SearchFiles(params)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() { _ = reader.Close() }()
|
|
|
|
var paths []string
|
|
|
|
for element := new(utils.ResultItem); reader.NextRecord(element) == nil; element = new(utils.ResultItem) {
|
|
path := element.Path + "/" + element.Name
|
|
relPath := strings.TrimPrefix(path, storage.repository+"/"+storage.prefix+"/")
|
|
if storage.plusWorkaround {
|
|
relPath = strings.Replace(relPath, "%2B", "+", -1)
|
|
}
|
|
paths = append(paths, relPath)
|
|
}
|
|
|
|
return paths, nil
|
|
}
|
|
|
|
func (storage *PublishedStorage) RenameFile(oldName, newName string) error {
|
|
oldTarget := filepath.Join(storage.repository, storage.prefix, oldName)
|
|
newTarget := filepath.Join(storage.repository, storage.prefix, newName)
|
|
|
|
if storage.plusWorkaround {
|
|
oldTarget = strings.Replace(oldTarget, "+", "%2B", -1)
|
|
newTarget = strings.Replace(newTarget, "+", "%2B", -1)
|
|
}
|
|
|
|
params := services.NewMoveCopyParams()
|
|
params.Pattern = oldTarget
|
|
params.Target = newTarget
|
|
params.Flat = true
|
|
|
|
_, _, err := storage.manager.Move(params)
|
|
return err
|
|
}
|
|
|
|
func (storage *PublishedStorage) SymLink(src string, dst string) error {
|
|
oldTarget := filepath.Join(storage.repository, storage.prefix, src)
|
|
newTarget := filepath.Join(storage.repository, storage.prefix, dst)
|
|
|
|
if storage.plusWorkaround {
|
|
oldTarget = strings.Replace(oldTarget, "+", "%2B", -1)
|
|
newTarget = strings.Replace(newTarget, "+", "%2B", -1)
|
|
}
|
|
|
|
params := services.NewMoveCopyParams()
|
|
params.Pattern = oldTarget
|
|
params.Target = newTarget
|
|
params.Flat = true
|
|
|
|
props := utils.NewProperties()
|
|
props.AddProperty("SymLink", src)
|
|
params.SetTargetProps(props)
|
|
|
|
_, _, err := storage.manager.Copy(params)
|
|
return err
|
|
}
|
|
|
|
func (storage *PublishedStorage) HardLink(src string, dst string) error {
|
|
return storage.SymLink(src, dst)
|
|
}
|
|
|
|
func (storage *PublishedStorage) FileExists(path string) (bool, error) {
|
|
targetPath := filepath.Join(storage.repository, storage.prefix, path)
|
|
if storage.plusWorkaround {
|
|
targetPath = strings.Replace(targetPath, "+", "%2B", -1)
|
|
}
|
|
|
|
params := services.NewSearchParams()
|
|
params.Pattern = targetPath
|
|
|
|
reader, err := storage.manager.SearchFiles(params)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
defer func() { _ = reader.Close() }()
|
|
|
|
length, err := reader.Length()
|
|
isEmpty := length == 0
|
|
return !isEmpty, err
|
|
}
|
|
|
|
func (storage *PublishedStorage) ReadLink(path string) (string, error) {
|
|
targetPath := filepath.Join(storage.repository, storage.prefix, path)
|
|
if storage.plusWorkaround {
|
|
targetPath = strings.Replace(targetPath, "+", "%2B", -1)
|
|
}
|
|
|
|
props, err := storage.manager.GetItemProps(targetPath)
|
|
if err != nil {
|
|
return "", nil
|
|
}
|
|
|
|
for k, v := range props.Properties {
|
|
if k == "SymLink" && len(v) > 0 {
|
|
return v[0], nil
|
|
}
|
|
}
|
|
|
|
return "", nil
|
|
}
|