Repository name, uuid, persistence, lookup.

This commit is contained in:
Andrey Smirnov
2013-12-19 16:33:53 +04:00
parent 97f4e8d5f2
commit 7470016094
2 changed files with 168 additions and 13 deletions

119
debian/remote.go vendored
View File

@@ -2,10 +2,14 @@
package debian
import (
"bytes"
"code.google.com/p/go-uuid/uuid"
"fmt"
"github.com/smira/aptly/database"
"github.com/smira/aptly/utils"
debc "github.com/smira/godebiancontrol"
"github.com/ugorji/go/codec"
"log"
"net/url"
"strings"
)
@@ -15,35 +19,48 @@ import (
// Repostitory could be filtered when fetching by components, architectures
// TODO: support flat format
type RemoteRepo struct {
ArchiveRoot string
Distribution string
Components []string
// Permanent internal ID
UUID string
// User-assigned name
Name string
// Root of Debian archive, URL
ArchiveRoot string
// Distribution name, e.g. squeeze
Distribution string
// List of components to fetch, if empty, then fetch all components
Components []string
// List of architectures to fetch, if empty, then fetch all architectures
Architectures []string
archiveRootURL *url.URL
}
// NewRemoteRepo creates new instance of Debian remote repository with specified params
func NewRemoteRepo(archiveRoot string, distribution string, components []string, architectures []string) (*RemoteRepo, error) {
func NewRemoteRepo(name string, archiveRoot string, distribution string, components []string, architectures []string) (*RemoteRepo, error) {
result := &RemoteRepo{
UUID: uuid.New(),
Name: name,
ArchiveRoot: archiveRoot,
Distribution: distribution,
Components: components,
Architectures: architectures,
}
var err error
result.archiveRootURL, err = url.Parse(archiveRoot)
err := result.prepare()
if err != nil {
return nil, err
}
return result, nil
}
func (repo *RemoteRepo) prepare() error {
var err error
repo.archiveRootURL, err = url.Parse(repo.ArchiveRoot)
return err
}
// String interface
func (repo *RemoteRepo) String() string {
return fmt.Sprintf("%s %s", repo.ArchiveRoot, repo.Distribution)
return fmt.Sprintf("[%s]: %s %s", repo.Name, repo.ArchiveRoot, repo.Distribution)
}
// ReleaseURL returns URL to Release file in repo root
@@ -166,3 +183,87 @@ func (repo *RemoteRepo) Download(d utils.Downloader, db database.Storage, packag
return nil
}
// Encode does msgpack encoding of RemoteRepo
func (repo *RemoteRepo) Encode() []byte {
var buf bytes.Buffer
encoder := codec.NewEncoder(&buf, &codec.MsgpackHandle{})
encoder.Encode(repo)
return buf.Bytes()
}
// Decode decodes msgpack representation into RemoteRepo
func (repo *RemoteRepo) Decode(input []byte) error {
decoder := codec.NewDecoderBytes(input, &codec.MsgpackHandle{})
err := decoder.Decode(repo)
if err != nil {
return err
}
return repo.prepare()
}
// Key is a unique id in DB
func (repo *RemoteRepo) Key() []byte {
return []byte("R" + repo.UUID)
}
// RemoteRepoCollection does listing, updating/adding/deleting of RemoteRepos
type RemoteRepoCollection struct {
db database.Storage
list []*RemoteRepo
}
// NewRemoteRepoCollection loads RemoteRepos from DB and makes up collection
func NewRemoteRepoCollection(db database.Storage) *RemoteRepoCollection {
result := &RemoteRepoCollection{
db: db,
}
blobs := db.FetchByPrefix([]byte("R"))
result.list = make([]*RemoteRepo, 0, len(blobs))
for _, blob := range blobs {
r := &RemoteRepo{}
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 *RemoteRepoCollection) Add(repo *RemoteRepo) error {
for _, r := range collection.list {
if r.Name == repo.Name {
return fmt.Errorf("mirror 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 *RemoteRepoCollection) Update(repo *RemoteRepo) error {
return collection.db.Put(repo.Key(), repo.Encode())
}
// ByName looks up repository by name
func (collection *RemoteRepoCollection) ByName(name string) (*RemoteRepo, error) {
for _, r := range collection.list {
if r.Name == name {
return r, nil
}
}
return nil, fmt.Errorf("mirror with name %s not found", name)
}

62
debian/remote_test.go vendored
View File

@@ -1,6 +1,7 @@
package debian
import (
"github.com/smira/aptly/database"
"github.com/smira/aptly/utils"
. "launchpad.net/gocheck"
"testing"
@@ -19,12 +20,12 @@ type RemoteRepoSuite struct {
var _ = Suite(&RemoteRepoSuite{})
func (s *RemoteRepoSuite) SetUpTest(c *C) {
s.repo, _ = NewRemoteRepo("http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{})
s.repo, _ = NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{})
s.downloader = utils.NewFakeDownloader().ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile)
}
func (s *RemoteRepoSuite) TestInvalidURL(c *C) {
_, err := NewRemoteRepo("http://lolo%2", "squeeze", []string{"main"}, []string{})
_, err := NewRemoteRepo("s", "http://lolo%2", "squeeze", []string{"main"}, []string{})
c.Assert(err, ErrorMatches, ".*hexadecimal escape in host.*")
}
@@ -36,6 +37,11 @@ func (s *RemoteRepoSuite) TestBinaryURL(c *C) {
c.Assert(s.repo.BinaryURL("main", "amd64").String(), Equals, "http://mirror.yandex.ru/debian/dists/squeeze/main/binary-amd64/Packages")
}
func (s *RemoteRepoSuite) TestPackageURL(c *C) {
c.Assert(s.repo.PackageURL("pool/main/0/0ad/0ad_0~r11863-2_i386.deb").String(), Equals,
"http://mirror.yandex.ru/debian/pool/main/0/0ad/0ad_0~r11863-2_i386.deb")
}
func (s *RemoteRepoSuite) TestFetch(c *C) {
err := s.repo.Fetch(s.downloader)
c.Assert(err, IsNil)
@@ -44,17 +50,65 @@ func (s *RemoteRepoSuite) TestFetch(c *C) {
}
func (s *RemoteRepoSuite) TestFetchWrongArchitecture(c *C) {
s.repo, _ = NewRemoteRepo("http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{"xyz"})
s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{"xyz"})
err := s.repo.Fetch(s.downloader)
c.Assert(err, ErrorMatches, "architecture xyz not available in repo.*")
}
func (s *RemoteRepoSuite) TestFetchWrongComponent(c *C) {
s.repo, _ = NewRemoteRepo("http://mirror.yandex.ru/debian/", "squeeze", []string{"xyz"}, []string{"i386"})
s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"xyz"}, []string{"i386"})
err := s.repo.Fetch(s.downloader)
c.Assert(err, ErrorMatches, "component xyz not available in repo.*")
}
func (s *RemoteRepoSuite) TestEncodeDecode(c *C) {
repo := &RemoteRepo{}
err := repo.Decode(s.repo.Encode())
c.Assert(err, IsNil)
c.Check(repo.Name, Equals, "yandex")
c.Check(repo.ArchiveRoot, Equals, "http://mirror.yandex.ru/debian/")
}
func (s *RemoteRepoSuite) TestKey(c *C) {
c.Assert(len(s.repo.Key()), Equals, 37)
}
type RemoteRepoCollectionSuite struct {
db database.Storage
collection *RemoteRepoCollection
}
var _ = Suite(&RemoteRepoCollectionSuite{})
func (s *RemoteRepoCollectionSuite) SetUpTest(c *C) {
s.db, _ = database.OpenDB(c.MkDir())
s.collection = NewRemoteRepoCollection(s.db)
}
func (s *RemoteRepoCollectionSuite) TearDownTest(c *C) {
s.db.Close()
}
func (s *RemoteRepoCollectionSuite) TestAddByName(c *C) {
r, err := s.collection.ByName("yandex")
c.Assert(err, ErrorMatches, "*.not found")
repo, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{})
c.Assert(s.collection.Add(repo), IsNil)
c.Assert(s.collection.Add(repo), ErrorMatches, ".*already exists")
r, err = s.collection.ByName("yandex")
c.Assert(err, IsNil)
c.Assert(r.String(), Equals, repo.String())
collection := NewRemoteRepoCollection(s.db)
r, err = collection.ByName("yandex")
c.Assert(err, IsNil)
c.Assert(r.String(), Equals, repo.String())
}
const exampleReleaseFile = `Origin: LP-PPA-agenda-developers-daily
Label: Agenda Daily Builds
Suite: precise