1package deb
2
3import (
4	"bytes"
5	"errors"
6	"fmt"
7	"io/ioutil"
8	"os"
9	"path/filepath"
10
11	"github.com/aptly-dev/aptly/aptly"
12	"github.com/aptly-dev/aptly/database"
13	"github.com/aptly-dev/aptly/files"
14	"github.com/ugorji/go/codec"
15
16	. "gopkg.in/check.v1"
17)
18
19type pathExistsChecker struct {
20	*CheckerInfo
21}
22
23var PathExists = &pathExistsChecker{
24	&CheckerInfo{Name: "PathExists", Params: []string{"path"}},
25}
26
27func (checker *pathExistsChecker) Check(params []interface{}, names []string) (result bool, error string) {
28	_, err := os.Stat(params[0].(string))
29	return err == nil, ""
30}
31
32type NullSigner struct{}
33
34func (n *NullSigner) Init() error {
35	return nil
36}
37
38func (n *NullSigner) SetKey(keyRef string) {
39}
40
41func (n *NullSigner) SetBatch(batch bool) {
42}
43
44func (n *NullSigner) SetKeyRing(keyring, secretKeyring string) {
45}
46
47func (n *NullSigner) SetPassphrase(passphrase, passphraseFile string) {
48}
49
50func (n *NullSigner) DetachedSign(source string, destination string) error {
51	return ioutil.WriteFile(destination, []byte{}, 0644)
52}
53
54func (n *NullSigner) ClearSign(source string, destination string) error {
55	return ioutil.WriteFile(destination, []byte{}, 0644)
56}
57
58type FakeStorageProvider struct {
59	storages map[string]aptly.PublishedStorage
60}
61
62func (p *FakeStorageProvider) GetPublishedStorage(name string) aptly.PublishedStorage {
63	storage, ok := p.storages[name]
64	if !ok {
65		panic(fmt.Sprintf("unknown storage: %#v", name))
66	}
67	return storage
68}
69
70type PublishedRepoSuite struct {
71	PackageListMixinSuite
72	repo, repo2, repo3, repo4, repo5    *PublishedRepo
73	root, root2                         string
74	provider                            *FakeStorageProvider
75	publishedStorage, publishedStorage2 *files.PublishedStorage
76	packagePool                         aptly.PackagePool
77	cs                                  aptly.ChecksumStorage
78	localRepo                           *LocalRepo
79	snapshot, snapshot2                 *Snapshot
80	db                                  database.Storage
81	factory                             *CollectionFactory
82	packageCollection                   *PackageCollection
83}
84
85var _ = Suite(&PublishedRepoSuite{})
86
87func (s *PublishedRepoSuite) SetUpTest(c *C) {
88	s.SetUpPackages()
89
90	s.db, _ = database.NewOpenDB(c.MkDir())
91	s.factory = NewCollectionFactory(s.db)
92
93	s.root = c.MkDir()
94	s.publishedStorage = files.NewPublishedStorage(s.root, "", "")
95	s.root2 = c.MkDir()
96	s.publishedStorage2 = files.NewPublishedStorage(s.root2, "", "")
97	s.provider = &FakeStorageProvider{map[string]aptly.PublishedStorage{
98		"":            s.publishedStorage,
99		"files:other": s.publishedStorage2}}
100	s.packagePool = files.NewPackagePool(s.root, false)
101	s.cs = files.NewMockChecksumStorage()
102
103	tmpFilepath := filepath.Join(c.MkDir(), "file")
104	c.Assert(ioutil.WriteFile(tmpFilepath, nil, 0777), IsNil)
105
106	var err error
107	s.p1.Files()[0].PoolPath, err = s.packagePool.Import(tmpFilepath, s.p1.Files()[0].Filename, &s.p1.Files()[0].Checksums, false, s.cs)
108	c.Assert(err, IsNil)
109
110	s.p1.UpdateFiles(s.p1.Files())
111	s.p2.UpdateFiles(s.p1.Files())
112	s.p3.UpdateFiles(s.p1.Files())
113
114	s.reflist = NewPackageRefListFromPackageList(s.list)
115
116	repo, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{}, false, false, false)
117	repo.packageRefs = s.reflist
118	s.factory.RemoteRepoCollection().Add(repo)
119
120	s.localRepo = NewLocalRepo("local1", "comment1")
121	s.localRepo.packageRefs = s.reflist
122	s.factory.LocalRepoCollection().Add(s.localRepo)
123
124	s.snapshot, _ = NewSnapshotFromRepository("snap", repo)
125	s.factory.SnapshotCollection().Add(s.snapshot)
126
127	s.snapshot2, _ = NewSnapshotFromRepository("snap", repo)
128	s.factory.SnapshotCollection().Add(s.snapshot2)
129
130	s.packageCollection = s.factory.PackageCollection()
131	s.packageCollection.Update(s.p1)
132	s.packageCollection.Update(s.p2)
133	s.packageCollection.Update(s.p3)
134
135	s.repo, _ = NewPublishedRepo("", "ppa", "squeeze", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory)
136	s.repo.SkipContents = true
137
138	s.repo2, _ = NewPublishedRepo("", "ppa", "maverick", nil, []string{"main"}, []interface{}{s.localRepo}, s.factory)
139	s.repo2.SkipContents = true
140
141	s.repo3, _ = NewPublishedRepo("", "linux", "natty", nil, []string{"main", "contrib"}, []interface{}{s.snapshot, s.snapshot2}, s.factory)
142	s.repo3.SkipContents = true
143
144	s.repo4, _ = NewPublishedRepo("", "ppa", "maverick", []string{"source"}, []string{"main"}, []interface{}{s.localRepo}, s.factory)
145	s.repo4.SkipContents = true
146
147	s.repo5, _ = NewPublishedRepo("files:other", "ppa", "maverick", []string{"source"}, []string{"main"}, []interface{}{s.localRepo}, s.factory)
148	s.repo5.SkipContents = true
149}
150
151func (s *PublishedRepoSuite) TearDownTest(c *C) {
152	s.db.Close()
153}
154
155func (s *PublishedRepoSuite) TestNewPublishedRepo(c *C) {
156	c.Check(s.repo.sourceItems["main"].snapshot, Equals, s.snapshot)
157	c.Check(s.repo.SourceKind, Equals, "snapshot")
158	c.Check(s.repo.Sources["main"], Equals, s.snapshot.UUID)
159	c.Check(s.repo.Components(), DeepEquals, []string{"main"})
160
161	c.Check(s.repo2.sourceItems["main"].localRepo, Equals, s.localRepo)
162	c.Check(s.repo2.SourceKind, Equals, "local")
163	c.Check(s.repo2.Sources["main"], Equals, s.localRepo.UUID)
164	c.Check(s.repo2.sourceItems["main"].packageRefs.Len(), Equals, 3)
165	c.Check(s.repo2.Components(), DeepEquals, []string{"main"})
166
167	c.Check(s.repo.RefList("main").Len(), Equals, 3)
168	c.Check(s.repo2.RefList("main").Len(), Equals, 3)
169
170	c.Check(s.repo3.Sources, DeepEquals, map[string]string{"main": s.snapshot.UUID, "contrib": s.snapshot2.UUID})
171	c.Check(s.repo3.SourceKind, Equals, "snapshot")
172	c.Check(s.repo3.sourceItems["main"].snapshot, Equals, s.snapshot)
173	c.Check(s.repo3.sourceItems["contrib"].snapshot, Equals, s.snapshot2)
174	c.Check(s.repo3.Components(), DeepEquals, []string{"contrib", "main"})
175
176	c.Check(s.repo3.RefList("main").Len(), Equals, 3)
177	c.Check(s.repo3.RefList("contrib").Len(), Equals, 3)
178
179	c.Check(func() { NewPublishedRepo("", ".", "a", nil, nil, nil, s.factory) }, PanicMatches, "publish with empty sources")
180	c.Check(func() {
181		NewPublishedRepo("", ".", "a", nil, []string{"main"}, []interface{}{s.snapshot, s.snapshot2}, s.factory)
182	}, PanicMatches, "sources and components should be equal in size")
183	c.Check(func() {
184		NewPublishedRepo("", ".", "a", nil, []string{"main", "contrib"}, []interface{}{s.localRepo, s.snapshot2}, s.factory)
185	}, PanicMatches, "interface conversion:.*")
186
187	_, err := NewPublishedRepo("", ".", "a", nil, []string{"main", "main"}, []interface{}{s.snapshot, s.snapshot2}, s.factory)
188	c.Check(err, ErrorMatches, "duplicate component name: main")
189
190	_, err = NewPublishedRepo("", ".", "wheezy/updates", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory)
191	c.Check(err, ErrorMatches, "invalid distribution wheezy/updates, '/' is not allowed")
192}
193
194func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) {
195
196	for _, t := range []struct {
197		prefix        string
198		expected      string
199		errorExpected string
200	}{
201		{
202			prefix:   "ppa",
203			expected: "ppa",
204		},
205		{
206			prefix:   "",
207			expected: ".",
208		},
209		{
210			prefix:   "/",
211			expected: ".",
212		},
213		{
214			prefix:   "//",
215			expected: ".",
216		},
217		{
218			prefix:   "//ppa/",
219			expected: "ppa",
220		},
221		{
222			prefix:   "ppa/..",
223			expected: ".",
224		},
225		{
226			prefix:   "ppa/ubuntu/",
227			expected: "ppa/ubuntu",
228		},
229		{
230			prefix:   "ppa/../ubuntu/",
231			expected: "ubuntu",
232		},
233		{
234			prefix:        "../ppa/",
235			errorExpected: "invalid prefix .*",
236		},
237		{
238			prefix:        "../ppa/../ppa/",
239			errorExpected: "invalid prefix .*",
240		},
241		{
242			prefix:        "ppa/dists",
243			errorExpected: "invalid prefix .*",
244		},
245		{
246			prefix:        "ppa/pool",
247			errorExpected: "invalid prefix .*",
248		},
249	} {
250		repo, err := NewPublishedRepo("", t.prefix, "squeeze", nil, []string{"main"}, []interface{}{s.snapshot}, s.factory)
251		if t.errorExpected != "" {
252			c.Check(err, ErrorMatches, t.errorExpected)
253		} else {
254			c.Check(repo.Prefix, Equals, t.expected)
255		}
256	}
257}
258
259func (s *PublishedRepoSuite) TestDistributionComponentGuessing(c *C) {
260	repo, err := NewPublishedRepo("", "ppa", "", nil, []string{""}, []interface{}{s.snapshot}, s.factory)
261	c.Check(err, IsNil)
262	c.Check(repo.Distribution, Equals, "squeeze")
263	c.Check(repo.Components(), DeepEquals, []string{"main"})
264
265	repo, err = NewPublishedRepo("", "ppa", "wheezy", nil, []string{""}, []interface{}{s.snapshot}, s.factory)
266	c.Check(err, IsNil)
267	c.Check(repo.Distribution, Equals, "wheezy")
268	c.Check(repo.Components(), DeepEquals, []string{"main"})
269
270	repo, err = NewPublishedRepo("", "ppa", "", nil, []string{"non-free"}, []interface{}{s.snapshot}, s.factory)
271	c.Check(err, IsNil)
272	c.Check(repo.Distribution, Equals, "squeeze")
273	c.Check(repo.Components(), DeepEquals, []string{"non-free"})
274
275	repo, err = NewPublishedRepo("", "ppa", "squeeze", nil, []string{""}, []interface{}{s.localRepo}, s.factory)
276	c.Check(err, IsNil)
277	c.Check(repo.Distribution, Equals, "squeeze")
278	c.Check(repo.Components(), DeepEquals, []string{"main"})
279
280	_, err = NewPublishedRepo("", "ppa", "", nil, []string{"main"}, []interface{}{s.localRepo}, s.factory)
281	c.Check(err, ErrorMatches, "unable to guess distribution name, please specify explicitly")
282
283	s.localRepo.DefaultDistribution = "precise"
284	s.localRepo.DefaultComponent = "contrib"
285	s.factory.LocalRepoCollection().Update(s.localRepo)
286
287	repo, err = NewPublishedRepo("", "ppa", "", nil, []string{""}, []interface{}{s.localRepo}, s.factory)
288	c.Check(err, IsNil)
289	c.Check(repo.Distribution, Equals, "precise")
290	c.Check(repo.Components(), DeepEquals, []string{"contrib"})
291
292	s.localRepo.DefaultDistribution = "precise/updates"
293
294	repo, err = NewPublishedRepo("", "ppa", "", nil, []string{""}, []interface{}{s.localRepo}, s.factory)
295	c.Check(err, IsNil)
296	c.Check(repo.Distribution, Equals, "precise-updates")
297	c.Check(repo.Components(), DeepEquals, []string{"contrib"})
298
299	repo, err = NewPublishedRepo("", "ppa", "", nil, []string{"", "contrib"}, []interface{}{s.snapshot, s.snapshot2}, s.factory)
300	c.Check(err, IsNil)
301	c.Check(repo.Distribution, Equals, "squeeze")
302	c.Check(repo.Components(), DeepEquals, []string{"contrib", "main"})
303
304	_, err = NewPublishedRepo("", "ppa", "", nil, []string{"", ""}, []interface{}{s.snapshot, s.snapshot2}, s.factory)
305	c.Check(err, ErrorMatches, "duplicate component name: main")
306}
307
308func (s *PublishedRepoSuite) TestPublish(c *C) {
309	err := s.repo.Publish(s.packagePool, s.provider, s.factory, &NullSigner{}, nil, false)
310	c.Assert(err, IsNil)
311
312	c.Check(s.repo.Architectures, DeepEquals, []string{"i386"})
313
314	rf, err := os.Open(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/squeeze/Release"))
315	c.Assert(err, IsNil)
316
317	cfr := NewControlFileReader(rf, true, false)
318	st, err := cfr.ReadStanza()
319	c.Assert(err, IsNil)
320
321	c.Check(st["Origin"], Equals, "ppa squeeze")
322	c.Check(st["Components"], Equals, "main")
323	c.Check(st["Architectures"], Equals, "i386")
324
325	pf, err := os.Open(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/squeeze/main/binary-i386/Packages"))
326	c.Assert(err, IsNil)
327
328	cfr = NewControlFileReader(pf, false, false)
329
330	for i := 0; i < 3; i++ {
331		st, err = cfr.ReadStanza()
332		c.Assert(err, IsNil)
333
334		c.Check(st["Filename"], Equals, "pool/main/a/alien-arena/alien-arena-common_7.40-2_i386.deb")
335	}
336
337	st, err = cfr.ReadStanza()
338	c.Assert(err, IsNil)
339	c.Assert(st, IsNil)
340
341	drf, err := os.Open(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/squeeze/main/binary-i386/Release"))
342	c.Assert(err, IsNil)
343
344	cfr = NewControlFileReader(drf, true, false)
345	st, err = cfr.ReadStanza()
346	c.Assert(err, IsNil)
347
348	c.Check(st["Archive"], Equals, "squeeze")
349	c.Check(st["Architecture"], Equals, "i386")
350
351	_, err = os.Stat(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main/a/alien-arena/alien-arena-common_7.40-2_i386.deb"))
352	c.Assert(err, IsNil)
353}
354
355func (s *PublishedRepoSuite) TestPublishNoSigner(c *C) {
356	err := s.repo.Publish(s.packagePool, s.provider, s.factory, nil, nil, false)
357	c.Assert(err, IsNil)
358
359	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/squeeze/Release"), PathExists)
360	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/squeeze/main/binary-i386/Release"), PathExists)
361}
362
363func (s *PublishedRepoSuite) TestPublishLocalRepo(c *C) {
364	err := s.repo2.Publish(s.packagePool, s.provider, s.factory, nil, nil, false)
365	c.Assert(err, IsNil)
366
367	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/maverick/Release"), PathExists)
368	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/maverick/main/binary-i386/Release"), PathExists)
369}
370
371func (s *PublishedRepoSuite) TestPublishLocalSourceRepo(c *C) {
372	err := s.repo4.Publish(s.packagePool, s.provider, s.factory, nil, nil, false)
373	c.Assert(err, IsNil)
374
375	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/maverick/Release"), PathExists)
376	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/maverick/main/source/Release"), PathExists)
377}
378
379func (s *PublishedRepoSuite) TestPublishOtherStorage(c *C) {
380	err := s.repo5.Publish(s.packagePool, s.provider, s.factory, nil, nil, false)
381	c.Assert(err, IsNil)
382
383	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/maverick/Release"), PathExists)
384	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/maverick/Release"), Not(PathExists))
385}
386
387func (s *PublishedRepoSuite) TestString(c *C) {
388	c.Check(s.repo.String(), Equals,
389		"ppa/squeeze [] publishes {main: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}")
390	c.Check(s.repo2.String(), Equals,
391		"ppa/maverick [] publishes {main: [local1]: comment1}")
392	repo, _ := NewPublishedRepo("", "", "squeeze", []string{"s390"}, []string{"main"}, []interface{}{s.snapshot}, s.factory)
393	c.Check(repo.String(), Equals,
394		"./squeeze [s390] publishes {main: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}")
395	repo, _ = NewPublishedRepo("", "", "squeeze", []string{"i386", "amd64"}, []string{"main"}, []interface{}{s.snapshot}, s.factory)
396	c.Check(repo.String(), Equals,
397		"./squeeze [i386, amd64] publishes {main: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}")
398	repo.Origin = "myorigin"
399	c.Check(repo.String(), Equals,
400		"./squeeze (origin: myorigin) [i386, amd64] publishes {main: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}")
401	repo.Label = "mylabel"
402	c.Check(repo.String(), Equals,
403		"./squeeze (origin: myorigin, label: mylabel) [i386, amd64] publishes {main: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}")
404	c.Check(s.repo3.String(), Equals,
405		"linux/natty [] publishes {contrib: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}, {main: [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze}")
406	c.Check(s.repo5.String(), Equals,
407		"files:other:ppa/maverick [source] publishes {main: [local1]: comment1}")
408}
409
410func (s *PublishedRepoSuite) TestKey(c *C) {
411	c.Check(s.repo.Key(), DeepEquals, []byte("Uppa>>squeeze"))
412	c.Check(s.repo5.Key(), DeepEquals, []byte("Ufiles:other:ppa>>maverick"))
413}
414
415func (s *PublishedRepoSuite) TestRefKey(c *C) {
416	c.Check(s.repo.RefKey(""), DeepEquals, []byte("E"+s.repo.UUID))
417	c.Check(s.repo.RefKey("main"), DeepEquals, []byte("E"+s.repo.UUID+"main"))
418}
419
420func (s *PublishedRepoSuite) TestEncodeDecode(c *C) {
421	encoded := s.repo.Encode()
422	repo := &PublishedRepo{}
423	err := repo.Decode(encoded)
424
425	s.repo.sourceItems = nil
426	c.Assert(err, IsNil)
427	c.Assert(repo, DeepEquals, s.repo)
428
429	encoded2 := s.repo2.Encode()
430	repo2 := &PublishedRepo{}
431	err = repo2.Decode(encoded2)
432
433	s.repo2.sourceItems = nil
434	c.Assert(err, IsNil)
435	c.Assert(repo2, DeepEquals, s.repo2)
436}
437
438type PublishedRepoCollectionSuite struct {
439	PackageListMixinSuite
440	db                                database.Storage
441	factory                           *CollectionFactory
442	snapshotCollection                *SnapshotCollection
443	collection                        *PublishedRepoCollection
444	snap1, snap2                      *Snapshot
445	localRepo                         *LocalRepo
446	repo1, repo2, repo3, repo4, repo5 *PublishedRepo
447}
448
449var _ = Suite(&PublishedRepoCollectionSuite{})
450
451func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) {
452	s.db, _ = database.NewOpenDB(c.MkDir())
453	s.factory = NewCollectionFactory(s.db)
454
455	s.snapshotCollection = s.factory.SnapshotCollection()
456
457	s.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1")
458	s.snap2 = NewSnapshotFromPackageList("snap2", []*Snapshot{}, NewPackageList(), "desc2")
459
460	s.snapshotCollection.Add(s.snap1)
461	s.snapshotCollection.Add(s.snap2)
462
463	s.localRepo = NewLocalRepo("local1", "comment1")
464	s.factory.LocalRepoCollection().Add(s.localRepo)
465
466	s.repo1, _ = NewPublishedRepo("", "ppa", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory)
467	s.repo2, _ = NewPublishedRepo("", "", "anaconda", []string{}, []string{"main", "contrib"}, []interface{}{s.snap2, s.snap1}, s.factory)
468	s.repo3, _ = NewPublishedRepo("", "ppa", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap2}, s.factory)
469	s.repo4, _ = NewPublishedRepo("", "ppa", "precise", []string{}, []string{"main"}, []interface{}{s.localRepo}, s.factory)
470	s.repo5, _ = NewPublishedRepo("files:other", "ppa", "precise", []string{}, []string{"main"}, []interface{}{s.localRepo}, s.factory)
471
472	s.collection = s.factory.PublishedRepoCollection()
473}
474
475func (s *PublishedRepoCollectionSuite) TearDownTest(c *C) {
476	s.db.Close()
477}
478
479func (s *PublishedRepoCollectionSuite) TestAddByStoragePrefixDistribution(c *C) {
480	_, err := s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
481	c.Assert(err, ErrorMatches, "*.not found")
482
483	c.Assert(s.collection.Add(s.repo1), IsNil)
484	c.Assert(s.collection.Add(s.repo1), ErrorMatches, ".*already exists")
485	c.Assert(s.collection.CheckDuplicate(s.repo2), IsNil)
486	c.Assert(s.collection.Add(s.repo2), IsNil)
487	c.Assert(s.collection.Add(s.repo3), ErrorMatches, ".*already exists")
488	c.Assert(s.collection.CheckDuplicate(s.repo3), Equals, s.repo1)
489	c.Assert(s.collection.Add(s.repo4), IsNil)
490	c.Assert(s.collection.Add(s.repo5), IsNil)
491
492	r, err := s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
493	c.Assert(err, IsNil)
494
495	err = s.collection.LoadComplete(r, s.factory)
496	c.Assert(err, IsNil)
497	c.Assert(r.String(), Equals, s.repo1.String())
498
499	collection := NewPublishedRepoCollection(s.db)
500	r, err = collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
501	c.Assert(err, IsNil)
502
503	err = s.collection.LoadComplete(r, s.factory)
504	c.Assert(err, IsNil)
505	c.Assert(r.String(), Equals, s.repo1.String())
506
507	r, err = s.collection.ByStoragePrefixDistribution("files:other", "ppa", "precise")
508	c.Assert(err, IsNil)
509	c.Check(r.String(), Equals, s.repo5.String())
510}
511
512func (s *PublishedRepoCollectionSuite) TestByUUID(c *C) {
513	_, err := s.collection.ByUUID(s.repo1.UUID)
514	c.Assert(err, ErrorMatches, "*.not found")
515
516	c.Assert(s.collection.Add(s.repo1), IsNil)
517
518	r, err := s.collection.ByUUID(s.repo1.UUID)
519	c.Assert(err, IsNil)
520
521	err = s.collection.LoadComplete(r, s.factory)
522	c.Assert(err, IsNil)
523	c.Assert(r.String(), Equals, s.repo1.String())
524}
525
526func (s *PublishedRepoCollectionSuite) TestUpdateLoadComplete(c *C) {
527	c.Assert(s.collection.Update(s.repo1), IsNil)
528	c.Assert(s.collection.Update(s.repo4), IsNil)
529
530	collection := NewPublishedRepoCollection(s.db)
531	r, err := collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
532	c.Assert(err, IsNil)
533	c.Assert(r.sourceItems["main"].snapshot, IsNil)
534	c.Assert(s.collection.LoadComplete(r, s.factory), IsNil)
535	c.Assert(r.Sources["main"], Equals, s.repo1.sourceItems["main"].snapshot.UUID)
536	c.Assert(r.RefList("main").Len(), Equals, 0)
537
538	r, err = collection.ByStoragePrefixDistribution("", "ppa", "precise")
539	c.Assert(err, IsNil)
540	c.Assert(r.sourceItems["main"].localRepo, IsNil)
541	c.Assert(s.collection.LoadComplete(r, s.factory), IsNil)
542	c.Assert(r.sourceItems["main"].localRepo.UUID, Equals, s.repo4.sourceItems["main"].localRepo.UUID)
543	c.Assert(r.sourceItems["main"].packageRefs.Len(), Equals, 0)
544	c.Assert(r.RefList("main").Len(), Equals, 0)
545}
546
547func (s *PublishedRepoCollectionSuite) TestLoadPre0_6(c *C) {
548	type oldPublishedRepo struct {
549		UUID          string
550		Prefix        string
551		Distribution  string
552		Origin        string
553		Label         string
554		Architectures []string
555		SourceKind    string
556		Component     string
557		SourceUUID    string `codec:"SnapshotUUID"`
558	}
559
560	old := oldPublishedRepo{
561		UUID:          s.repo1.UUID,
562		Prefix:        "ppa",
563		Distribution:  "anaconda",
564		Architectures: []string{"i386"},
565		SourceKind:    SourceLocalRepo,
566		Component:     "contrib",
567		SourceUUID:    s.localRepo.UUID,
568	}
569
570	var buf bytes.Buffer
571
572	encoder := codec.NewEncoder(&buf, &codec.MsgpackHandle{})
573	encoder.Encode(&old)
574
575	c.Assert(s.db.Put(s.repo1.Key(), buf.Bytes()), IsNil)
576	c.Assert(s.db.Put(s.repo1.RefKey(""), s.localRepo.RefList().Encode()), IsNil)
577
578	collection := NewPublishedRepoCollection(s.db)
579	repo, err := collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
580	c.Check(err, IsNil)
581	c.Check(repo.Component, Equals, "")
582	c.Check(repo.SourceUUID, Equals, "")
583	c.Check(repo.Sources, DeepEquals, map[string]string{"contrib": s.localRepo.UUID})
584
585	c.Check(collection.LoadComplete(repo, s.factory), IsNil)
586	c.Check(repo.sourceItems["contrib"].localRepo.UUID, Equals, s.localRepo.UUID)
587	c.Check(repo.RefList("contrib").Len(), Equals, 0)
588}
589
590func (s *PublishedRepoCollectionSuite) TestForEachAndLen(c *C) {
591	s.collection.Add(s.repo1)
592
593	count := 0
594	err := s.collection.ForEach(func(*PublishedRepo) error {
595		count++
596		return nil
597	})
598	c.Assert(count, Equals, 1)
599	c.Assert(err, IsNil)
600
601	c.Check(s.collection.Len(), Equals, 1)
602
603	e := errors.New("c")
604
605	err = s.collection.ForEach(func(*PublishedRepo) error {
606		return e
607	})
608	c.Assert(err, Equals, e)
609}
610
611func (s *PublishedRepoCollectionSuite) TestBySnapshot(c *C) {
612	c.Check(s.collection.Add(s.repo1), IsNil)
613	c.Check(s.collection.Add(s.repo2), IsNil)
614
615	c.Check(s.collection.BySnapshot(s.snap1), DeepEquals, []*PublishedRepo{s.repo1, s.repo2})
616	c.Check(s.collection.BySnapshot(s.snap2), DeepEquals, []*PublishedRepo{s.repo2})
617}
618
619func (s *PublishedRepoCollectionSuite) TestByLocalRepo(c *C) {
620	c.Check(s.collection.Add(s.repo1), IsNil)
621	c.Check(s.collection.Add(s.repo4), IsNil)
622	c.Check(s.collection.Add(s.repo5), IsNil)
623
624	c.Check(s.collection.ByLocalRepo(s.localRepo), DeepEquals, []*PublishedRepo{s.repo4, s.repo5})
625}
626
627type PublishedRepoRemoveSuite struct {
628	PackageListMixinSuite
629	db                                  database.Storage
630	factory                             *CollectionFactory
631	snapshotCollection                  *SnapshotCollection
632	collection                          *PublishedRepoCollection
633	root, root2                         string
634	provider                            *FakeStorageProvider
635	publishedStorage, publishedStorage2 *files.PublishedStorage
636	snap1                               *Snapshot
637	repo1, repo2, repo3, repo4, repo5   *PublishedRepo
638}
639
640var _ = Suite(&PublishedRepoRemoveSuite{})
641
642func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) {
643	s.db, _ = database.NewOpenDB(c.MkDir())
644	s.factory = NewCollectionFactory(s.db)
645
646	s.snapshotCollection = s.factory.SnapshotCollection()
647
648	s.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1")
649
650	s.snapshotCollection.Add(s.snap1)
651
652	s.repo1, _ = NewPublishedRepo("", "ppa", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory)
653	s.repo2, _ = NewPublishedRepo("", "", "anaconda", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory)
654	s.repo3, _ = NewPublishedRepo("", "ppa", "meduza", []string{}, []string{"main"}, []interface{}{s.snap1}, s.factory)
655	s.repo4, _ = NewPublishedRepo("", "ppa", "osminog", []string{}, []string{"contrib"}, []interface{}{s.snap1}, s.factory)
656	s.repo5, _ = NewPublishedRepo("files:other", "ppa", "osminog", []string{}, []string{"contrib"}, []interface{}{s.snap1}, s.factory)
657
658	s.collection = s.factory.PublishedRepoCollection()
659	s.collection.Add(s.repo1)
660	s.collection.Add(s.repo2)
661	s.collection.Add(s.repo3)
662	s.collection.Add(s.repo4)
663	s.collection.Add(s.repo5)
664
665	s.root = c.MkDir()
666	s.publishedStorage = files.NewPublishedStorage(s.root, "", "")
667	s.publishedStorage.MkDir("ppa/dists/anaconda")
668	s.publishedStorage.MkDir("ppa/dists/meduza")
669	s.publishedStorage.MkDir("ppa/dists/osminog")
670	s.publishedStorage.MkDir("ppa/pool/main")
671	s.publishedStorage.MkDir("ppa/pool/contrib")
672	s.publishedStorage.MkDir("dists/anaconda")
673	s.publishedStorage.MkDir("pool/main")
674
675	s.root2 = c.MkDir()
676	s.publishedStorage2 = files.NewPublishedStorage(s.root2, "", "")
677	s.publishedStorage2.MkDir("ppa/dists/osminog")
678	s.publishedStorage2.MkDir("ppa/pool/contrib")
679
680	s.provider = &FakeStorageProvider{map[string]aptly.PublishedStorage{
681		"":            s.publishedStorage,
682		"files:other": s.publishedStorage2}}
683}
684
685func (s *PublishedRepoRemoveSuite) TearDownTest(c *C) {
686	s.db.Close()
687}
688
689func (s *PublishedRepoRemoveSuite) TestRemoveFilesOnlyDist(c *C) {
690	s.repo1.RemoveFiles(s.provider, false, []string{}, nil)
691
692	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
693	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
694	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
695	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), PathExists)
696	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
697	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
698	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
699	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
700	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
701}
702
703func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPool(c *C) {
704	s.repo1.RemoveFiles(s.provider, false, []string{"main"}, nil)
705
706	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
707	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
708	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
709	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), Not(PathExists))
710	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
711	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
712	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
713	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
714	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
715}
716
717func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithTwoPools(c *C) {
718	s.repo1.RemoveFiles(s.provider, false, []string{"main", "contrib"}, nil)
719
720	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
721	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
722	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
723	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), Not(PathExists))
724	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), Not(PathExists))
725	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
726	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
727	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
728	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
729}
730
731func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPrefix(c *C) {
732	s.repo1.RemoveFiles(s.provider, true, []string{"main"}, nil)
733
734	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
735	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), Not(PathExists))
736	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), Not(PathExists))
737	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), Not(PathExists))
738	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), Not(PathExists))
739	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
740	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
741	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
742	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
743}
744
745func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPrefixRoot(c *C) {
746	s.repo2.RemoveFiles(s.provider, true, []string{"main"}, nil)
747
748	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), PathExists)
749	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
750	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), PathExists)
751	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
752	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), Not(PathExists))
753	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), Not(PathExists))
754	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
755	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
756}
757
758func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2(c *C) {
759	err := s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false, false)
760	c.Check(err, IsNil)
761
762	_, err = s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
763	c.Check(err, ErrorMatches, ".*not found")
764
765	collection := NewPublishedRepoCollection(s.db)
766	_, err = collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
767	c.Check(err, ErrorMatches, ".*not found")
768
769	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
770	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
771	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
772	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), PathExists)
773	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
774	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
775	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
776	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
777	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
778
779	err = s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false, false)
780	c.Check(err, ErrorMatches, ".*not found")
781
782	err = s.collection.Remove(s.provider, "", "ppa", "meduza", s.factory, nil, false, false)
783	c.Check(err, IsNil)
784
785	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
786	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), Not(PathExists))
787	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
788	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), Not(PathExists))
789	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
790	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
791	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
792	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
793	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
794}
795
796func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2SkipCleanup(c *C) {
797	err := s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false, true)
798	c.Check(err, IsNil)
799
800	_, err = s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
801	c.Check(err, ErrorMatches, ".*not found")
802
803	collection := NewPublishedRepoCollection(s.db)
804	_, err = collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
805	c.Check(err, ErrorMatches, ".*not found")
806
807	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
808	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
809	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
810	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), PathExists)
811	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
812	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
813	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
814	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
815	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
816
817	err = s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false, true)
818	c.Check(err, ErrorMatches, ".*not found")
819
820	err = s.collection.Remove(s.provider, "", "ppa", "meduza", s.factory, nil, false, true)
821	c.Check(err, IsNil)
822
823	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
824	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), Not(PathExists))
825	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
826	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), Not(PathExists))
827	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
828	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
829	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
830	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
831	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
832}
833
834func (s *PublishedRepoRemoveSuite) TestRemoveRepo3(c *C) {
835	err := s.collection.Remove(s.provider, "", ".", "anaconda", s.factory, nil, false, false)
836	c.Check(err, IsNil)
837
838	_, err = s.collection.ByStoragePrefixDistribution("", ".", "anaconda")
839	c.Check(err, ErrorMatches, ".*not found")
840
841	collection := NewPublishedRepoCollection(s.db)
842	_, err = collection.ByStoragePrefixDistribution("", ".", "anaconda")
843	c.Check(err, ErrorMatches, ".*not found")
844
845	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), PathExists)
846	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
847	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
848	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), PathExists)
849	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
850	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/"), Not(PathExists))
851	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/"), Not(PathExists))
852	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
853	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
854}
855
856func (s *PublishedRepoRemoveSuite) TestRemoveRepo5(c *C) {
857	err := s.collection.Remove(s.provider, "files:other", "ppa", "osminog", s.factory, nil, false, false)
858	c.Check(err, IsNil)
859
860	_, err = s.collection.ByStoragePrefixDistribution("files:other", "ppa", "osminog")
861	c.Check(err, ErrorMatches, ".*not found")
862
863	collection := NewPublishedRepoCollection(s.db)
864	_, err = collection.ByStoragePrefixDistribution("files:other", "ppa", "osminog")
865	c.Check(err, ErrorMatches, ".*not found")
866
867	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), PathExists)
868	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
869	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
870	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), PathExists)
871	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
872	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/"), PathExists)
873	c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/"), PathExists)
874	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), Not(PathExists))
875	c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), Not(PathExists))
876}
877