Add artifact to Git and Helm repos status

- create index.yaml symlink for Helm repos
- set symlink URL in status
This commit is contained in:
stefanprodan 2020-04-12 13:17:12 +03:00
parent 461c015273
commit 2bbcd91544
4 changed files with 149 additions and 104 deletions

View File

@ -42,3 +42,61 @@ func NotReadyCondition(reason, message string) sourcev1.SourceCondition {
Message: message,
}
}
func ReadyGitRepository(repository sourcev1.GitRepository, artifact sourcev1.Artifact, url, reason, message string) sourcev1.GitRepository {
repository.Status.Conditions = []sourcev1.SourceCondition{ReadyCondition(reason, message)}
repository.Status.URL = url
if repository.Status.Artifact != nil {
if repository.Status.Artifact.Path != artifact.Path {
repository.Status.Artifact = &artifact
}
} else {
repository.Status.Artifact = &artifact
}
return repository
}
func NotReadyGitRepository(repository sourcev1.GitRepository, reason, message string) sourcev1.GitRepository {
repository.Status.Conditions = []sourcev1.SourceCondition{NotReadyCondition(reason, message)}
return repository
}
func GitRepositoryReadyMessage(repository sourcev1.GitRepository) string {
for _, condition := range repository.Status.Conditions {
if condition.Type == sourcev1.ReadyCondition {
return condition.Message
}
}
return ""
}
func ReadyHelmRepository(repository sourcev1.HelmRepository, artifact sourcev1.Artifact, url, reason, message string) sourcev1.HelmRepository {
repository.Status.Conditions = []sourcev1.SourceCondition{ReadyCondition(reason, message)}
repository.Status.URL = url
if repository.Status.Artifact != nil {
if repository.Status.Artifact.Path != artifact.Path {
repository.Status.Artifact = &artifact
}
} else {
repository.Status.Artifact = &artifact
}
return repository
}
func NotReadyHelmRepository(repository sourcev1.HelmRepository, reason, message string) sourcev1.HelmRepository {
repository.Status.Conditions = []sourcev1.SourceCondition{NotReadyCondition(reason, message)}
return repository
}
func HelmRepositoryReadyMessage(repository sourcev1.HelmRepository) string {
for _, condition := range repository.Status.Conditions {
if condition.Type == sourcev1.ReadyCondition {
return condition.Message
}
}
return ""
}

View File

