Published persistence: save persisted when publishing.

This commit is contained in:
Andrey Smirnov
2014-01-16 23:04:22 +04:00
parent a8e6251a80
commit 33a8dcdacd
3 changed files with 311 additions and 4 deletions
+157 -1
View File
@@ -2,8 +2,13 @@ package debian
import (
"bufio"
"bytes"
"code.google.com/p/go-uuid/uuid"
"fmt"
"github.com/smira/aptly/database"
"github.com/smira/aptly/utils"
"github.com/ugorji/go/codec"
"log"
"path/filepath"
"strings"
"time"
@@ -11,6 +16,8 @@ import (
// PublishedRepo is a published for http/ftp representation of snapshot as Debian repository
type PublishedRepo struct {
// Internal unique ID
UUID string
// Prefix & distribution should be unique across all published repositories
Prefix string
Distribution string
@@ -26,6 +33,7 @@ type PublishedRepo struct {
// NewPublishedRepo creates new published repository
func NewPublishedRepo(prefix string, distribution string, component string, architectures []string, snapshot *Snapshot) *PublishedRepo {
return &PublishedRepo{
UUID: uuid.New(),
Prefix: prefix,
Distribution: distribution,
Component: component,
@@ -35,6 +43,44 @@ func NewPublishedRepo(prefix string, distribution string, component string, arch
}
}
// String returns human-readable represenation of PublishedRepo
func (p *PublishedRepo) String() string {
var prefix, archs string
if p.Prefix != "" {
prefix = p.Prefix
} else {
prefix = "."
}
if len(p.Architectures) > 0 {
archs = fmt.Sprintf(" [%s]", strings.Join(p.Architectures, ", "))
}
return fmt.Sprintf("%s/%s (%s)%s publishes %s", prefix, p.Distribution, p.Component, archs, p.snapshot.String())
}
// Key returns unique key identifying PublishedRepo
func (p *PublishedRepo) Key() []byte {
return []byte("U" + p.Prefix + ">>" + p.Distribution)
}
// Encode does msgpack encoding of PublishedRepo
func (p *PublishedRepo) Encode() []byte {
var buf bytes.Buffer
encoder := codec.NewEncoder(&buf, &codec.MsgpackHandle{})
encoder.Encode(p)
return buf.Bytes()
}
// Decode decodes msgpack representation into PublishedRepo
func (p *PublishedRepo) Decode(input []byte) error {
decoder := codec.NewDecoderBytes(input, &codec.MsgpackHandle{})
return decoder.Decode(p)
}
// Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them
func (p *PublishedRepo) Publish(repo *Repository, packageCollection *PackageCollection, signer utils.Signer) error {
err := repo.MkDir(filepath.Join(p.Prefix, "pool"))
@@ -57,7 +103,7 @@ func (p *PublishedRepo) Publish(repo *Repository, packageCollection *PackageColl
return fmt.Errorf("repository is empty, can't publish")
}
if p.Architectures == nil {
if len(p.Architectures) == 0 {
p.Architectures = list.Architectures()
}
@@ -189,3 +235,113 @@ func (p *PublishedRepo) Publish(repo *Repository, packageCollection *PackageColl
return nil
}
// PublishedRepoCollection does listing, updating/adding/deleting of PublishedRepos
type PublishedRepoCollection struct {
db database.Storage
list []*PublishedRepo
}
// NewPublishedRepoCollection loads PublishedRepos from DB and makes up collection
func NewPublishedRepoCollection(db database.Storage) *PublishedRepoCollection {
result := &PublishedRepoCollection{
db: db,
}
blobs := db.FetchByPrefix([]byte("U"))
result.list = make([]*PublishedRepo, 0, len(blobs))
for _, blob := range blobs {
r := &PublishedRepo{}
if err := r.Decode(blob); err != nil {
log.Printf("Error decoding published repo: %s\n", err)
} else {
result.list = append(result.list, r)
}
}
return result
}
// Add appends new repo to collection and saves it
func (collection *PublishedRepoCollection) Add(repo *PublishedRepo) error {
if collection.CheckDuplicate(repo) != nil {
return fmt.Errorf("published repo with prefix/distribution %s/%s already exists", repo.Prefix, repo.Distribution)
}
err := collection.Update(repo)
if err != nil {
return err
}
collection.list = append(collection.list, repo)
return nil
}
// CheckDuplicate verifies that there's no published repo with the same name
func (collection *PublishedRepoCollection) CheckDuplicate(repo *PublishedRepo) *PublishedRepo {
for _, r := range collection.list {
if r.Prefix == repo.Prefix && r.Distribution == repo.Distribution {
return r
}
}
return nil
}
// Update stores updated information about repo in DB
func (collection *PublishedRepoCollection) Update(repo *PublishedRepo) error {
err := collection.db.Put(repo.Key(), repo.Encode())
if err != nil {
return err
}
return nil
}
// LoadComplete loads additional information for remote repo
func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, snapshotCollection *SnapshotCollection) error {
snapshot, err := snapshotCollection.ByUUID(repo.SnapshotUUID)
if err != nil {
return err
}
repo.snapshot = snapshot
return nil
}
// ByPrefixDistribution looks up repository by prefix & distribution
func (collection *PublishedRepoCollection) ByPrefixDistribution(prefix, distribution string) (*PublishedRepo, error) {
for _, r := range collection.list {
if r.Prefix == prefix && r.Distribution == distribution {
return r, nil
}
}
return nil, fmt.Errorf("published repo with prefix/distribution %s/%s not found", prefix, distribution)
}
// ByUUID looks up repository by uuid
func (collection *PublishedRepoCollection) ByUUID(uuid string) (*PublishedRepo, error) {
for _, r := range collection.list {
if r.UUID == uuid {
return r, nil
}
}
return nil, fmt.Errorf("published repo with uuid %s not found", uuid)
}
// ForEach runs method for each repository
func (collection *PublishedRepoCollection) ForEach(handler func(*PublishedRepo) error) error {
var err error
for _, r := range collection.list {
err = handler(r)
if err != nil {
return err
}
}
return err
}
// Len returns number of remote repos
func (collection *PublishedRepoCollection) Len() int {
return len(collection.list)
}