mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-01-12 03:21:33 +00:00
Published persistence: save persisted when publishing.
This commit is contained in:
@@ -21,10 +21,15 @@ func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
|
||||
var prefix string
|
||||
if len(args) == 2 {
|
||||
prefix = args[1]
|
||||
if prefix == "." || prefix == "/" {
|
||||
prefix = ""
|
||||
}
|
||||
} else {
|
||||
prefix = ""
|
||||
}
|
||||
|
||||
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
snapshot, err := snapshotCollection.ByName(name)
|
||||
if err != nil {
|
||||
@@ -67,10 +72,21 @@ func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
|
||||
|
||||
published := debian.NewPublishedRepo(prefix, distribution, component, context.architecturesList, snapshot)
|
||||
|
||||
duplicate := publishedCollecton.CheckDuplicate(published)
|
||||
if duplicate != nil {
|
||||
publishedCollecton.LoadComplete(duplicate, snapshotCollection)
|
||||
return fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
|
||||
}
|
||||
|
||||
packageCollection := debian.NewPackageCollection(context.database)
|
||||
err = published.Publish(context.packageRepository, packageCollection, signer)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("unable to publish: %s", err)
|
||||
}
|
||||
|
||||
err = publishedCollecton.Add(published)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to save to DB: %s", err)
|
||||
}
|
||||
|
||||
if prefix != "" && !strings.HasSuffix(prefix, "/") {
|
||||
|
||||
158
debian/publish.go
vendored
158
debian/publish.go
vendored
@@ -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)
|
||||
}
|
||||
|
||||
139
debian/publish_test.go
vendored
139
debian/publish_test.go
vendored
@@ -1,6 +1,7 @@
|
||||
package debian
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/smira/aptly/database"
|
||||
. "launchpad.net/gocheck"
|
||||
"os"
|
||||
@@ -25,6 +26,7 @@ type PublishedRepoSuite struct {
|
||||
PackageListMixinSuite
|
||||
repo *PublishedRepo
|
||||
packageRepo *Repository
|
||||
snapshot *Snapshot
|
||||
db database.Storage
|
||||
packageCollection *PackageCollection
|
||||
}
|
||||
@@ -41,9 +43,9 @@ func (s *PublishedRepoSuite) SetUpTest(c *C) {
|
||||
repo, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{})
|
||||
repo.packageRefs = s.reflist
|
||||
|
||||
snapshot, _ := NewSnapshotFromRepository("snap", repo)
|
||||
s.snapshot, _ = NewSnapshotFromRepository("snap", repo)
|
||||
|
||||
s.repo = NewPublishedRepo("ppa", "squeeze", "main", nil, snapshot)
|
||||
s.repo = NewPublishedRepo("ppa", "squeeze", "main", nil, s.snapshot)
|
||||
|
||||
s.packageCollection = NewPackageCollection(s.db)
|
||||
s.packageCollection.Update(s.p1)
|
||||
@@ -57,6 +59,10 @@ func (s *PublishedRepoSuite) SetUpTest(c *C) {
|
||||
f.Close()
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TearDownTest(c *C) {
|
||||
s.db.Close()
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestPublish(c *C) {
|
||||
err := s.repo.Publish(s.packageRepo, s.packageCollection, &NullSigner{})
|
||||
c.Assert(err, IsNil)
|
||||
@@ -93,3 +99,132 @@ func (s *PublishedRepoSuite) TestPublish(c *C) {
|
||||
_, err = os.Stat(filepath.Join(s.packageRepo.RootPath, "public/ppa/pool/main/a/alien-arena/alien-arena-common_7.40-2_i386.deb"))
|
||||
c.Assert(err, IsNil)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestString(c *C) {
|
||||
c.Check(s.repo.String(), Equals,
|
||||
"ppa/squeeze (main) publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
||||
c.Check(NewPublishedRepo("", "squeeze", "main", nil, s.snapshot).String(), Equals,
|
||||
"./squeeze (main) publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
||||
c.Check(NewPublishedRepo("", "squeeze", "main", []string{"i386", "amd64"}, s.snapshot).String(), Equals,
|
||||
"./squeeze (main) [i386, amd64] publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestKey(c *C) {
|
||||
c.Check(s.repo.Key(), DeepEquals, []byte("Uppa>>squeeze"))
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestEncodeDecode(c *C) {
|
||||
encoded := s.repo.Encode()
|
||||
repo := &PublishedRepo{}
|
||||
err := repo.Decode(encoded)
|
||||
|
||||
s.repo.snapshot = nil
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(repo, DeepEquals, s.repo)
|
||||
}
|
||||
|
||||
type PublishedRepoCollectionSuite struct {
|
||||
PackageListMixinSuite
|
||||
db database.Storage
|
||||
snapshotCollection *SnapshotCollection
|
||||
collection *PublishedRepoCollection
|
||||
snap1, snap2 *Snapshot
|
||||
repo1, repo2, repo3 *PublishedRepo
|
||||
}
|
||||
|
||||
var _ = Suite(&PublishedRepoCollectionSuite{})
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) {
|
||||
s.db, _ = database.OpenDB(c.MkDir())
|
||||
|
||||
s.snapshotCollection = NewSnapshotCollection(s.db)
|
||||
|
||||
s.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1")
|
||||
s.snap2 = NewSnapshotFromPackageList("snap2", []*Snapshot{}, NewPackageList(), "desc2")
|
||||
|
||||
s.snapshotCollection.Add(s.snap1)
|
||||
s.snapshotCollection.Add(s.snap2)
|
||||
|
||||
s.repo1 = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap1)
|
||||
s.repo2 = NewPublishedRepo("", "anaconda", "main", []string{}, s.snap2)
|
||||
s.repo3 = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap2)
|
||||
|
||||
s.collection = NewPublishedRepoCollection(s.db)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TearDownTest(c *C) {
|
||||
s.db.Close()
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TestAddByName(c *C) {
|
||||
r, err := s.collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Assert(err, ErrorMatches, "*.not found")
|
||||
|
||||
c.Assert(s.collection.Add(s.repo1), IsNil)
|
||||
c.Assert(s.collection.Add(s.repo1), ErrorMatches, ".*already exists")
|
||||
c.Assert(s.collection.CheckDuplicate(s.repo2), IsNil)
|
||||
c.Assert(s.collection.Add(s.repo2), IsNil)
|
||||
c.Assert(s.collection.Add(s.repo3), ErrorMatches, ".*already exists")
|
||||
c.Assert(s.collection.CheckDuplicate(s.repo3), Equals, s.repo1)
|
||||
|
||||
r, err = s.collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.collection.LoadComplete(r, s.snapshotCollection)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.String(), Equals, s.repo1.String())
|
||||
|
||||
collection := NewPublishedRepoCollection(s.db)
|
||||
r, err = collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.collection.LoadComplete(r, s.snapshotCollection)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.String(), Equals, s.repo1.String())
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TestByUUID(c *C) {
|
||||
r, err := s.collection.ByUUID(s.repo1.UUID)
|
||||
c.Assert(err, ErrorMatches, "*.not found")
|
||||
|
||||
c.Assert(s.collection.Add(s.repo1), IsNil)
|
||||
|
||||
r, err = s.collection.ByUUID(s.repo1.UUID)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.collection.LoadComplete(r, s.snapshotCollection)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.String(), Equals, s.repo1.String())
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TestUpdateLoadComplete(c *C) {
|
||||
c.Assert(s.collection.Update(s.repo1), IsNil)
|
||||
|
||||
collection := NewPublishedRepoCollection(s.db)
|
||||
r, err := collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.snapshot, IsNil)
|
||||
c.Assert(s.collection.LoadComplete(r, s.snapshotCollection), IsNil)
|
||||
c.Assert(r.snapshot.UUID, Equals, s.repo1.snapshot.UUID)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TestForEachAndLen(c *C) {
|
||||
s.collection.Add(s.repo1)
|
||||
|
||||
count := 0
|
||||
err := s.collection.ForEach(func(*PublishedRepo) error {
|
||||
count++
|
||||
return nil
|
||||
})
|
||||
c.Assert(count, Equals, 1)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Check(s.collection.Len(), Equals, 1)
|
||||
|
||||
e := errors.New("c")
|
||||
|
||||
err = s.collection.ForEach(func(*PublishedRepo) error {
|
||||
return e
|
||||
})
|
||||
c.Assert(err, Equals, e)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user