mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-05-06 22:18:28 +00:00
Repository name, uuid, persistence, lookup.
This commit is contained in:
Vendored
+110
-9
@@ -2,10 +2,14 @@
|
|||||||
package debian
|
package debian
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"code.google.com/p/go-uuid/uuid"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/smira/aptly/database"
|
"github.com/smira/aptly/database"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
debc "github.com/smira/godebiancontrol"
|
debc "github.com/smira/godebiancontrol"
|
||||||
|
"github.com/ugorji/go/codec"
|
||||||
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -15,35 +19,48 @@ import (
|
|||||||
// Repostitory could be filtered when fetching by components, architectures
|
// Repostitory could be filtered when fetching by components, architectures
|
||||||
// TODO: support flat format
|
// TODO: support flat format
|
||||||
type RemoteRepo struct {
|
type RemoteRepo struct {
|
||||||
ArchiveRoot string
|
// Permanent internal ID
|
||||||
Distribution string
|
UUID string
|
||||||
Components []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
|
Architectures []string
|
||||||
archiveRootURL *url.URL
|
archiveRootURL *url.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRemoteRepo creates new instance of Debian remote repository with specified params
|
// 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{
|
result := &RemoteRepo{
|
||||||
|
UUID: uuid.New(),
|
||||||
|
Name: name,
|
||||||
ArchiveRoot: archiveRoot,
|
ArchiveRoot: archiveRoot,
|
||||||
Distribution: distribution,
|
Distribution: distribution,
|
||||||
Components: components,
|
Components: components,
|
||||||
Architectures: architectures,
|
Architectures: architectures,
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
err := result.prepare()
|
||||||
|
|
||||||
result.archiveRootURL, err = url.Parse(archiveRoot)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *RemoteRepo) prepare() error {
|
||||||
|
var err error
|
||||||
|
repo.archiveRootURL, err = url.Parse(repo.ArchiveRoot)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// String interface
|
// String interface
|
||||||
func (repo *RemoteRepo) String() string {
|
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
|
// 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
|
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)
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+58
-4
@@ -1,6 +1,7 @@
|
|||||||
package debian
|
package debian
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/smira/aptly/database"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
. "launchpad.net/gocheck"
|
. "launchpad.net/gocheck"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -19,12 +20,12 @@ type RemoteRepoSuite struct {
|
|||||||
var _ = Suite(&RemoteRepoSuite{})
|
var _ = Suite(&RemoteRepoSuite{})
|
||||||
|
|
||||||
func (s *RemoteRepoSuite) SetUpTest(c *C) {
|
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)
|
s.downloader = utils.NewFakeDownloader().ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RemoteRepoSuite) TestInvalidURL(c *C) {
|
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.*")
|
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")
|
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) {
|
func (s *RemoteRepoSuite) TestFetch(c *C) {
|
||||||
err := s.repo.Fetch(s.downloader)
|
err := s.repo.Fetch(s.downloader)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
@@ -44,17 +50,65 @@ func (s *RemoteRepoSuite) TestFetch(c *C) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *RemoteRepoSuite) TestFetchWrongArchitecture(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)
|
err := s.repo.Fetch(s.downloader)
|
||||||
c.Assert(err, ErrorMatches, "architecture xyz not available in repo.*")
|
c.Assert(err, ErrorMatches, "architecture xyz not available in repo.*")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RemoteRepoSuite) TestFetchWrongComponent(c *C) {
|
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)
|
err := s.repo.Fetch(s.downloader)
|
||||||
c.Assert(err, ErrorMatches, "component xyz not available in repo.*")
|
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
|
const exampleReleaseFile = `Origin: LP-PPA-agenda-developers-daily
|
||||||
Label: Agenda Daily Builds
|
Label: Agenda Daily Builds
|
||||||
Suite: precise
|
Suite: precise
|
||||||
|
|||||||
Reference in New Issue
Block a user