@ -83,28 +83,19 @@ func (r *GitRepositoryReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
r.gc(repo)
// try git clone
readyCondition, artifacts, err := r.sync(repo)
syncedRepo, err := r.sync(*repo.DeepCopy())
if err != nil {
log.Info("Repository sync failed", "error", err.Error())
} else {
// update artifacts if commit hash changed
if repo.Status.Artifact != artifacts {
timeNew := metav1.Now()
repo.Status.LastUpdateTime = &timeNew
repo.Status.Artifact = artifacts
}
log.Info("Repository sync succeeded", "msg", readyCondition.Message)
}
// update status
readyCondition.LastTransitionTime = metav1.Now()
repo.Status.Conditions = []sourcev1.SourceCondition{readyCondition}
if err := r.Status().Update(ctx, &repo); err != nil {
if err := r.Status().Update(ctx, &syncedRepo); err != nil {
log.Error(err, "unable to update GitRepository status")
return result, err
}
log.Info("Repository sync succeeded", "msg", GitRepositoryReadyMessage(syncedRepo))
// requeue repository
return result, nil
}
@ -116,7 +107,7 @@ func (r *GitRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error {
WithEventFilter(predicate.Funcs{
DeleteFunc: func(e event.DeleteEvent) bool {
// delete artifacts
artifact := r.Storage.ArtifactFor(r.Kind, e.Meta, "dummy")
artifact := r.Storage.ArtifactFor(r.Kind, e.Meta, "dummy", "")
if err := r.Storage.RemoveAll(artifact); err != nil {
r.Log.Error(err, "unable to delete artifacts",
r.Kind, fmt.Sprintf("%s/%s", e.Meta.GetNamespace(), e.Meta.GetName()))
@ -130,9 +121,10 @@ func (r *GitRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error {
Complete(r)
}
func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourcev1.SourceCondition, string, error) {
func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourcev1.GitRepository, error) {
// set defaults: master branch, no tags fetching, max two commits
branch := "master"
revision := ""
tagMode := git.NoTags
depth := 2
@ -159,21 +151,21 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
tmpSSH, err := ioutil.TempDir("", repository.Name)
if err != nil {
err = fmt.Errorf("tmp dir error: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
defer os.RemoveAll(tmpSSH)
auth, err := r.auth(repository, tmpSSH)
if err != nil {
err = fmt.Errorf("auth error: %w", err)
return NotReadyCondition(sourcev1.AuthenticationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
// create tmp dir for the Git clone
tmpGit, err := ioutil.TempDir("", repository.Name)
if err != nil {
err = fmt.Errorf("tmp dir error: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
defer os.RemoveAll(tmpGit)
@ -192,7 +184,7 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
})
if err != nil {
err = fmt.Errorf("git clone error: %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.GitOperationFailedReason, err.Error()), err
}
// checkout commit or tag
@ -201,7 +193,7 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
w, err := repo.Worktree()
if err != nil {
err = fmt.Errorf("git worktree error: %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.GitOperationFailedReason, err.Error()), err
}
err = w.Checkout(&git.CheckoutOptions{
@ -210,19 +202,19 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
})
if err != nil {
err = fmt.Errorf("git checkout %s for %s error: %w", commit, branch, err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.GitOperationFailedReason, err.Error()), err
}
} else if exp := repository.Spec.Reference.SemVer; exp != "" {
rng, err := semver.ParseRange(exp)
if err != nil {
err = fmt.Errorf("semver parse range error: %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.GitOperationFailedReason, err.Error()), err
}
repoTags, err := repo.Tags()
if err != nil {
err = fmt.Errorf("git list tags error: %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.GitOperationFailedReason, err.Error()), err
}
tags := make(map[string]string)
@ -246,11 +238,12 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
v := svers[len(svers)-1]
t := svTags[v.String()]
commit := tags[t]
revision = fmt.Sprintf("%s/%s", t, commit)
w, err := repo.Worktree()
if err != nil {
err = fmt.Errorf("git worktree error: %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.GitOperationFailedReason, err.Error()), err
}
err = w.Checkout(&git.CheckoutOptions{
@ -258,11 +251,11 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
})
if err != nil {
err = fmt.Errorf("git checkout error: %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.GitOperationFailedReason, err.Error()), err
}
} else {
err = fmt.Errorf("no match found for semver: %s", repository.Spec.Reference.SemVer)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.GitOperationFailedReason, err.Error()), err
}
}
}
@ -271,24 +264,28 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
ref, err := repo.Head()
if err != nil {
err = fmt.Errorf("git resolve HEAD error: %w", err)
return NotReadyCondition(sourcev1.GitOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.GitOperationFailedReason, err.Error()), err
}
if revision == "" {
revision = fmt.Sprintf("%s/%s", branch, ref.Hash().String())
}
artifact := r.Storage.ArtifactFor(r.Kind, repository.ObjectMeta.GetObjectMeta(),
fmt.Sprintf("%s.tar.gz", ref.Hash().String()))
fmt.Sprintf("%s.tar.gz", ref.Hash().String()), revision)
// create artifact dir
err = r.Storage.MkdirAll(artifact)
if err != nil {
err = fmt.Errorf("mkdir dir error: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
// acquire lock
unlock, err := r.Storage.Lock(artifact)
if err != nil {
err = fmt.Errorf("unable to acquire lock: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
defer unlock()
@ -296,26 +293,24 @@ func (r *GitRepositoryReconciler) sync(repository sourcev1.GitRepository) (sourc
err = r.Storage.Archive(artifact, tmpGit, "")
if err != nil {
err = fmt.Errorf("storage archive error: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
// update latest symlink
err = r.Storage.Symlink(artifact, "latest.tar.gz")
url, err := r.Storage.Symlink(artifact, "latest.tar.gz")
if err != nil {
err = fmt.Errorf("storage lock error: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
return NotReadyGitRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
message := fmt.Sprintf("Artifact is available at: %s", artifact.Path)
return ReadyCondition(sourcev1.GitOperationSucceedReason, message), artifact.URL, nil
return ReadyGitRepository(repository, artifact, url, sourcev1.GitOperationSucceedReason, message), nil
}
func (r *GitRepositoryReconciler) shouldResetStatus(repository sourcev1.GitRepository) (bool, sourcev1.GitRepositoryStatus) {
resetStatus := false
if repository.Status.Artifact != "" {
parts := strings.Split(repository.Status.Artifact, "/")
artifact := r.Storage.ArtifactFor(r.Kind, repository.ObjectMeta.GetObjectMeta(), parts[len(parts)-1])
if !r.Storage.ArtifactExist(artifact) {
if repository.Status.Artifact != nil {
if !r.Storage.ArtifactExist(*repository.Status.Artifact) {
resetStatus = true
}
}
@ -338,10 +333,8 @@ func (r *GitRepositoryReconciler) shouldResetStatus(repository sourcev1.GitRepos
}
func (r *GitRepositoryReconciler) gc(repository sourcev1.GitRepository) {
if repository.Status.Artifact != "" {
parts := strings.Split(repository.Status.Artifact, "/")
artifact := r.Storage.ArtifactFor(r.Kind, repository.ObjectMeta.GetObjectMeta(), parts[len(parts)-1])
if err := r.Storage.RemoveAllButCurrent(artifact); err != nil {
if repository.Status.Artifact != nil {
if err := r.Storage.RemoveAllButCurrent(*repository.Status.Artifact); err != nil {
r.Log.Info("Artifacts GC failed", "error", err)
}
}
@ -370,9 +363,13 @@ func (r *GitRepositoryReconciler) auth(repository sourcev1.GitRepository, tmp st
auth := &http.BasicAuth{}
if username, ok := credentials["username"]; ok {
auth.Username = string(username)
} else {
return nil, fmt.Errorf("%s secret does not contain username", repository.Spec.SecretRef.Name)
}
if password, ok := credentials["password"]; ok {
auth.Password = string(password)
} else {
return nil, fmt.Errorf("%s secret does not contain password", repository.Spec.SecretRef.Name)
}
if auth.Username == "" || auth.Password == "" {

View File

@ -22,7 +22,6 @@ import (
"io/ioutil"
"net/url"
"path"
"strings"
"time"
"github.com/go-logr/logr"
@ -57,7 +56,7 @@ func (r *HelmRepositoryReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
log := r.Log.WithValues("helmrepository", req.NamespacedName)
log := r.Log.WithValues(r.Kind, req.NamespacedName)
var repository sourcev1.HelmRepository
if err := r.Get(ctx, req.NamespacedName, &repository); err != nil {
@ -80,28 +79,19 @@ func (r *HelmRepositoryReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
r.gc(repository)
// try to download index
readyCondition, artifact, err := r.index(repository)
syncedRepo, err := r.sync(*repository.DeepCopy())
if err != nil {
log.Info("Helm repository index failed", "error", err.Error())
} else {
// update artifact if path changed
if repository.Status.Artifact != artifact {
timeNew := metav1.Now()
repository.Status.LastUpdateTime = &timeNew
repository.Status.Artifact = artifact
}
log.Info("Helm repository index succeeded", "msg", readyCondition.Message)
}
// update status
readyCondition.LastTransitionTime = metav1.Now()
repository.Status.Conditions = []sourcev1.SourceCondition{readyCondition}
if err := r.Status().Update(ctx, &repository); err != nil {
if err := r.Status().Update(ctx, &syncedRepo); err != nil {
log.Error(err, "unable to update HelmRepository status")
return result, err
}
log.Info("Repository sync succeeded", "msg", HelmRepositoryReadyMessage(syncedRepo))
// requeue repository
return result, nil
}
@ -113,7 +103,7 @@ func (r *HelmRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error {
WithEventFilter(predicate.Funcs{
DeleteFunc: func(e event.DeleteEvent) bool {
// delete artifacts
artifact := r.Storage.ArtifactFor(r.Kind, e.Meta, "dummy")
artifact := r.Storage.ArtifactFor(r.Kind, e.Meta, "", "")
if err := r.Storage.RemoveAll(artifact); err != nil {
r.Log.Error(err, "unable to delete artifacts",
r.Kind, fmt.Sprintf("%s/%s", e.Meta.GetNamespace(), e.Meta.GetName()))
@ -127,15 +117,15 @@ func (r *HelmRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error {
Complete(r)
}
func (r *HelmRepositoryReconciler) index(repository sourcev1.HelmRepository) (sourcev1.SourceCondition, string, error) {
func (r *HelmRepositoryReconciler) sync(repository sourcev1.HelmRepository) (sourcev1.HelmRepository, error) {
u, err := url.Parse(repository.Spec.URL)
if err != nil {
return NotReadyCondition(sourcev1.URLInvalidReason, err.Error()), "", err
return NotReadyHelmRepository(repository, sourcev1.URLInvalidReason, err.Error()), err
}
c, err := r.Getters.ByScheme(u.Scheme)
if err != nil {
return NotReadyCondition(sourcev1.URLInvalidReason, err.Error()), "", err
return NotReadyHelmRepository(repository, sourcev1.URLInvalidReason, err.Error()), err
}
u.RawPath = path.Join(u.RawPath, "index.yaml")
@ -145,40 +135,40 @@ func (r *HelmRepositoryReconciler) index(repository sourcev1.HelmRepository) (so
// TODO(hidde): add authentication config
res, err := c.Get(indexURL, getter.WithURL(repository.Spec.URL))
if err != nil {
return NotReadyCondition(sourcev1.IndexationFailedReason, err.Error()), "", err
return NotReadyHelmRepository(repository, sourcev1.IndexationFailedReason, err.Error()), err
}
data, err := ioutil.ReadAll(res)
if err != nil {
return NotReadyCondition(sourcev1.IndexationFailedReason, err.Error()), "", err
return NotReadyHelmRepository(repository, sourcev1.IndexationFailedReason, err.Error()), err
}
i := &repo.IndexFile{}
if err := yaml.Unmarshal(data, i); err != nil {
return NotReadyCondition(sourcev1.IndexationFailedReason, err.Error()), "", err
return NotReadyHelmRepository(repository, sourcev1.IndexationFailedReason, err.Error()), err
}
index, err := yaml.Marshal(i)
if err != nil {
return NotReadyCondition(sourcev1.IndexationFailedReason, err.Error()), "", err
return NotReadyHelmRepository(repository, sourcev1.IndexationFailedReason, err.Error()), err
}
sum := r.Storage.Checksum(index)
artifact := r.Storage.ArtifactFor(r.Kind, repository.ObjectMeta.GetObjectMeta(),
fmt.Sprintf("index-%s.yaml", sum))
fmt.Sprintf("index-%s.yaml", sum), sum)
// create artifact dir
err = r.Storage.MkdirAll(artifact)
if err != nil {
err = fmt.Errorf("unable to create repository index directory: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
return NotReadyHelmRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
// acquire lock
unlock, err := r.Storage.Lock(artifact)
if err != nil {
err = fmt.Errorf("unable to acquire lock: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
return NotReadyHelmRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
defer unlock()
@ -186,19 +176,24 @@ func (r *HelmRepositoryReconciler) index(repository sourcev1.HelmRepository) (so
err = r.Storage.WriteFile(artifact, index)
if err != nil {
err = fmt.Errorf("unable to write repository index file: %w", err)
return NotReadyCondition(sourcev1.StorageOperationFailedReason, err.Error()), "", err
return NotReadyHelmRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
message := fmt.Sprintf("Artifact is available at %s", artifact.Path)
return ReadyCondition(sourcev1.IndexationSucceededReason, message), artifact.URL, nil
// update index symlink
indexUrl, err := r.Storage.Symlink(artifact, "index.yaml")
if err != nil {
err = fmt.Errorf("storage error %w", err)
return NotReadyHelmRepository(repository, sourcev1.StorageOperationFailedReason, err.Error()), err
}
message := fmt.Sprintf("Index is available at %s", artifact.Path)
return ReadyHelmRepository(repository, artifact, indexUrl, sourcev1.IndexationSucceededReason, message), nil
}
func (r *HelmRepositoryReconciler) shouldResetStatus(repository sourcev1.HelmRepository) (bool, sourcev1.HelmRepositoryStatus) {
resetStatus := false
if repository.Status.Artifact != "" {
parts := strings.Split(repository.Status.Artifact, "/")
artifact := r.Storage.ArtifactFor(r.Kind, repository.ObjectMeta.GetObjectMeta(), parts[len(parts)-1])
if !r.Storage.ArtifactExist(artifact) {
if repository.Status.Artifact != nil {
if !r.Storage.ArtifactExist(*repository.Status.Artifact) {
resetStatus = true
}
}
@ -221,10 +216,8 @@ func (r *HelmRepositoryReconciler) shouldResetStatus(repository sourcev1.HelmRep
}
func (r *HelmRepositoryReconciler) gc(repository sourcev1.HelmRepository) {
if repository.Status.Artifact != "" {
parts := strings.Split(repository.Status.Artifact, "/")
artifact := r.Storage.ArtifactFor(r.Kind, repository.ObjectMeta.GetObjectMeta(), parts[len(parts)-1])
if err := r.Storage.RemoveAllButCurrent(artifact); err != nil {
if repository.Status.Artifact != nil {
if err := r.Storage.RemoveAllButCurrent(*repository.Status.Artifact); err != nil {
r.Log.Info("Artifacts GC failed", "error", err)
}
}

View File

@ -29,6 +29,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
sourcev1 "github.com/fluxcd/source-controller/api/v1alpha1"
"github.com/fluxcd/source-controller/internal/lockedfile"
)
@ -44,15 +45,6 @@ type Storage struct {
Timeout time.Duration `json:"timeout"`
}
// Artifact represents the output of a source synchronisation
type Artifact struct {
// Path is the local file path of this artifact
Path string `json:"path"`
// URL is the HTTP address of this artifact
URL string `json:"url"`
}
// NewStorage creates the storage helper for a given path and hostname
func NewStorage(basePath string, hostname string, timeout time.Duration) (*Storage, error) {
if f, err := os.Stat(basePath); os.IsNotExist(err) || !f.IsDir() {
@ -67,31 +59,33 @@ func NewStorage(basePath string, hostname string, timeout time.Duration) (*Stora
}
// ArtifactFor returns an artifact for the given Kubernetes object
func (s *Storage) ArtifactFor(kind string, metadata metav1.Object, fileName string) Artifact {
func (s *Storage) ArtifactFor(kind string, metadata metav1.Object, fileName, revision string) sourcev1.Artifact {
path := fmt.Sprintf("%s/%s-%s/%s", kind, metadata.GetName(), metadata.GetNamespace(), fileName)
localPath := filepath.Join(s.BasePath, path)
url := fmt.Sprintf("http://%s/%s", s.Hostname, path)
return Artifact{
return sourcev1.Artifact{
Path: localPath,
URL: url,
Revision: revision,
LastUpdateTime: metav1.Now(),
}
}
// MkdirAll calls os.MkdirAll for the given artifact base dir
func (s *Storage) MkdirAll(artifact Artifact) error {
func (s *Storage) MkdirAll(artifact sourcev1.Artifact) error {
dir := filepath.Dir(artifact.Path)
return os.MkdirAll(dir, 0777)
}
// RemoveAll calls os.RemoveAll for the given artifact base dir
func (s *Storage) RemoveAll(artifact Artifact) error {
func (s *Storage) RemoveAll(artifact sourcev1.Artifact) error {
dir := filepath.Dir(artifact.Path)
return os.RemoveAll(dir)
}
// RemoveAllButCurrent removes all files for the given artifact base dir excluding the current one
func (s *Storage) RemoveAllButCurrent(artifact Artifact) error {
func (s *Storage) RemoveAllButCurrent(artifact sourcev1.Artifact) error {
dir := filepath.Dir(artifact.Path)
errors := []string{}
_ = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
@ -110,7 +104,7 @@ func (s *Storage) RemoveAllButCurrent(artifact Artifact) error {
}
// ArtifactExist returns a boolean indicating whether the artifact file exists in storage
func (s *Storage) ArtifactExist(artifact Artifact) bool {
func (s *Storage) ArtifactExist(artifact sourcev1.Artifact) bool {
if _, err := os.Stat(artifact.Path); os.IsNotExist(err) {
return false
}
@ -118,7 +112,7 @@ func (s *Storage) ArtifactExist(artifact Artifact) bool {
}
// Archive creates a tar.gz to the artifact path from the given dir excluding the provided file extensions
func (s *Storage) Archive(artifact Artifact, dir string, excludes string) error {
func (s *Storage) Archive(artifact sourcev1.Artifact, dir string, excludes string) error {
if excludes == "" {
excludes = "jpg,jpeg,gif,png,wmv,flv,tar.gz,zip"
}
@ -138,7 +132,7 @@ func (s *Storage) Archive(artifact Artifact, dir string, excludes string) error
}
// WriteFile writes the given bytes to the artifact path if the checksum differs
func (s *Storage) WriteFile(artifact Artifact, data []byte) error {
func (s *Storage) WriteFile(artifact sourcev1.Artifact, data []byte) error {
sum := s.Checksum(data)
if file, err := os.Stat(artifact.Path); !os.IsNotExist(err) && !file.IsDir() {
if fb, err := ioutil.ReadFile(artifact.Path); err == nil && sum == s.Checksum(fb) {
@ -150,24 +144,27 @@ func (s *Storage) WriteFile(artifact Artifact, data []byte) error {
}
// Symlink creates or updates a symbolic link for the given artifact
func (s *Storage) Symlink(artifact Artifact, linkName string) error {
// and returns the URL for the symlink
func (s *Storage) Symlink(artifact sourcev1.Artifact, linkName string) (string, error) {
dir := filepath.Dir(artifact.Path)
link := filepath.Join(dir, linkName)
tmpLink := link + ".tmp"
if err := os.Remove(tmpLink); err != nil && !os.IsNotExist(err) {
return err
return "", err
}
if err := os.Symlink(artifact.Path, tmpLink); err != nil {
return err
return "", err
}
if err := os.Rename(tmpLink, link); err != nil {
return err
return "", err
}
return nil
parts := strings.Split(artifact.URL, "/")
url := strings.Replace(artifact.URL, parts[len(parts)-1], linkName, 1)
return url, nil
}
// Checksum returns the SHA1 checksum for the given bytes as a string
@ -176,7 +173,7 @@ func (s *Storage) Checksum(b []byte) string {
}
// Lock creates a file lock for the given artifact
func (s *Storage) Lock(artifact Artifact) (unlock func(), err error) {
func (s *Storage) Lock(artifact sourcev1.Artifact) (unlock func(), err error) {
lockFile := artifact.Path + ".lock"
mutex := lockedfile.MutexAt(lockFile)
return mutex.Lock()