mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-04 05:10:40 +00:00
Local repo: model + collection.
This commit is contained in:
Vendored
+214
@@ -0,0 +1,214 @@
|
||||
package debian
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"fmt"
|
||||
"github.com/smira/aptly/database"
|
||||
"github.com/ugorji/go/codec"
|
||||
"log"
|
||||
)
|
||||
|
||||
// LocalRepo is a collection of packages created locally
|
||||
type LocalRepo struct {
|
||||
// Permanent internal ID
|
||||
UUID string
|
||||
// User-assigned name
|
||||
Name string
|
||||
// Comment
|
||||
Comment string
|
||||
// "Snapshot" of current list of packages
|
||||
packageRefs *PackageRefList
|
||||
}
|
||||
|
||||
// NewLocalRepo creates new instance of Debian local repository
|
||||
func NewLocalRepo(name string, comment string) *LocalRepo {
|
||||
if comment == "" {
|
||||
comment = "local repo"
|
||||
}
|
||||
return &LocalRepo{
|
||||
UUID: uuid.New(),
|
||||
Name: name,
|
||||
Comment: comment,
|
||||
}
|
||||
}
|
||||
|
||||
// String interface
|
||||
func (repo *LocalRepo) String() string {
|
||||
return fmt.Sprintf("[%s]: %s", repo.Name, repo.Comment)
|
||||
}
|
||||
|
||||
// NumPackages return number of packages in local repo
|
||||
func (repo *LocalRepo) NumPackages() int {
|
||||
if repo.packageRefs == nil {
|
||||
return 0
|
||||
}
|
||||
return repo.packageRefs.Len()
|
||||
}
|
||||
|
||||
// RefList returns package list for repo
|
||||
func (repo *LocalRepo) RefList() *PackageRefList {
|
||||
return repo.packageRefs
|
||||
}
|
||||
|
||||
// Encode does msgpack encoding of LocalRepo
|
||||
func (repo *LocalRepo) Encode() []byte {
|
||||
var buf bytes.Buffer
|
||||
|
||||
encoder := codec.NewEncoder(&buf, &codec.MsgpackHandle{})
|
||||
encoder.Encode(repo)
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// Decode decodes msgpack representation into LocalRepo
|
||||
func (repo *LocalRepo) Decode(input []byte) error {
|
||||
decoder := codec.NewDecoderBytes(input, &codec.MsgpackHandle{})
|
||||
return decoder.Decode(repo)
|
||||
}
|
||||
|
||||
// Key is a unique id in DB
|
||||
func (repo *LocalRepo) Key() []byte {
|
||||
return []byte("L" + repo.UUID)
|
||||
}
|
||||
|
||||
// RefKey is a unique id for package reference list
|
||||
func (repo *LocalRepo) RefKey() []byte {
|
||||
return []byte("E" + repo.UUID)
|
||||
}
|
||||
|
||||
// LocalRepoCollection does listing, updating/adding/deleting of LocalRepos
|
||||
type LocalRepoCollection struct {
|
||||
db database.Storage
|
||||
list []*LocalRepo
|
||||
}
|
||||
|
||||
// NewLocalRepoCollection loads LocalRepos from DB and makes up collection
|
||||
func NewLocalRepoCollection(db database.Storage) *LocalRepoCollection {
|
||||
result := &LocalRepoCollection{
|
||||
db: db,
|
||||
}
|
||||
|
||||
blobs := db.FetchByPrefix([]byte("L"))
|
||||
result.list = make([]*LocalRepo, 0, len(blobs))
|
||||
|
||||
for _, blob := range blobs {
|
||||
r := &LocalRepo{}
|
||||
if err := r.Decode(blob); err != nil {
|
||||
log.Printf("Error decoding mirror: %s\n", err)
|
||||
} else {
|
||||
result.list = append(result.list, r)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Add appends new repo to collection and saves it
|
||||
func (collection *LocalRepoCollection) Add(repo *LocalRepo) error {
|
||||
for _, r := range collection.list {
|
||||
if r.Name == repo.Name {
|
||||
return fmt.Errorf("local repo with name %s already exists", repo.Name)
|
||||
}
|
||||
}
|
||||
|
||||
err := collection.Update(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
collection.list = append(collection.list, repo)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update stores updated information about repo in DB
|
||||
func (collection *LocalRepoCollection) Update(repo *LocalRepo) error {
|
||||
err := collection.db.Put(repo.Key(), repo.Encode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if repo.packageRefs != nil {
|
||||
err = collection.db.Put(repo.RefKey(), repo.packageRefs.Encode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadComplete loads additional information for local repo
|
||||
func (collection *LocalRepoCollection) LoadComplete(repo *LocalRepo) error {
|
||||
encoded, err := collection.db.Get(repo.RefKey())
|
||||
if err == database.ErrNotFound {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
repo.packageRefs = &PackageRefList{}
|
||||
return repo.packageRefs.Decode(encoded)
|
||||
}
|
||||
|
||||
// ByName looks up repository by name
|
||||
func (collection *LocalRepoCollection) ByName(name string) (*LocalRepo, error) {
|
||||
for _, r := range collection.list {
|
||||
if r.Name == name {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("local repo with name %s not found", name)
|
||||
}
|
||||
|
||||
// ByUUID looks up repository by uuid
|
||||
func (collection *LocalRepoCollection) ByUUID(uuid string) (*LocalRepo, error) {
|
||||
for _, r := range collection.list {
|
||||
if r.UUID == uuid {
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("local repo with uuid %s not found", uuid)
|
||||
}
|
||||
|
||||
// ForEach runs method for each repository
|
||||
func (collection *LocalRepoCollection) ForEach(handler func(*LocalRepo) 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 *LocalRepoCollection) Len() int {
|
||||
return len(collection.list)
|
||||
}
|
||||
|
||||
// Drop removes remote repo from collection
|
||||
func (collection *LocalRepoCollection) Drop(repo *LocalRepo) error {
|
||||
repoPosition := -1
|
||||
|
||||
for i, r := range collection.list {
|
||||
if r == repo {
|
||||
repoPosition = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if repoPosition == -1 {
|
||||
panic("local repo not found!")
|
||||
}
|
||||
|
||||
collection.list[len(collection.list)-1], collection.list[repoPosition], collection.list =
|
||||
nil, collection.list[len(collection.list)-1], collection.list[:len(collection.list)-1]
|
||||
|
||||
err := collection.db.Delete(repo.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return collection.db.Delete(repo.RefKey())
|
||||
}
|
||||
Vendored
+190
@@ -0,0 +1,190 @@
|
||||
package debian
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/smira/aptly/database"
|
||||
. "launchpad.net/gocheck"
|
||||
)
|
||||
|
||||
type LocalRepoSuite struct {
|
||||
db database.Storage
|
||||
list *PackageList
|
||||
reflist *PackageRefList
|
||||
repo *LocalRepo
|
||||
}
|
||||
|
||||
var _ = Suite(&LocalRepoSuite{})
|
||||
|
||||
func (s *LocalRepoSuite) SetUpTest(c *C) {
|
||||
s.db, _ = database.OpenDB(c.MkDir())
|
||||
s.list = NewPackageList()
|
||||
s.list.Add(&Package{Name: "lib", Version: "1.7", Architecture: "i386"})
|
||||
s.list.Add(&Package{Name: "app", Version: "1.9", Architecture: "amd64"})
|
||||
|
||||
s.reflist = NewPackageRefListFromPackageList(s.list)
|
||||
|
||||
s.repo = NewLocalRepo("lrepo", "Super repo")
|
||||
s.repo.packageRefs = s.reflist
|
||||
}
|
||||
|
||||
func (s *LocalRepoSuite) TearDownTest(c *C) {
|
||||
s.db.Close()
|
||||
}
|
||||
|
||||
func (s *LocalRepoSuite) TestString(c *C) {
|
||||
c.Check(NewLocalRepo("lrepo", "My first repo").String(), Equals, "[lrepo]: My first repo")
|
||||
c.Check(NewLocalRepo("lrepo2", "").String(), Equals, "[lrepo2]: local repo")
|
||||
}
|
||||
|
||||
func (s *LocalRepoSuite) TestNumPackages(c *C) {
|
||||
c.Check(NewLocalRepo("lrepo", "My first repo").NumPackages(), Equals, 0)
|
||||
c.Check(s.repo.NumPackages(), Equals, 2)
|
||||
}
|
||||
|
||||
func (s *LocalRepoSuite) TestRefList(c *C) {
|
||||
c.Check(NewLocalRepo("lrepo", "My first repo").RefList(), IsNil)
|
||||
c.Check(s.repo.RefList(), Equals, s.reflist)
|
||||
}
|
||||
|
||||
func (s *LocalRepoSuite) TestEncodeDecode(c *C) {
|
||||
repo := &LocalRepo{}
|
||||
err := repo.Decode(s.repo.Encode())
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Check(repo.Name, Equals, s.repo.Name)
|
||||
c.Check(repo.Comment, Equals, s.repo.Comment)
|
||||
}
|
||||
|
||||
func (s *LocalRepoSuite) TestKey(c *C) {
|
||||
c.Assert(len(s.repo.Key()), Equals, 37)
|
||||
c.Assert(s.repo.Key()[0], Equals, byte('L'))
|
||||
}
|
||||
|
||||
func (s *LocalRepoSuite) TestRefKey(c *C) {
|
||||
c.Assert(len(s.repo.RefKey()), Equals, 37)
|
||||
c.Assert(s.repo.RefKey()[0], Equals, byte('E'))
|
||||
c.Assert(s.repo.RefKey()[1:], DeepEquals, s.repo.Key()[1:])
|
||||
}
|
||||
|
||||
type LocalRepoCollectionSuite struct {
|
||||
db database.Storage
|
||||
collection *LocalRepoCollection
|
||||
list *PackageList
|
||||
reflist *PackageRefList
|
||||
}
|
||||
|
||||
var _ = Suite(&LocalRepoCollectionSuite{})
|
||||
|
||||
func (s *LocalRepoCollectionSuite) SetUpTest(c *C) {
|
||||
s.db, _ = database.OpenDB(c.MkDir())
|
||||
s.collection = NewLocalRepoCollection(s.db)
|
||||
|
||||
s.list = NewPackageList()
|
||||
s.list.Add(&Package{Name: "lib", Version: "1.7", Architecture: "i386"})
|
||||
s.list.Add(&Package{Name: "app", Version: "1.9", Architecture: "amd64"})
|
||||
|
||||
s.reflist = NewPackageRefListFromPackageList(s.list)
|
||||
}
|
||||
|
||||
func (s *LocalRepoCollectionSuite) TearDownTest(c *C) {
|
||||
s.db.Close()
|
||||
}
|
||||
|
||||
func (s *LocalRepoCollectionSuite) TestAddByName(c *C) {
|
||||
r, err := s.collection.ByName("local1")
|
||||
c.Assert(err, ErrorMatches, "*.not found")
|
||||
|
||||
repo := NewLocalRepo("local1", "Comment 1")
|
||||
c.Assert(s.collection.Add(repo), IsNil)
|
||||
c.Assert(s.collection.Add(repo), ErrorMatches, ".*already exists")
|
||||
|
||||
r, err = s.collection.ByName("local1")
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.String(), Equals, repo.String())
|
||||
|
||||
collection := NewLocalRepoCollection(s.db)
|
||||
r, err = collection.ByName("local1")
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.String(), Equals, repo.String())
|
||||
}
|
||||
|
||||
func (s *LocalRepoCollectionSuite) TestByUUID(c *C) {
|
||||
r, err := s.collection.ByUUID("some-uuid")
|
||||
c.Assert(err, ErrorMatches, "*.not found")
|
||||
|
||||
repo := NewLocalRepo("local1", "Comment 1")
|
||||
c.Assert(s.collection.Add(repo), IsNil)
|
||||
|
||||
r, err = s.collection.ByUUID(repo.UUID)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.String(), Equals, repo.String())
|
||||
}
|
||||
|
||||
func (s *LocalRepoCollectionSuite) TestUpdateLoadComplete(c *C) {
|
||||
repo := NewLocalRepo("local1", "Comment 1")
|
||||
c.Assert(s.collection.Update(repo), IsNil)
|
||||
|
||||
collection := NewLocalRepoCollection(s.db)
|
||||
r, err := collection.ByName("local1")
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.packageRefs, IsNil)
|
||||
|
||||
repo.packageRefs = s.reflist
|
||||
c.Assert(s.collection.Update(repo), IsNil)
|
||||
|
||||
collection = NewLocalRepoCollection(s.db)
|
||||
r, err = collection.ByName("local1")
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.packageRefs, IsNil)
|
||||
c.Assert(r.NumPackages(), Equals, 0)
|
||||
c.Assert(s.collection.LoadComplete(r), IsNil)
|
||||
c.Assert(r.NumPackages(), Equals, 2)
|
||||
}
|
||||
|
||||
func (s *LocalRepoCollectionSuite) TestForEachAndLen(c *C) {
|
||||
repo := NewLocalRepo("local1", "Comment 1")
|
||||
s.collection.Add(repo)
|
||||
|
||||
count := 0
|
||||
err := s.collection.ForEach(func(*LocalRepo) 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(*LocalRepo) error {
|
||||
return e
|
||||
})
|
||||
c.Assert(err, Equals, e)
|
||||
}
|
||||
|
||||
func (s *LocalRepoCollectionSuite) TestDrop(c *C) {
|
||||
repo1 := NewLocalRepo("local1", "Comment 1")
|
||||
s.collection.Add(repo1)
|
||||
|
||||
repo2 := NewLocalRepo("local2", "Comment 2")
|
||||
s.collection.Add(repo2)
|
||||
|
||||
r1, _ := s.collection.ByUUID(repo1.UUID)
|
||||
c.Check(r1, Equals, repo1)
|
||||
|
||||
err := s.collection.Drop(repo1)
|
||||
c.Check(err, IsNil)
|
||||
|
||||
_, err = s.collection.ByUUID(repo1.UUID)
|
||||
c.Check(err, ErrorMatches, "local repo .* not found")
|
||||
|
||||
collection := NewLocalRepoCollection(s.db)
|
||||
_, err = collection.ByName("local1")
|
||||
c.Check(err, ErrorMatches, "local repo .* not found")
|
||||
|
||||
r2, _ := collection.ByName("local2")
|
||||
c.Check(r2.String(), Equals, repo2.String())
|
||||
|
||||
c.Check(func() { s.collection.Drop(repo1) }, Panics, "local repo not found!")
|
||||
}
|
||||
Reference in New Issue
Block a user