Compare commits

..

116 Commits

Author SHA1 Message Date
Andrey Smirnov b5d025f141 Version bump for 0.5.1. 2014-05-10 18:10:19 +04:00
Andrey Smirnov 3c7a2281b2 Fix "production" libraries in Gomfile with exact SHA. 2014-05-10 18:08:12 +04:00
Andrey Smirnov be3ad21fbe Add target to build "all-in-one" source tarball for Debian. 2014-05-10 18:06:23 +04:00
Andrey Smirnov 5301e8a341 Fix pool directory for packages with version in Source: field. #44 2014-05-10 17:25:44 +04:00
Andrey Smirnov 49eed59238 Fix test on command line help. #47 2014-05-10 17:13:49 +04:00
Andrey Smirnov 3e78240b39 Remove debugging output. #47 2014-05-10 17:07:17 +04:00
Andrey Smirnov 10bbefeb25 Fix support for flat format repositories in subdirectories with common pool. #47 2014-05-10 16:56:50 +04:00
Andrey Smirnov 35eac72226 Missed file. #46 2014-05-10 13:35:06 +04:00
Andrey Smirnov 5371f94b7a Debian 7.5 has been released, update tests. 2014-05-10 13:34:46 +04:00
Andrey Smirnov 53adf39d89 Bring back automatic HTTP_PROXY setting from environment. #46 2014-05-10 13:27:01 +04:00
Andrey Smirnov bc7972ff68 Version bump for 0.6~dev. 2014-04-24 14:24:03 +04:00
Andrey Smirnov 21e8aa5519 Remove comments. 2014-04-24 01:31:31 +04:00
Andrey Smirnov f0825d93be aptly 0.5 2014-04-24 01:17:14 +04:00
Andrey Smirnov 9e538d9475 aptly version 0.5 2014-04-24 01:15:59 +04:00
Andrey Smirnov 042602f991 Update man page. #42 2014-04-24 01:03:15 +04:00
Andrey Smirnov e8a894bc88 More tests for merging. #42 2014-04-24 01:01:14 +04:00
Andrey Smirnov 59647fe6d0 Fix subtle bug in .Merge: if there are duplicate name-arch on the left, override them all. #42 2014-04-24 00:57:17 +04:00
Andrey Smirnov 37a6fb336a PackageList doesn't allow duplicates and PackageRefList does sorting on keys. #42 2014-04-23 23:47:32 +04:00
Andrey Smirnov 7c2faafa91 Simplify implementation (and improve performance) by using the fact that RefList is always sorted. #42 2014-04-23 23:46:33 +04:00
Andrey Smirnov 87295c6580 Move command description from man file to command help. #42
Man file is auto-generated from inline command help.

N.B. I should document this in Contributing.
2014-04-23 23:30:21 +04:00
Andrey Smirnov 4ce4923f58 Merge branch 'f-newestpkg' of https://github.com/ryanuber/aptly into ryanuber-lastest-merge 2014-04-23 23:21:39 +04:00
Andrey Smirnov 2a83596307 Merge pull request #43 from ryanuber/make_package
Fix path to manpage in Makefile
2014-04-23 22:56:37 +04:00
Ryan Uber 5f29cb202a Fix path to manpage in Makefile 2014-04-23 00:50:06 -07:00
Ryan Uber 3800f2c957 Added CLI test for snapshot merge with latest flag 2014-04-23 00:25:44 -07:00
Ryan Uber 6c3b2f686e snapshot: FilterLatestRefs returns nothing as it deals with a pointer. 2014-04-22 23:33:30 -07:00
Ryan Uber 708fd800df snapshot: separate test for FilterLatestRefs 2014-04-22 23:04:45 -07:00
Ryan Uber 385ac1afd0 snapshot: explicity call FilterLatestRefs() where needed rather than calling from Merge() 2014-04-22 22:28:14 -07:00
Ryan Uber d9f8673286 snapshot: break out FilterLatestPackages to its own function 2014-04-22 19:17:10 -07:00
Ryan Uber d1cc562f3c cmd/snapshot_merge: reword -latest flag to match man page 2014-04-22 17:48:53 -07:00
Ryan Uber e6992d822d Updated man page for snapshot merging with -latest flag 2014-04-22 17:46:29 -07:00
Ryan Uber 0d8debe7b6 snapshot: simplify merging latest packages 2014-04-22 17:44:03 -07:00
Ryan Uber 89eafd1b21 Initial pass at testing merged snapshotting with -latest flag 2014-04-22 17:44:03 -07:00
Ryan Uber 1a735e849b snapshot: alter result generation in Merge() to accommodate snapshot diff 2014-04-22 17:44:03 -07:00
Ryan Uber a93052aa8a snapshot: merge adjustments for -latest flag 2014-04-22 17:44:03 -07:00
Ryan Uber 133d67bffa snapshot: newest -> latest 2014-04-22 17:44:03 -07:00
Ryan Uber 60d48e890c snapshot: Move 'newest' logic out of main compilation loop and evaluate the reflist afterward. 2014-04-22 17:44:03 -07:00
Ryan Uber dbcfd6f58b snapshot: keep a tab of seen packages and only include the latest copy during merge 2014-04-22 17:44:03 -07:00
Ryan Uber cd369f5fa0 snapshot: add cli flag for taking newest during merge 2014-04-22 17:44:03 -07:00
Ryan Uber 992a5cee37 snapshot: first pass at newest-wins functionality. 2014-04-22 17:44:03 -07:00
Andrey Smirnov fb8686a634 Update man page. #8 2014-04-22 20:20:52 +04:00
Andrey Smirnov cc8baec317 Command aptly publish switch to switch published snapshot. #8 2014-04-22 20:17:21 +04:00
Andrey Smirnov 1200e9cc95 Command aptly publish update: update local repo published in-place. #8 2014-04-22 18:35:20 +04:00
Andrey Smirnov 3342ce490a System tests for cleaning up prefix/component. #8 2014-04-22 17:51:29 +04:00
Andrey Smirnov 4541e0bdae Fix misprint. #8 2014-04-22 17:51:22 +04:00
Andrey Smirnov 522684aabb Use progress for printing. #8 2014-04-22 17:19:39 +04:00
Andrey Smirnov 8963cd8027 Use progress when printing. #8 2014-04-22 17:19:10 +04:00
Andrey Smirnov 9445f3a0fa Basis for repo re-publishing, cleaning up prefix + component published package pool. #8 2014-04-22 17:07:25 +04:00
Andrey Smirnov d69eaeff4e New methods for public root: Filelist and Remove. #8 2014-04-22 17:05:32 +04:00
Andrey Smirnov 1bac201687 Refactoring: build pool path in Package. #8 2014-04-22 16:20:51 +04:00
Andrey Smirnov 45335da0ed Fix system tests. #41 2014-04-22 11:41:46 +04:00
Andrey Smirnov b10aeacfc0 Merge branch 'docfix' of https://github.com/Temikus/aptly 2014-04-22 11:28:34 +04:00
Artem Yakimenko d9f4686e2c Fixing minor spelling/grammar issues in documentation. 2014-04-22 11:08:57 +04:00
Andrey Smirnov 7eb2fdf425 Re-publishing for local repositories. #8
Cleanup part is missing.
2014-04-22 10:49:40 +04:00
Andrey Smirnov c70c196420 Renaming files in public area. #8 2014-04-22 10:40:17 +04:00
Andrey Smirnov e81f86f942 Slight refactoring, add oldRefs. #8 2014-04-21 21:26:44 +04:00
Andrey Smirnov 6352ce30ed Disable compression when downloading, otherwise HTTP client may do "decompression" on its own. #33 2014-04-16 15:55:04 +04:00
Andrey Smirnov cefc3cc2dc Fix test. #31 2014-04-16 00:22:11 +04:00
Andrey Smirnov 376bb69803 Updated man page. #31 2014-04-15 23:54:33 +04:00
Andrey Smirnov e33f5792e1 Add -raw for aptly publish list. #31 2014-04-15 23:53:53 +04:00
Andrey Smirnov 8d214e6d12 Add comments on precise file deletion. #8 2014-04-15 14:28:26 +04:00
Andrey Smirnov 73761c311e Update man. #29 [ci skip] 2014-04-15 13:36:29 +04:00
Andrey Smirnov b85f46547b Allow to customize Origin/Label during publishing. #29 2014-04-15 11:47:21 +04:00
Andrey Smirnov 108dc235a7 Update man page. #27 2014-04-15 11:09:25 +04:00
Andrey Smirnov 90dd21b270 Raw (machine-readable) format for aptly mirror/repo/snapshot list. #27 2014-04-15 10:43:36 +04:00
Andrey Smirnov ce615facf9 Fix gom invocation. #28
Thanks to @erickeller for finding that.
2014-04-13 23:10:53 +04:00
Andrey Smirnov a8cf83774a PublishedRepo remembers RefList is has been published with. #8 2014-04-08 11:58:32 +04:00
Andrey Smirnov 470571c7db Fix variable shadowing. 2014-04-08 11:53:02 +04:00
Andrey Smirnov 55807412a1 Update goleveldb with fix for missing manifest.
See also #25, syndtr/goleveldb#49
2014-04-08 11:47:16 +04:00
Andrey Smirnov c106e66cff Style fixes. 2014-04-08 01:39:41 +04:00
Andrey Smirnov d6fd4e46a0 Style fix. 2014-04-08 01:04:01 +04:00
Andrey Smirnov b34707faed man page built with fixed ronn. #22 2014-04-08 00:28:17 +04:00
Andrey Smirnov e4de1738ce Update to goleveldb with fix for missing CURRENT file in db. #25 2014-04-08 00:26:01 +04:00
Andrey Smirnov ff045f9a48 Fixups after renaming debian -> deb. #21 2014-04-07 21:22:58 +04:00
Andrey Smirnov fd662c9275 Rename debian -> deb. #21 2014-04-07 21:15:13 +04:00
Andrey Smirnov 83b2e0250d Rework fatal mechanism, open config on demand. 2014-04-06 21:05:06 +04:00
Andrey Smirnov 3db7125932 Refactor ppa parsing: take pointer to config. 2014-04-06 19:12:07 +04:00
Andrey Smirnov efcce4ef3c Re-enable system test on db recover with empty DB. #25 2014-04-06 16:10:11 +04:00
Andrey Smirnov d90f8dba7f Update goleveldb with my pull request merged. #25 2014-04-06 16:01:19 +04:00
Andrey Smirnov 173dd775bc Tests for aptly db recover. #25 2014-04-05 17:01:16 +04:00
Andrey Smirnov 4afa3126e4 Fix ugly bug. #25 2014-04-05 16:20:04 +04:00
Andrey Smirnov 5a6ccb7259 Add command aptly db recover. 2014-04-05 16:11:19 +04:00
Andrey Smirnov 2c3553ef0b Major refactoring: access to context happens in methods. #13 2014-04-05 16:10:51 +04:00
Andrey Smirnov 400d0da7d4 Add method to recover LevelDB after crash. 2014-04-05 00:30:39 +04:00
Andrey Smirnov 4caeea49b1 Stop building on 1.2. 2014-04-03 00:57:39 +04:00
Andrey Smirnov f648c9547c Support for switching to smira/commander with free placement of flags. #17 2014-04-03 00:16:18 +04:00
Andrey Smirnov d84226a054 Switch to own fork of commander/flag. 2014-03-28 23:05:54 +04:00
Andrey Smirnov 006d173d4f One more fix for the test. 2014-03-28 21:27:05 +04:00
Andrey Smirnov 6ca62a9d50 Fix test. 2014-03-28 21:04:29 +04:00
Andrey Smirnov c7dcc8ff59 System test for aptly repo edit. #12 2014-03-28 20:49:37 +04:00
Andrey Smirnov 4c237ed1b1 Command aptly repo edit to change repository defaults. #12 2014-03-28 20:41:51 +04:00
Andrey Smirnov ec866eb403 Pool would be modified by repo add, so create copy. 2014-03-26 22:29:43 +04:00
Andrey Smirnov 53e73c52a4 Tests for guessing publishing defaults from local repo params. #12 2014-03-26 21:40:17 +04:00
Andrey Smirnov 0f8f43b9f0 Default distribution/component could be specified when creating repo. #12 2014-03-26 21:24:09 +04:00
Andrey Smirnov 7f2f435e2d Forgotten file. #10 2014-03-26 21:23:49 +04:00
Andrey Smirnov c325119081 Repo can't be dropped if published. #10 2014-03-26 21:10:43 +04:00
Andrey Smirnov 3b16ca156a Pool as a fixture is not required. #10 2014-03-26 19:48:34 +04:00
Andrey Smirnov 22014206d7 System tests for aptly publish repo. #10 2014-03-26 19:44:38 +04:00
Andrey Smirnov 9ff49ff24a Fix words: source might be snapshot or local repo. #10 2014-03-26 19:44:15 +04:00
Andrey Smirnov 37ea845fd9 Command aptly publish repo. #10 2014-03-25 18:42:56 +04:00
Andrey Smirnov 1a88876e63 GPG may suddenly decide to re-validate its trustdb, resulting in any
call to `gpg` resulting in exit code 2.

Don't allow GPG to validate trustdb when invoked in automated fashion.
2014-03-25 18:42:03 +04:00
Andrey Smirnov 1a60ac6aa0 Refactoring: use CollectionFactory instead of manual collection creation. 2014-03-25 14:59:26 +04:00
Andrey Smirnov a0497058ee Don't allow to drop repo if it is published. 2014-03-25 14:29:25 +04:00
Andrey Smirnov 140c925079 Fix shadowed variables. 2014-03-24 18:39:45 +04:00
Andrey Smirnov 5bd5e0a827 Style fix. 2014-03-24 18:23:34 +04:00
Andrey Smirnov 3c32cd3884 Move man page to /usr/share/man/, as it should be. 2014-03-24 18:20:16 +04:00
Andrey Smirnov 32717e92ba First round of support for localRepos as source for publishing. Also more intelligent algo to get publishing defaults. #10 #12 2014-03-19 16:43:42 +04:00
Andrey Smirnov c2fc2f9988 Add placeholders for default local repo publish settings. #12 2014-03-19 16:19:57 +04:00
Andrey Smirnov 1189bca5a4 Add central place to create all collections from. 2014-03-18 18:58:09 +04:00
Andrey Smirnov 2315c00ae1 Test on creating snapshot from empty local repo. 2014-03-18 18:57:16 +04:00
Andrey Smirnov e5de8b9353 Print bytes in human-readable format. #18 2014-03-17 17:05:38 +04:00
Andrey Smirnov 099806aa82 Function HumanBytes for human-readable representation of numbers. #18 2014-03-17 16:47:04 +04:00
Andrey Smirnov 6a42aad322 Compact LevelDB in aptly db cleanup. #19 2014-03-17 16:22:49 +04:00
Andrey Smirnov b13e50a570 Bump version to development 0.5~dev. 2014-03-17 16:06:37 +04:00
Andrey Smirnov dff0ab2fa3 Leave filedescriptors to gpg. 2014-03-17 15:55:35 +04:00
Andrey Smirnov a7f135a441 .deb package building instructions. 2014-03-17 15:55:21 +04:00
Andrey Smirnov c71a57169c Add instruction on installation from repo. 2014-03-13 00:24:46 +04:00
261 changed files with 122939 additions and 1552 deletions
-1
View File
@@ -2,7 +2,6 @@ language: go
go:
- 1.1
- 1.2
- 1.2.1
- tip
+3 -3
View File
@@ -3,10 +3,10 @@ gom 'code.google.com/p/go.crypto/ssh/terminal', :commit => '7aa593ce8cea'
gom 'code.google.com/p/gographviz', :commit => '212766062629'
gom 'code.google.com/p/snappy-go/snappy', :commit => '12e4b4183793'
gom 'github.com/cheggaaa/pb', :commit => '74be7a1388046f374ac36e93d46f5d56e856f827'
gom 'github.com/gonuts/commander', :commit => 'f8ba4e959ca914268227c3ebbd7f6bf0bb35541a'
gom 'github.com/gonuts/flag', :commit => '741a6cbd37a30dedc93f817e7de6aaf0ca38a493'
gom 'github.com/smira/commander', :commit => '082a3ce267a8225a8ccf94deaf18901223d38fed'
gom 'github.com/smira/flag', :commit => '0d0aac2addb39050f45e92c5a6252926096dc841'
gom 'github.com/mkrautz/goar', :commit => '36eb5f3452b1283a211fa35bc00c646fd0db5c4b'
gom 'github.com/syndtr/goleveldb/leveldb', :commit => '527a7b286bd095794af6c519627b7ed3d8fd067a'
gom 'github.com/syndtr/goleveldb/leveldb', :commit => 'ff3719c6816e2cd194f05058452d660608e178ac'
gom 'github.com/ugorji/go/codec', :commit => '71c2886f5a673a35f909803f38ece5810165097b'
gom 'github.com/wsxiaoys/terminal/color', :commit => '5668e431776a7957528361f90ce828266c69ed08'
+25 -2
View File
@@ -1,6 +1,6 @@
GOVERSION=$(shell go version | awk '{print $$3;}')
PACKAGES=database debian files http utils
ALL_PACKAGES=aptly cmd console database debian files http utils
PACKAGES=database deb files http utils
ALL_PACKAGES=aptly cmd console database deb files http utils
BINPATH=$(abspath ./_vendor/bin)
GOM_ENVIRONMENT=-test
PYTHON?=python
@@ -61,4 +61,27 @@ mem.png: mem.dat mem.gp
gnuplot mem.gp
open mem.png
package:
rm -rf root/
mkdir -p root/usr/bin/ root/usr/share/man/man1/ root/etc/bash_completion.d
cp $(BINPATH)/aptly root/usr/bin
cp man/aptly.1 root/usr/share/man/man1
(cd root/etc/bash_completion.d && wget https://raw.github.com/aptly-dev/aptly-bash-completion/master/aptly)
gzip root/usr/share/man/man1/aptly.1
fpm -s dir -t deb -n aptly -v $(VERSION) --url=http://www.aptly.info/ --license=MIT --vendor="Andrey Smirnov <me@smira.ru>" \
-f -m "Andrey Smirnov <me@smira.ru>" --description="Debian repository management tool" -C root/ .
mv aptly_$(VERSION)_*.deb ~
src-package:
rm -rf aptly-$(VERSION)
mkdir -p aptly-$(VERSION)/src/github.com/smira/aptly/
cd aptly-$(VERSION)/src/github.com/smira/ && git clone https://github.com/smira/aptly && cd aptly && git checkout v$(VERSION)
cd aptly-$(VERSION)/src/github.com/smira/aptly && gom -production install
cd aptly-$(VERSION)/src/github.com/smira/aptly && find . -name .git -print | xargs rm -rf
cd aptly-$(VERSION)/src/github.com/smira/aptly && find . -name .bzr -print | xargs rm -rf
cd aptly-$(VERSION)/src/github.com/smira/aptly && find . -name .hg -print | xargs rm -rf
rm -rf aptly-$(VERSION)/src/github.com/smira/aptly/_vendor/{pkg,bin}
tar cyf aptly-$(VERSION)-src.tar.bz2 aptly-$(VERSION)
rm -rf aptly-$(VERSION)
.PHONY: coverage.out
+18 -1
View File
@@ -32,6 +32,23 @@ Current limitations:
Download
--------
To install aptly on Debian/Ubuntu, add new repository to /etc/apt/sources.list::
deb http://repo.aptly.info/ squeeze main
And import key that is used to sign the release::
$ gpg --keyserver keys.gnupg.net --recv-keys 2A194991
$ gpg -a --export 2A194991 | sudo apt-key add -
After that you can install aptly as any other software package::
$ apt-get update
$ apt-get install aptly
Don't worry about squeeze part in repo name: aptly package should work on Debian squeeze+,
Ubuntu 10.0+. Package contains aptly binary, man page and bash completion.
Binary executables (depends almost only on libc) are available for download from `Bintray <http://dl.bintray.com/smira/aptly/>`_.
If you have Go environment set up, you can build aptly from source by running (go 1.1+ required)::
@@ -40,7 +57,7 @@ If you have Go environment set up, you can build aptly from source by running (g
mkdir -p $GOPATH/src/github.com/smira/aptly
git clone https://github.com/smira/aptly $GOPATH/src/github.com/smira/aptly
cd $GOPATH/src/github.com/smira/aptly
gom install
gom -production install
gom build -o $GOPATH/bin/aptly
Aptly is using `gom <https://github.com/mattn/gom>`_ to fix external dependencies, so regular ``go get github.com/smira/aptly``
+8 -2
View File
@@ -33,11 +33,17 @@ type PublishedStorage interface {
// CreateFile creates file for writing under public path
CreateFile(path string) (*os.File, error)
// RemoveDirs removes directory structure under public path
RemoveDirs(path string) error
RemoveDirs(path string, progress Progress) error
// Remove removes single file under public path
Remove(path string) error
// LinkFromPool links package file from pool to dist's pool location
LinkFromPool(prefix string, component string, poolDirectory string, sourcePool PackagePool, sourcePath string) (string, error)
LinkFromPool(publishedDirectory string, sourcePool PackagePool, sourcePath string) error
// Filelist returns list of files under prefix
Filelist(prefix string) ([]string, error)
// ChecksumsForFile proxies requests to utils.ChecksumsForFile, joining public path
ChecksumsForFile(path string) (utils.ChecksumInfo, error)
// RenameFile renames (moves) file
RenameFile(oldName, newName string) error
}
// Progress is a progress displaying entity, it allows progress bars & simple prints
+1 -1
View File
@@ -1,7 +1,7 @@
package aptly
// Version of aptly
const Version = "0.4.1"
const Version = "0.5.1"
// Enable debugging features?
const EnableDebug = false
+10 -12
View File
@@ -3,28 +3,26 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/aptly"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"github.com/smira/flag"
"os"
"time"
)
// ListPackagesRefList shows list of packages in PackageRefList
func ListPackagesRefList(reflist *debian.PackageRefList) (err error) {
func ListPackagesRefList(reflist *deb.PackageRefList) (err error) {
fmt.Printf("Packages:\n")
if reflist == nil {
return
}
packageCollection := debian.NewPackageCollection(context.database)
err = reflist.ForEach(func(key []byte) error {
p, err := packageCollection.ByKey(key)
if err != nil {
return err
p, err2 := context.CollectionFactory().PackageCollection().ByKey(key)
if err2 != nil {
return err2
}
fmt.Printf(" %s\n", p)
return nil
@@ -47,9 +45,9 @@ repositories, manage local repositories, filter them, merge,
upgrade individual packages, take snapshots and publish them
back as Debian repositories.
aptly goal is to establish repeatiblity and controlled changes
in package environment. aptly allows to fix set of packages in
repository, so that package installation and upgrade becomes
aptly's goal is to establish repeatability and controlled changes
in a package-centric environment. aptly allows to fix a set of packages
in a repository, so that package installation and upgrade becomes
deterministic. At the same time aptly allows to perform controlled,
fine-grained changes in repository contents to transition your
package environment to new version.`,
+207 -77
View File
@@ -2,14 +2,14 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/smira/aptly/aptly"
"github.com/smira/aptly/console"
"github.com/smira/aptly/database"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/aptly/files"
"github.com/smira/aptly/http"
"github.com/smira/aptly/utils"
"github.com/smira/flag"
"os"
"path/filepath"
"runtime"
@@ -18,13 +18,17 @@ import (
"time"
)
// Common context shared by all commands
var context struct {
// AptlyContext is a common context shared by all commands
type AptlyContext struct {
flags *flag.FlagSet
configLoaded bool
progress aptly.Progress
downloader aptly.Downloader
database database.Storage
packagePool aptly.PackagePool
publishedStorage aptly.PublishedStorage
collectionFactory *deb.CollectionFactory
dependencyOptions int
architecturesList []string
// Debug features
@@ -33,92 +37,161 @@ var context struct {
fileMemStats *os.File
}
// InitContext initializes context with default settings
func InitContext(cmd *commander.Command) error {
var err error
var context *AptlyContext
context.dependencyOptions = 0
if utils.Config.DepFollowSuggests || cmd.Flag.Lookup("dep-follow-suggests").Value.Get().(bool) {
context.dependencyOptions |= debian.DepFollowSuggests
}
if utils.Config.DepFollowRecommends || cmd.Flag.Lookup("dep-follow-recommends").Value.Get().(bool) {
context.dependencyOptions |= debian.DepFollowRecommends
}
if utils.Config.DepFollowAllVariants || cmd.Flag.Lookup("dep-follow-all-variants").Value.Get().(bool) {
context.dependencyOptions |= debian.DepFollowAllVariants
}
if utils.Config.DepFollowSource || cmd.Flag.Lookup("dep-follow-source").Value.Get().(bool) {
context.dependencyOptions |= debian.DepFollowSource
}
// FatalError is type for panicking to abort execution with non-zero
// exit code and print meaningful explanation
type FatalError struct {
ReturnCode int
Message string
}
context.architecturesList = utils.Config.Architectures
optionArchitectures := cmd.Flag.Lookup("architectures").Value.String()
if optionArchitectures != "" {
context.architecturesList = strings.Split(optionArchitectures, ",")
}
// Fatal panics and aborts execution with exit code 1
func Fatal(err error) {
panic(&FatalError{ReturnCode: 1, Message: err.Error()})
}
context.progress = console.NewProgress()
context.progress.Start()
// Config loads and returns current configuration
func (context *AptlyContext) Config() *utils.ConfigStructure {
if !context.configLoaded {
var err error
context.downloader = http.NewDownloader(utils.Config.DownloadConcurrency, context.progress)
configLocation := context.flags.Lookup("config").Value.String()
if configLocation != "" {
err = utils.LoadConfig(configLocation, &utils.Config)
context.database, err = database.OpenDB(filepath.Join(utils.Config.RootDir, "db"))
if err != nil {
return fmt.Errorf("can't open database: %s", err)
}
context.packagePool = files.NewPackagePool(utils.Config.RootDir)
context.publishedStorage = files.NewPublishedStorage(utils.Config.RootDir)
if aptly.EnableDebug {
cpuprofile := cmd.Flag.Lookup("cpuprofile").Value.String()
if cpuprofile != "" {
context.fileCPUProfile, err = os.Create(cpuprofile)
if err != nil {
return err
Fatal(err)
}
pprof.StartCPUProfile(context.fileCPUProfile)
}
memprofile := cmd.Flag.Lookup("memprofile").Value.String()
if memprofile != "" {
context.fileMemProfile, err = os.Create(memprofile)
if err != nil {
return err
}
}
memstats := cmd.Flag.Lookup("memstats").Value.String()
if memstats != "" {
interval := cmd.Flag.Lookup("meminterval").Value.Get().(time.Duration)
context.fileMemStats, err = os.Create(memstats)
if err != nil {
return err
} else {
configLocations := []string{
filepath.Join(os.Getenv("HOME"), ".aptly.conf"),
"/etc/aptly.conf",
}
context.fileMemStats.WriteString("# Time\tHeapSys\tHeapAlloc\tHeapIdle\tHeapReleased\n")
go func() {
var stats runtime.MemStats
start := time.Now().UnixNano()
for {
runtime.ReadMemStats(&stats)
if context.fileMemStats != nil {
context.fileMemStats.WriteString(fmt.Sprintf("%d\t%d\t%d\t%d\t%d\n",
(time.Now().UnixNano()-start)/1000000, stats.HeapSys, stats.HeapAlloc, stats.HeapIdle, stats.HeapReleased))
time.Sleep(interval)
} else {
break
}
for _, configLocation := range configLocations {
err = utils.LoadConfig(configLocation, &utils.Config)
if err == nil {
break
}
}()
if !os.IsNotExist(err) {
Fatal(fmt.Errorf("error loading config file %s: %s", configLocation, err))
}
}
if err != nil {
fmt.Printf("Config file not found, creating default config at %s\n\n", configLocations[0])
utils.SaveConfig(configLocations[0], &utils.Config)
}
}
context.configLoaded = true
}
return &utils.Config
}
// DependencyOptions calculates options related to dependecy handling
func (context *AptlyContext) DependencyOptions() int {
if context.dependencyOptions == -1 {
context.dependencyOptions = 0
if context.Config().DepFollowSuggests || context.flags.Lookup("dep-follow-suggests").Value.Get().(bool) {
context.dependencyOptions |= deb.DepFollowSuggests
}
if context.Config().DepFollowRecommends || context.flags.Lookup("dep-follow-recommends").Value.Get().(bool) {
context.dependencyOptions |= deb.DepFollowRecommends
}
if context.Config().DepFollowAllVariants || context.flags.Lookup("dep-follow-all-variants").Value.Get().(bool) {
context.dependencyOptions |= deb.DepFollowAllVariants
}
if context.Config().DepFollowSource || context.flags.Lookup("dep-follow-source").Value.Get().(bool) {
context.dependencyOptions |= deb.DepFollowSource
}
}
return nil
return context.dependencyOptions
}
// ArchitecturesList returns list of architectures fixed via command line or config
func (context *AptlyContext) ArchitecturesList() []string {
if context.architecturesList == nil {
context.architecturesList = context.Config().Architectures
optionArchitectures := context.flags.Lookup("architectures").Value.String()
if optionArchitectures != "" {
context.architecturesList = strings.Split(optionArchitectures, ",")
}
}
return context.architecturesList
}
// Progress creates or returns Progress object
func (context *AptlyContext) Progress() aptly.Progress {
if context.progress == nil {
context.progress = console.NewProgress()
context.progress.Start()
}
return context.progress
}
// Downloader returns instance of current downloader
func (context *AptlyContext) Downloader() aptly.Downloader {
if context.downloader == nil {
context.downloader = http.NewDownloader(context.Config().DownloadConcurrency, context.Progress())
}
return context.downloader
}
// DBPath builds path to database
func (context *AptlyContext) DBPath() string {
return filepath.Join(context.Config().RootDir, "db")
}
// Database opens and returns current instance of database
func (context *AptlyContext) Database() (database.Storage, error) {
if context.database == nil {
var err error
context.database, err = database.OpenDB(context.DBPath())
if err != nil {
return nil, fmt.Errorf("can't open database: %s", err)
}
}
return context.database, nil
}
// CollectionFactory builds factory producing all kinds of collections
func (context *AptlyContext) CollectionFactory() *deb.CollectionFactory {
if context.collectionFactory == nil {
db, err := context.Database()
if err != nil {
Fatal(err)
}
context.collectionFactory = deb.NewCollectionFactory(db)
}
return context.collectionFactory
}
// PackagePool returns instance of PackagePool
func (context *AptlyContext) PackagePool() aptly.PackagePool {
if context.packagePool == nil {
context.packagePool = files.NewPackagePool(context.Config().RootDir)
}
return context.packagePool
}
// PublishedStorage returns instance of PublishedStorage
func (context *AptlyContext) PublishedStorage() aptly.PublishedStorage {
if context.publishedStorage == nil {
context.publishedStorage = files.NewPublishedStorage(context.Config().RootDir)
}
return context.publishedStorage
}
// ShutdownContext shuts context down
@@ -149,3 +222,60 @@ func ShutdownContext() {
context.progress.Shutdown()
}
}
// InitContext initializes context with default settings
func InitContext(flags *flag.FlagSet) error {
var err error
context = &AptlyContext{flags: flags, dependencyOptions: -1}
if aptly.EnableDebug {
cpuprofile := flags.Lookup("cpuprofile").Value.String()
if cpuprofile != "" {
context.fileCPUProfile, err = os.Create(cpuprofile)
if err != nil {
return err
}
pprof.StartCPUProfile(context.fileCPUProfile)
}
memprofile := flags.Lookup("memprofile").Value.String()
if memprofile != "" {
context.fileMemProfile, err = os.Create(memprofile)
if err != nil {
return err
}
}
memstats := flags.Lookup("memstats").Value.String()
if memstats != "" {
interval := flags.Lookup("meminterval").Value.Get().(time.Duration)
context.fileMemStats, err = os.Create(memstats)
if err != nil {
return err
}
context.fileMemStats.WriteString("# Time\tHeapSys\tHeapAlloc\tHeapIdle\tHeapReleased\n")
go func() {
var stats runtime.MemStats
start := time.Now().UnixNano()
for {
runtime.ReadMemStats(&stats)
if context.fileMemStats != nil {
context.fileMemStats.WriteString(fmt.Sprintf("%d\t%d\t%d\t%d\t%d\n",
(time.Now().UnixNano()-start)/1000000, stats.HeapSys, stats.HeapAlloc, stats.HeapIdle, stats.HeapReleased))
time.Sleep(interval)
} else {
break
}
}
}()
}
}
return nil
}
+2 -3
View File
@@ -1,8 +1,7 @@
package cmd
import (
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/commander"
)
func makeCmdDb() *commander.Command {
@@ -11,7 +10,7 @@ func makeCmdDb() *commander.Command {
Short: "manage aptly's internal database and package pool",
Subcommands: []*commander.Command{
makeCmdDbCleanup(),
makeCmdDbRecover(),
},
Flag: *flag.NewFlagSet("aptly-db", flag.ExitOnError),
}
}
+42 -41
View File
@@ -2,10 +2,9 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/aptly/utils"
"github.com/smira/commander"
"sort"
)
@@ -19,12 +18,11 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
}
// collect information about references packages...
existingPackageRefs := debian.NewPackageRefList()
existingPackageRefs := deb.NewPackageRefList()
context.progress.Printf("Loading mirrors, local repos and snapshots...\n")
repoCollection := debian.NewRemoteRepoCollection(context.database)
err = repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
err := repoCollection.LoadComplete(repo)
context.Progress().Printf("Loading mirrors, local repos and snapshots...\n")
err = context.CollectionFactory().RemoteRepoCollection().ForEach(func(repo *deb.RemoteRepo) error {
err := context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
if err != nil {
return err
}
@@ -37,9 +35,8 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
return err
}
localRepoCollection := debian.NewLocalRepoCollection(context.database)
err = localRepoCollection.ForEach(func(repo *debian.LocalRepo) error {
err := localRepoCollection.LoadComplete(repo)
err = context.CollectionFactory().LocalRepoCollection().ForEach(func(repo *deb.LocalRepo) error {
err := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if err != nil {
return err
}
@@ -52,9 +49,8 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
return err
}
snapshotCollection := debian.NewSnapshotCollection(context.database)
err = snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
err := snapshotCollection.LoadComplete(snapshot)
err = context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
err := context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
if err != nil {
return err
}
@@ -66,44 +62,45 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
}
// ... and compare it to the list of all packages
context.progress.Printf("Loading list of all packages...\n")
packageCollection := debian.NewPackageCollection(context.database)
allPackageRefs := packageCollection.AllPackageRefs()
context.Progress().Printf("Loading list of all packages...\n")
allPackageRefs := context.CollectionFactory().PackageCollection().AllPackageRefs()
toDelete := allPackageRefs.Substract(existingPackageRefs)
// delete packages that are no longer referenced
context.progress.Printf("Deleting unreferenced packages (%d)...\n", toDelete.Len())
context.Progress().Printf("Deleting unreferenced packages (%d)...\n", toDelete.Len())
context.database.StartBatch()
// database can't err as collection factory already constructed
db, _ := context.Database()
db.StartBatch()
err = toDelete.ForEach(func(ref []byte) error {
return packageCollection.DeleteByKey(ref)
return context.CollectionFactory().PackageCollection().DeleteByKey(ref)
})
if err != nil {
return err
}
err = context.database.FinishBatch()
err = db.FinishBatch()
if err != nil {
return fmt.Errorf("unable to write to DB: %s", err)
}
// now, build a list of files that should be present in Repository (package pool)
context.progress.Printf("Building list of files referenced by packages...\n")
context.Progress().Printf("Building list of files referenced by packages...\n")
referencedFiles := make([]string, 0, existingPackageRefs.Len())
context.progress.InitBar(int64(existingPackageRefs.Len()), false)
context.Progress().InitBar(int64(existingPackageRefs.Len()), false)
err = existingPackageRefs.ForEach(func(key []byte) error {
pkg, err := packageCollection.ByKey(key)
if err != nil {
return err
pkg, err2 := context.CollectionFactory().PackageCollection().ByKey(key)
if err2 != nil {
return err2
}
paths, err := pkg.FilepathList(context.packagePool)
if err != nil {
return err
paths, err2 := pkg.FilepathList(context.PackagePool())
if err2 != nil {
return err2
}
referencedFiles = append(referencedFiles, paths...)
context.progress.AddBar(1)
context.Progress().AddBar(1)
return nil
})
@@ -112,11 +109,11 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
}
sort.Strings(referencedFiles)
context.progress.ShutdownBar()
context.Progress().ShutdownBar()
// build a list of files in the package pool
context.progress.Printf("Building list of files in package pool...\n")
existingFiles, err := context.packagePool.FilepathList(context.progress)
context.Progress().Printf("Building list of files in package pool...\n")
existingFiles, err := context.PackagePool().FilepathList(context.Progress())
if err != nil {
return fmt.Errorf("unable to collect file paths: %s", err)
}
@@ -125,24 +122,29 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
filesToDelete := utils.StrSlicesSubstract(existingFiles, referencedFiles)
// delete files that are no longer referenced
context.progress.Printf("Deleting unreferenced files (%d)...\n", len(filesToDelete))
context.Progress().Printf("Deleting unreferenced files (%d)...\n", len(filesToDelete))
if len(filesToDelete) > 0 {
context.progress.InitBar(int64(len(filesToDelete)), false)
totalSize := int64(0)
context.Progress().InitBar(int64(len(filesToDelete)), false)
var size, totalSize int64
for _, file := range filesToDelete {
size, err := context.packagePool.Remove(file)
size, err = context.PackagePool().Remove(file)
if err != nil {
return err
}
context.progress.AddBar(1)
context.Progress().AddBar(1)
totalSize += size
}
context.progress.ShutdownBar()
context.Progress().ShutdownBar()
context.progress.Printf("Disk space freed: %.2f GiB...\n", float64(totalSize)/1024.0/1024.0/1024.0)
context.Progress().Printf("Disk space freed: %s...\n", utils.HumanBytes(totalSize))
}
context.Progress().Printf("Compacting database...\n")
err = db.CompactDB()
return err
}
@@ -159,7 +161,6 @@ Example:
$ aptly db cleanup
`,
Flag: *flag.NewFlagSet("aptly-db-cleanup", flag.ExitOnError),
}
return cmd
+39
View File
@@ -0,0 +1,39 @@
package cmd
import (
"github.com/smira/aptly/database"
"github.com/smira/commander"
)
// aptly db recover
func aptlyDbRecover(cmd *commander.Command, args []string) error {
var err error
if len(args) != 0 {
cmd.Usage()
return err
}
context.Progress().Printf("Recovering database...\n")
err = database.RecoverDB(context.DBPath())
return err
}
func makeCmdDbRecover() *commander.Command {
cmd := &commander.Command{
Run: aptlyDbRecover,
UsageLine: "recover",
Short: "recover DB after crash",
Long: `
Database recover does its' best to recover the database after a crash.
It is recommended to backup the DB before running recover.
Example:
$ aptly db recover
`,
}
return cmd
}
+13 -23
View File
@@ -4,9 +4,8 @@ import (
"bytes"
"code.google.com/p/gographviz"
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"io"
"io/ioutil"
"os"
@@ -29,10 +28,8 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
fmt.Printf("Loading mirrors...\n")
repoCollection := debian.NewRemoteRepoCollection(context.database)
err = repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
err := repoCollection.LoadComplete(repo)
err = context.CollectionFactory().RemoteRepoCollection().ForEach(func(repo *deb.RemoteRepo) error {
err := context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
if err != nil {
return err
}
@@ -55,10 +52,8 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
fmt.Printf("Loading local repos...\n")
localRepoCollection := debian.NewLocalRepoCollection(context.database)
err = localRepoCollection.ForEach(func(repo *debian.LocalRepo) error {
err := localRepoCollection.LoadComplete(repo)
err = context.CollectionFactory().LocalRepoCollection().ForEach(func(repo *deb.LocalRepo) error {
err := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if err != nil {
return err
}
@@ -80,15 +75,13 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
fmt.Printf("Loading snapshots...\n")
snapshotCollection := debian.NewSnapshotCollection(context.database)
snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
existingNodes[snapshot.UUID] = true
return nil
})
err = snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
err := snapshotCollection.LoadComplete(snapshot)
err = context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
err := context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
if err != nil {
return err
}
@@ -122,9 +115,7 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
fmt.Printf("Loading published repos...\n")
publishedCollection := debian.NewPublishedRepoCollection(context.database)
publishedCollection.ForEach(func(repo *debian.PublishedRepo) error {
context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error {
graph.AddNode("aptly", graphvizEscape(repo.UUID), map[string]string{
"shape": "Mrecord",
"style": "filled",
@@ -132,9 +123,9 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
"label": graphvizEscape(fmt.Sprintf("{Published %s/%s|comp: %s|arch: %s}", repo.Prefix, repo.Distribution, repo.Component, strings.Join(repo.Architectures, ", "))),
})
_, exists := existingNodes[repo.SnapshotUUID]
_, exists := existingNodes[repo.SourceUUID]
if exists {
graph.AddEdge(graphvizEscape(repo.SnapshotUUID), "", graphvizEscape(repo.UUID), "", true, nil)
graph.AddEdge(graphvizEscape(repo.SourceUUID), "", graphvizEscape(repo.UUID), "", true, nil)
}
return nil
@@ -198,13 +189,12 @@ func makeCmdGraph() *commander.Command {
Long: `
Command graph displays relationship between mirrors, local repositories,
snapshots and published repositories using graphviz package to render
graph as image.
graph as an image.
Example:
$ aptly graph
`,
Flag: *flag.NewFlagSet("aptly-graph", flag.ExitOnError),
}
return cmd
+7 -8
View File
@@ -1,19 +1,21 @@
package cmd
import (
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/utils"
"github.com/smira/commander"
"github.com/smira/flag"
"strings"
)
func getVerifier(cmd *commander.Command) (utils.Verifier, error) {
if utils.Config.GpgDisableVerify || cmd.Flag.Lookup("ignore-signatures").Value.Get().(bool) {
func getVerifier(flags *flag.FlagSet) (utils.Verifier, error) {
if context.Config().GpgDisableVerify || flags.Lookup("ignore-signatures").Value.Get().(bool) {
return nil, nil
}
keyRings := flags.Lookup("keyring").Value.Get().([]string)
verifier := &utils.GpgVerifier{}
for _, keyRing := range keyRings.keyRings {
for _, keyRing := range keyRings {
verifier.AddKeyring(keyRing)
}
@@ -42,8 +44,6 @@ func (k *keyRingsFlag) String() string {
return strings.Join(k.keyRings, ",")
}
var keyRings = keyRingsFlag{}
func makeCmdMirror() *commander.Command {
return &commander.Command{
UsageLine: "mirror",
@@ -55,6 +55,5 @@ func makeCmdMirror() *commander.Command {
makeCmdMirrorDrop(),
makeCmdMirrorUpdate(),
},
Flag: *flag.NewFlagSet("aptly-mirror", flag.ExitOnError),
}
}
+12 -14
View File
@@ -2,10 +2,9 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/utils"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"github.com/smira/flag"
"strings"
)
@@ -16,7 +15,7 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error {
return err
}
downloadSources := utils.Config.DownloadSourcePackages || cmd.Flag.Lookup("with-sources").Value.Get().(bool)
downloadSources := context.Config().DownloadSourcePackages || context.flags.Lookup("with-sources").Value.Get().(bool)
var (
mirrorName, archiveURL, distribution string
@@ -25,7 +24,7 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error {
mirrorName = args[0]
if len(args) == 2 {
archiveURL, distribution, components, err = debian.ParsePPA(args[1])
archiveURL, distribution, components, err = deb.ParsePPA(args[1], context.Config())
if err != nil {
return err
}
@@ -33,24 +32,22 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error {
archiveURL, distribution, components = args[1], args[2], args[3:]
}
repo, err := debian.NewRemoteRepo(mirrorName, archiveURL, distribution, components, context.architecturesList, downloadSources)
repo, err := deb.NewRemoteRepo(mirrorName, archiveURL, distribution, components, context.ArchitecturesList(), downloadSources)
if err != nil {
return fmt.Errorf("unable to create mirror: %s", err)
}
verifier, err := getVerifier(cmd)
verifier, err := getVerifier(context.flags)
if err != nil {
return fmt.Errorf("unable to initialize GPG verifier: %s", err)
}
err = repo.Fetch(context.downloader, verifier)
err = repo.Fetch(context.Downloader(), verifier)
if err != nil {
return fmt.Errorf("unable to fetch mirror: %s", err)
}
repoCollection := debian.NewRemoteRepoCollection(context.database)
err = repoCollection.Add(repo)
err = context.CollectionFactory().RemoteRepoCollection().Add(repo)
if err != nil {
return fmt.Errorf("unable to add mirror: %s", err)
}
@@ -66,7 +63,8 @@ func makeCmdMirrorCreate() *commander.Command {
Short: "create new mirror",
Long: `
Creates mirror <name> of remote repository, aptly supports both regular and flat Debian repositories exported
via HTTP. aptly would try download Release file from remote repository and verify its signature.
via HTTP. aptly would try download Release file from remote repository and verify its' signature. Command
line format resembles apt utlitily sources.list(5).
PPA urls could specified in short format:
@@ -81,7 +79,7 @@ Example:
cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures")
cmd.Flag.Bool("with-sources", false, "download source packages in addition to binary packages")
cmd.Flag.Var(&keyRings, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)")
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)")
return cmd
}
+7 -10
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlyMirrorDrop(cmd *commander.Command, args []string) error {
@@ -16,16 +15,14 @@ func aptlyMirrorDrop(cmd *commander.Command, args []string) error {
name := args[0]
repoCollection := debian.NewRemoteRepoCollection(context.database)
repo, err := repoCollection.ByName(name)
repo, err := context.CollectionFactory().RemoteRepoCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to drop: %s", err)
}
force := cmd.Flag.Lookup("force").Value.Get().(bool)
force := context.flags.Lookup("force").Value.Get().(bool)
if !force {
snapshotCollection := debian.NewSnapshotCollection(context.database)
snapshots := snapshotCollection.ByRemoteRepoSource(repo)
snapshots := context.CollectionFactory().SnapshotCollection().ByRemoteRepoSource(repo)
if len(snapshots) > 0 {
fmt.Printf("Mirror `%s` was used to create following snapshots:\n", repo.Name)
@@ -37,7 +34,7 @@ func aptlyMirrorDrop(cmd *commander.Command, args []string) error {
}
}
err = repoCollection.Drop(repo)
err = context.CollectionFactory().RemoteRepoCollection().Drop(repo)
if err != nil {
return fmt.Errorf("unable to drop: %s", err)
}
@@ -54,7 +51,7 @@ func makeCmdMirrorDrop() *commander.Command {
Short: "delete mirror",
Long: `
Drop deletes information about remote repository mirror <name>. Package data is not deleted
(it could be still used by other mirrors or snapshots). If mirror is used as source
(since it could still be used by other mirrors or snapshots). If mirror is used as source
to create a snapshot, aptly would refuse to delete such mirror, use flag -force to override.
Example:
+30 -19
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"sort"
)
@@ -15,26 +14,37 @@ func aptlyMirrorList(cmd *commander.Command, args []string) error {
return err
}
repoCollection := debian.NewRemoteRepoCollection(context.database)
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
if repoCollection.Len() > 0 {
fmt.Printf("List of mirrors:\n")
repos := make([]string, repoCollection.Len())
i := 0
repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
repos := make([]string, context.CollectionFactory().RemoteRepoCollection().Len())
i := 0
context.CollectionFactory().RemoteRepoCollection().ForEach(func(repo *deb.RemoteRepo) error {
if raw {
repos[i] = repo.Name
} else {
repos[i] = repo.String()
i++
return nil
})
sort.Strings(repos)
for _, repo := range repos {
fmt.Printf(" * %s\n", repo)
}
i++
return nil
})
fmt.Printf("\nTo get more information about mirror, run `aptly mirror show <name>`.\n")
sort.Strings(repos)
if raw {
for _, repo := range repos {
fmt.Printf("%s\n", repo)
}
} else {
fmt.Printf("No mirrors found, create one with `aptly mirror create ...`.\n")
if len(repos) > 0 {
fmt.Printf("List of mirrors:\n")
for _, repo := range repos {
fmt.Printf(" * %s\n", repo)
}
fmt.Printf("\nTo get more information about mirror, run `aptly mirror show <name>`.\n")
} else {
fmt.Printf("No mirrors found, create one with `aptly mirror create ...`.\n")
}
}
return err
}
@@ -51,8 +61,9 @@ Example:
$ aptly mirror list
`,
Flag: *flag.NewFlagSet("aptly-mirror-list", flag.ExitOnError),
}
cmd.Flag.Bool("raw", false, "display list in machine-readable format")
return cmd
}
+6 -8
View File
@@ -2,10 +2,9 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/utils"
"github.com/smira/commander"
"github.com/smira/flag"
"strings"
)
@@ -18,13 +17,12 @@ func aptlyMirrorShow(cmd *commander.Command, args []string) error {
name := args[0]
repoCollection := debian.NewRemoteRepoCollection(context.database)
repo, err := repoCollection.ByName(name)
repo, err := context.CollectionFactory().RemoteRepoCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to show: %s", err)
}
err = repoCollection.LoadComplete(repo)
err = context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
if err != nil {
return fmt.Errorf("unable to show: %s", err)
}
@@ -51,7 +49,7 @@ func aptlyMirrorShow(cmd *commander.Command, args []string) error {
fmt.Printf("%s: %s\n", k, repo.Meta[k])
}
withPackages := cmd.Flag.Lookup("with-packages").Value.Get().(bool)
withPackages := context.flags.Lookup("with-packages").Value.Get().(bool)
if withPackages {
if repo.LastDownloadDate.IsZero() {
fmt.Printf("Unable to show package list, mirror hasn't been downloaded yet.\n")
@@ -69,7 +67,7 @@ func makeCmdMirrorShow() *commander.Command {
UsageLine: "show <name>",
Short: "show details about mirror",
Long: `
Shows detailed information about mirror.
Shows detailed information about the mirror.
Example:
+13 -17
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
@@ -16,42 +15,39 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
name := args[0]
repoCollection := debian.NewRemoteRepoCollection(context.database)
repo, err := repoCollection.ByName(name)
repo, err := context.CollectionFactory().RemoteRepoCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
err = repoCollection.LoadComplete(repo)
err = context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
ignoreMismatch := cmd.Flag.Lookup("ignore-checksums").Value.Get().(bool)
ignoreMismatch := context.flags.Lookup("ignore-checksums").Value.Get().(bool)
verifier, err := getVerifier(cmd)
verifier, err := getVerifier(context.flags)
if err != nil {
return fmt.Errorf("unable to initialize GPG verifier: %s", err)
}
err = repo.Fetch(context.downloader, verifier)
err = repo.Fetch(context.Downloader(), verifier)
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
packageCollection := debian.NewPackageCollection(context.database)
err = repo.Download(context.progress, context.downloader, packageCollection, context.packagePool, ignoreMismatch)
err = repo.Download(context.Progress(), context.Downloader(), context.CollectionFactory(), context.PackagePool(), ignoreMismatch)
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
err = repoCollection.Update(repo)
err = context.CollectionFactory().RemoteRepoCollection().Update(repo)
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
context.progress.Printf("\nMirror `%s` has been successfully updated.\n", repo.Name)
context.Progress().Printf("\nMirror `%s` has been successfully updated.\n", repo.Name)
return err
}
@@ -62,8 +58,8 @@ func makeCmdMirrorUpdate() *commander.Command {
Short: "update mirror",
Long: `
Updates remote mirror (downloads package files and meta information). When mirror is created,
this command should be run for the first time to fetch mirror contents. This command could be
run many times to get updated repository contents. If interrupted, command could be restarted safely.
this command should be run for the first time to fetch mirror contents. This command can be
run multiple times to get updated repository contents. If interrupted, command can be safely restarted.
Example:
@@ -74,7 +70,7 @@ Example:
cmd.Flag.Bool("ignore-checksums", false, "ignore checksum mismatches while downloading package files and metadata")
cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures")
cmd.Flag.Var(&keyRings, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)")
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)")
return cmd
}
+11 -9
View File
@@ -1,19 +1,19 @@
package cmd
import (
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/utils"
"github.com/smira/commander"
"github.com/smira/flag"
)
func getSigner(cmd *commander.Command) (utils.Signer, error) {
if cmd.Flag.Lookup("skip-signing").Value.Get().(bool) || utils.Config.GpgDisableSign {
func getSigner(flags *flag.FlagSet) (utils.Signer, error) {
if flags.Lookup("skip-signing").Value.Get().(bool) || context.Config().GpgDisableSign {
return nil, nil
}
signer := &utils.GpgSigner{}
signer.SetKey(cmd.Flag.Lookup("gpg-key").Value.String())
signer.SetKeyRing(cmd.Flag.Lookup("keyring").Value.String(), cmd.Flag.Lookup("secret-keyring").Value.String())
signer.SetKey(flags.Lookup("gpg-key").Value.String())
signer.SetKeyRing(flags.Lookup("keyring").Value.String(), flags.Lookup("secret-keyring").Value.String())
err := signer.Init()
if err != nil {
@@ -29,10 +29,12 @@ func makeCmdPublish() *commander.Command {
UsageLine: "publish",
Short: "manage published repositories",
Subcommands: []*commander.Command{
makeCmdPublishSnapshot(),
makeCmdPublishList(),
makeCmdPublishDrop(),
makeCmdPublishList(),
makeCmdPublishRepo(),
makeCmdPublishSnapshot(),
makeCmdPublishSwitch(),
makeCmdPublishUpdate(),
},
Flag: *flag.NewFlagSet("aptly-publish", flag.ExitOnError),
}
}
+4 -8
View File
@@ -2,9 +2,7 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/commander"
)
func aptlyPublishDrop(cmd *commander.Command, args []string) error {
@@ -21,14 +19,13 @@ func aptlyPublishDrop(cmd *commander.Command, args []string) error {
prefix = args[1]
}
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
err = publishedCollecton.Remove(context.publishedStorage, prefix, distribution)
err = context.CollectionFactory().PublishedRepoCollection().Remove(context.PublishedStorage(), prefix, distribution,
context.CollectionFactory(), context.Progress())
if err != nil {
return fmt.Errorf("unable to remove: %s", err)
}
fmt.Printf("\nPublished repositroy has been removed successfully.\n")
context.Progress().Printf("\nPublished repository has been removed successfully.\n")
return err
}
@@ -46,7 +43,6 @@ Example:
$ aptly publish drop wheezy
`,
Flag: *flag.NewFlagSet("aptly-publish-drop", flag.ExitOnError),
}
return cmd
+27 -18
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"sort"
)
@@ -15,23 +14,21 @@ func aptlyPublishList(cmd *commander.Command, args []string) error {
return err
}
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
snapshotCollection := debian.NewSnapshotCollection(context.database)
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
if publishedCollecton.Len() == 0 {
fmt.Printf("No snapshots have been published. Publish a snapshot by running `aptly publish snapshot ...`.\n")
return err
}
published := make([]string, 0, context.CollectionFactory().PublishedRepoCollection().Len())
published := make([]string, 0, publishedCollecton.Len())
err = publishedCollecton.ForEach(func(repo *debian.PublishedRepo) error {
err := publishedCollecton.LoadComplete(repo, snapshotCollection)
err = context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error {
err := context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
if err != nil {
return err
}
published = append(published, repo.String())
if raw {
published = append(published, fmt.Sprintf("%s %s", repo.Prefix, repo.Distribution))
} else {
published = append(published, repo.String())
}
return nil
})
@@ -41,10 +38,21 @@ func aptlyPublishList(cmd *commander.Command, args []string) error {
sort.Strings(published)
fmt.Printf("Published repositories:\n")
if raw {
for _, info := range published {
fmt.Printf("%s\n", info)
}
} else {
if len(published) == 0 {
fmt.Printf("No snapshots/local repos have been published. Publish a snapshot by running `aptly publish snapshot ...`.\n")
return err
}
for _, description := range published {
fmt.Printf(" * %s\n", description)
fmt.Printf("Published repositories:\n")
for _, description := range published {
fmt.Printf(" * %s\n", description)
}
}
return err
@@ -62,8 +70,9 @@ Example:
$ aptly publish list
`,
Flag: *flag.NewFlagSet("aptly-publish-list", flag.ExitOnError),
}
cmd.Flag.Bool("raw", false, "display list in machine-readable format")
return cmd
}
+39
View File
@@ -0,0 +1,39 @@
package cmd
import (
"github.com/smira/commander"
"github.com/smira/flag"
)
func makeCmdPublishRepo() *commander.Command {
cmd := &commander.Command{
Run: aptlyPublishSnapshotOrRepo,
UsageLine: "repo <name> [<prefix>]",
Short: "publish local repository",
Long: `
Command publishes current state of local repository ready to be consumed
by apt tools. Published repostiories appear under rootDir/public directory.
Valid GPG key is required for publishing.
It is not recommended to publish local repositories directly unless the
repository is for testing purposes and changes happen frequently. For
production usage please take snapshot of repository and publish it
using publish snapshot command.
Example:
$ aptly publish repo testing
`,
Flag: *flag.NewFlagSet("aptly-publish-repo", flag.ExitOnError),
}
cmd.Flag.String("distribution", "", "distribution name to publish")
cmd.Flag.String("component", "", "component name to publish")
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG")
cmd.Flag.String("origin", "", "origin name to publish")
cmd.Flag.String("label", "", "label to publish")
return cmd
}
+67 -62
View File
@@ -2,14 +2,14 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/aptly/utils"
"github.com/smira/commander"
"github.com/smira/flag"
"strings"
)
func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
var err error
if len(args) < 1 || len(args) > 2 {
cmd.Usage()
@@ -25,98 +25,101 @@ func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
prefix = ""
}
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
var (
source interface{}
message string
)
snapshotCollection := debian.NewSnapshotCollection(context.database)
snapshot, err := snapshotCollection.ByName(name)
if cmd.Name() == "snapshot" {
var snapshot *deb.Snapshot
snapshot, err = context.CollectionFactory().SnapshotCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
source = snapshot
message = fmt.Sprintf("Snapshot %s", snapshot.Name)
} else if cmd.Name() == "repo" {
var localRepo *deb.LocalRepo
localRepo, err = context.CollectionFactory().LocalRepoCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(localRepo)
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
source = localRepo
message = fmt.Sprintf("Local repo %s", localRepo.Name)
} else {
panic("unknown command")
}
component := context.flags.Lookup("component").Value.String()
distribution := context.flags.Lookup("distribution").Value.String()
published, err := deb.NewPublishedRepo(prefix, distribution, component, context.ArchitecturesList(), source, context.CollectionFactory())
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
published.Origin = cmd.Flag.Lookup("origin").Value.String()
published.Label = cmd.Flag.Lookup("label").Value.String()
err = snapshotCollection.LoadComplete(snapshot)
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
var sourceRepo *debian.RemoteRepo
if snapshot.SourceKind == "repo" && len(snapshot.SourceIDs) == 1 {
repoCollection := debian.NewRemoteRepoCollection(context.database)
sourceRepo, _ = repoCollection.ByUUID(snapshot.SourceIDs[0])
}
component := cmd.Flag.Lookup("component").Value.String()
if component == "" {
if sourceRepo != nil && len(sourceRepo.Components) == 1 {
component = sourceRepo.Components[0]
} else {
component = "main"
}
}
distribution := cmd.Flag.Lookup("distribution").Value.String()
if distribution == "" {
if sourceRepo != nil {
distribution = sourceRepo.Distribution
}
if distribution == "" {
return fmt.Errorf("unable to guess distribution name, please specify explicitly")
}
}
published, err := debian.NewPublishedRepo(prefix, distribution, component, context.architecturesList, snapshot)
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
duplicate := publishedCollecton.CheckDuplicate(published)
duplicate := context.CollectionFactory().PublishedRepoCollection().CheckDuplicate(published)
if duplicate != nil {
publishedCollecton.LoadComplete(duplicate, snapshotCollection)
context.CollectionFactory().PublishedRepoCollection().LoadComplete(duplicate, context.CollectionFactory())
return fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
}
signer, err := getSigner(cmd)
signer, err := getSigner(context.flags)
if err != nil {
return fmt.Errorf("unable to initialize GPG signer: %s", err)
}
packageCollection := debian.NewPackageCollection(context.database)
err = published.Publish(context.packagePool, context.publishedStorage, packageCollection, signer, context.progress)
err = published.Publish(context.PackagePool(), context.PublishedStorage(), context.CollectionFactory(), signer, context.Progress())
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
err = publishedCollecton.Add(published)
err = context.CollectionFactory().PublishedRepoCollection().Add(published)
if err != nil {
return fmt.Errorf("unable to save to DB: %s", err)
}
if prefix != "" && !strings.HasSuffix(prefix, "/") {
prefix, component, distribution = published.Prefix, published.Component, published.Distribution
if prefix == "." {
prefix = ""
} else if !strings.HasSuffix(prefix, "/") {
prefix += "/"
}
context.progress.Printf("\nSnapshot %s has been successfully published.\nPlease setup your webserver to serve directory '%s' with autoindexing.\n",
snapshot.Name, context.publishedStorage.PublicPath())
context.progress.Printf("Now you can add following line to apt sources:\n")
context.progress.Printf(" deb http://your-server/%s %s %s\n", prefix, distribution, component)
context.Progress().Printf("\n%s has been successfully published.\nPlease setup your webserver to serve directory '%s' with autoindexing.\n",
message, context.PublishedStorage().PublicPath())
context.Progress().Printf("Now you can add following line to apt sources:\n")
context.Progress().Printf(" deb http://your-server/%s %s %s\n", prefix, distribution, component)
if utils.StrSliceHasItem(published.Architectures, "source") {
context.progress.Printf(" deb-src http://your-server/%s %s %s\n", prefix, distribution, component)
context.Progress().Printf(" deb-src http://your-server/%s %s %s\n", prefix, distribution, component)
}
context.progress.Printf("Don't forget to add your GPG key to apt with apt-key.\n")
context.progress.Printf("\nYou can also use `aptly serve` to publish your repositories over HTTP quickly.\n")
context.Progress().Printf("Don't forget to add your GPG key to apt with apt-key.\n")
context.Progress().Printf("\nYou can also use `aptly serve` to publish your repositories over HTTP quickly.\n")
return err
}
func makeCmdPublishSnapshot() *commander.Command {
cmd := &commander.Command{
Run: aptlyPublishSnapshot,
Run: aptlyPublishSnapshotOrRepo,
UsageLine: "snapshot <name> [<prefix>]",
Short: "publish snapshot",
Long: `
Command publish publishes snapshot as Debian repository ready to be consumed
Command publishes snapshot as Debian repository ready to be consumed
by apt tools. Published repostiories appear under rootDir/public directory.
Valid GPG key is required for publishing.
@@ -129,9 +132,11 @@ Example:
cmd.Flag.String("distribution", "", "distribution name to publish")
cmd.Flag.String("component", "", "component name to publish")
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
cmd.Flag.String("keyring", "", "GPG keyring to use (instead of default)")
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG")
cmd.Flag.String("origin", "", "origin name to publish")
cmd.Flag.String("label", "", "label to publish")
return cmd
}
+107
View File
@@ -0,0 +1,107 @@
package cmd
import (
"fmt"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlyPublishSwitch(cmd *commander.Command, args []string) error {
var err error
if len(args) < 2 || len(args) > 3 {
cmd.Usage()
return err
}
distribution := args[0]
prefix := "."
var (
name string
snapshot *deb.Snapshot
)
if len(args) == 3 {
prefix = args[1]
name = args[2]
} else {
name = args[1]
}
snapshot, err = context.CollectionFactory().SnapshotCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to switch: %s", err)
}
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
if err != nil {
return fmt.Errorf("unable to switch: %s", err)
}
var published *deb.PublishedRepo
published, err = context.CollectionFactory().PublishedRepoCollection().ByPrefixDistribution(prefix, distribution)
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
if published.SourceKind != "snapshot" {
return fmt.Errorf("unable to update: not a snapshot publish")
}
err = context.CollectionFactory().PublishedRepoCollection().LoadComplete(published, context.CollectionFactory())
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
published.UpdateSnapshot(snapshot)
signer, err := getSigner(context.flags)
if err != nil {
return fmt.Errorf("unable to initialize GPG signer: %s", err)
}
err = published.Publish(context.PackagePool(), context.PublishedStorage(), context.CollectionFactory(), signer, context.Progress())
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
err = context.CollectionFactory().PublishedRepoCollection().Update(published)
if err != nil {
return fmt.Errorf("unable to save to DB: %s", err)
}
err = context.CollectionFactory().PublishedRepoCollection().CleanupPrefixComponentFiles(published.Prefix, published.Component,
context.PublishedStorage(), context.CollectionFactory(), context.Progress())
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
context.Progress().Printf("\nPublish for snapshot %s has been successfully switched to new snapshot.\n", published.String())
return err
}
func makeCmdPublishSwitch() *commander.Command {
cmd := &commander.Command{
Run: aptlyPublishSwitch,
UsageLine: "switch <distribution> [<prefix>] <new-snapshot>",
Short: "update published repository by switching to new snapshot",
Long: `
Command switches in-place published repository with new snapshot contents. All
publishing parameters are preserved (architecture list, distribution, component).
Example:
$ aptly publish update wheezy ppa wheezy-7.5
`,
Flag: *flag.NewFlagSet("aptly-publish-switch", flag.ExitOnError),
}
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG")
return cmd
}
+91
View File
@@ -0,0 +1,91 @@
package cmd
import (
"fmt"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlyPublishUpdate(cmd *commander.Command, args []string) error {
var err error
if len(args) < 1 || len(args) > 2 {
cmd.Usage()
return err
}
distribution := args[0]
prefix := "."
if len(args) == 2 {
prefix = args[1]
}
var published *deb.PublishedRepo
published, err = context.CollectionFactory().PublishedRepoCollection().ByPrefixDistribution(prefix, distribution)
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
if published.SourceKind != "local" {
return fmt.Errorf("unable to update: not a local repository publish")
}
err = context.CollectionFactory().PublishedRepoCollection().LoadComplete(published, context.CollectionFactory())
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
published.UpdateLocalRepo()
signer, err := getSigner(context.flags)
if err != nil {
return fmt.Errorf("unable to initialize GPG signer: %s", err)
}
err = published.Publish(context.PackagePool(), context.PublishedStorage(), context.CollectionFactory(), signer, context.Progress())
if err != nil {
return fmt.Errorf("unable to publish: %s", err)
}
err = context.CollectionFactory().PublishedRepoCollection().Update(published)
if err != nil {
return fmt.Errorf("unable to save to DB: %s", err)
}
err = context.CollectionFactory().PublishedRepoCollection().CleanupPrefixComponentFiles(published.Prefix, published.Component,
context.PublishedStorage(), context.CollectionFactory(), context.Progress())
if err != nil {
return fmt.Errorf("unable to update: %s", err)
}
context.Progress().Printf("\nPublish for local repo %s has been successfully updated.\n", published.String())
return err
}
func makeCmdPublishUpdate() *commander.Command {
cmd := &commander.Command{
Run: aptlyPublishUpdate,
UsageLine: "update <distribution> [<prefix>]",
Short: "update published local repository",
Long: `
Command re-publishes (updates) published local repository. <distribution>
and <prefix> should be occupied with local repository published
using command aptly publish repo. Update happens in-place with
minimum possible downtime for published repository.
Example:
$ aptly publish update wheezy ppa
`,
Flag: *flag.NewFlagSet("aptly-publish-update", flag.ExitOnError),
}
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "GPG keyring to use (instead of default)")
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG")
return cmd
}
+2 -3
View File
@@ -1,8 +1,7 @@
package cmd
import (
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/commander"
)
func makeCmdRepo() *commander.Command {
@@ -14,12 +13,12 @@ func makeCmdRepo() *commander.Command {
makeCmdRepoCopy(),
makeCmdRepoCreate(),
makeCmdRepoDrop(),
makeCmdRepoEdit(),
makeCmdRepoImport(),
makeCmdRepoList(),
makeCmdRepoMove(),
makeCmdRepoRemove(),
makeCmdRepoShow(),
},
Flag: *flag.NewFlagSet("aptly-repo", flag.ExitOnError),
}
}
+39 -41
View File
@@ -2,10 +2,10 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/aptly/utils"
"github.com/smira/commander"
"github.com/smira/flag"
"os"
"path/filepath"
"sort"
@@ -23,21 +23,19 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
verifier := &utils.GpgVerifier{}
localRepoCollection := debian.NewLocalRepoCollection(context.database)
repo, err := localRepoCollection.ByName(name)
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to add: %s", err)
}
err = localRepoCollection.LoadComplete(repo)
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if err != nil {
return fmt.Errorf("unable to add: %s", err)
}
context.progress.Printf("Loading packages...\n")
context.Progress().Printf("Loading packages...\n")
packageCollection := debian.NewPackageCollection(context.database)
list, err := debian.NewPackageListFromRefList(repo.RefList(), packageCollection, context.progress)
list, err := deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
if err != nil {
return fmt.Errorf("unable to load packages: %s", err)
}
@@ -45,15 +43,15 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
packageFiles := []string{}
for _, location := range args[1:] {
info, err := os.Stat(location)
if err != nil {
context.progress.ColoredPrintf("@y[!]@| @!Unable to process %s: %s@|", location, err)
info, err2 := os.Stat(location)
if err2 != nil {
context.Progress().ColoredPrintf("@y[!]@| @!Unable to process %s: %s@|", location, err2)
continue
}
if info.IsDir() {
err = filepath.Walk(location, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
err2 = filepath.Walk(location, func(path string, info os.FileInfo, err3 error) error {
if err3 != nil {
return err3
}
if info.IsDir() {
return nil
@@ -69,7 +67,7 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
if strings.HasSuffix(info.Name(), ".deb") || strings.HasSuffix(info.Name(), ".dsc") {
packageFiles = append(packageFiles, location)
} else {
context.progress.ColoredPrintf("@y[!]@| @!Unknwon file extenstion: %s@|", location)
context.Progress().ColoredPrintf("@y[!]@| @!Unknwon file extenstion: %s@|", location)
continue
}
}
@@ -80,46 +78,46 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
for _, file := range packageFiles {
var (
stanza debian.Stanza
err error
p *debian.Package
stanza deb.Stanza
p *deb.Package
)
candidateProcessedFiles := []string{}
isSourcePackage := strings.HasSuffix(file, ".dsc")
if isSourcePackage {
stanza, err = debian.GetControlFileFromDsc(file, verifier)
stanza, err = deb.GetControlFileFromDsc(file, verifier)
if err == nil {
stanza["Package"] = stanza["Source"]
delete(stanza, "Source")
p, err = debian.NewSourcePackageFromControlFile(stanza)
p, err = deb.NewSourcePackageFromControlFile(stanza)
}
} else {
stanza, err = debian.GetControlFileFromDeb(file)
p = debian.NewPackageFromControlFile(stanza)
stanza, err = deb.GetControlFileFromDeb(file)
p = deb.NewPackageFromControlFile(stanza)
}
if err != nil {
context.progress.ColoredPrintf("@y[!]@| @!Unable to read file %s: %s@|", file, err)
context.Progress().ColoredPrintf("@y[!]@| @!Unable to read file %s: %s@|", file, err)
continue
}
checksums, err := utils.ChecksumsForFile(file)
var checksums utils.ChecksumInfo
checksums, err = utils.ChecksumsForFile(file)
if err != nil {
return err
}
if isSourcePackage {
p.UpdateFiles(append(p.Files(), debian.PackageFile{Filename: filepath.Base(file), Checksums: checksums}))
p.UpdateFiles(append(p.Files(), deb.PackageFile{Filename: filepath.Base(file), Checksums: checksums}))
} else {
p.UpdateFiles([]debian.PackageFile{debian.PackageFile{Filename: filepath.Base(file), Checksums: checksums}})
p.UpdateFiles([]deb.PackageFile{deb.PackageFile{Filename: filepath.Base(file), Checksums: checksums}})
}
err = context.packagePool.Import(file, checksums.MD5)
err = context.PackagePool().Import(file, checksums.MD5)
if err != nil {
context.progress.ColoredPrintf("@y[!]@| @!Unable to import file %s into pool: %s@|", file, err)
context.Progress().ColoredPrintf("@y[!]@| @!Unable to import file %s into pool: %s@|", file, err)
continue
}
@@ -131,9 +129,9 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
continue
}
sourceFile := filepath.Join(filepath.Dir(file), filepath.Base(f.Filename))
err = context.packagePool.Import(sourceFile, f.Checksums.MD5)
err = context.PackagePool().Import(sourceFile, f.Checksums.MD5)
if err != nil {
context.progress.ColoredPrintf("@y[!]@| @!Unable to import file %s into pool: %s@|", sourceFile, err)
context.Progress().ColoredPrintf("@y[!]@| @!Unable to import file %s into pool: %s@|", sourceFile, err)
break
}
@@ -144,30 +142,30 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
continue
}
err = packageCollection.Update(p)
err = context.CollectionFactory().PackageCollection().Update(p)
if err != nil {
context.progress.ColoredPrintf("@y[!]@| @!Unable to save package %s: %s@|", p, err)
context.Progress().ColoredPrintf("@y[!]@| @!Unable to save package %s: %s@|", p, err)
continue
}
err = list.Add(p)
if err != nil {
context.progress.ColoredPrintf("@y[!]@| @!Unable to add package to repo %s: %s@|", p, err)
context.Progress().ColoredPrintf("@y[!]@| @!Unable to add package to repo %s: %s@|", p, err)
continue
}
context.progress.ColoredPrintf("@g[+]@| %s added@|", p)
context.Progress().ColoredPrintf("@g[+]@| %s added@|", p)
processedFiles = append(processedFiles, candidateProcessedFiles...)
}
repo.UpdateRefList(debian.NewPackageRefListFromPackageList(list))
repo.UpdateRefList(deb.NewPackageRefListFromPackageList(list))
err = localRepoCollection.Update(repo)
err = context.CollectionFactory().LocalRepoCollection().Update(repo)
if err != nil {
return fmt.Errorf("unable to save: %s", err)
}
if cmd.Flag.Lookup("remove-files").Value.Get().(bool) {
if context.flags.Lookup("remove-files").Value.Get().(bool) {
processedFiles = utils.StrSliceDeduplicate(processedFiles)
for _, file := range processedFiles {
@@ -189,9 +187,9 @@ func makeCmdRepoAdd() *commander.Command {
Long: `
Command adds packages to local repository from .deb (binary packages) and .dsc (source packages) files.
When importing from directory aptly would do recursive scan looking for all files matching *.deb or *.dsc
patterns. Every file discovered would be analyzed to extract metadata, package would be created and added
to database. Files would be imported to internal package pool. For source packages, all required files are
added as well automatically. Extra files for source package should be in the same directory as *.dsc file.
patterns. Every file discovered would be analyzed to extract metadata, package would then be created and added
to the database. Files would be imported to internal package pool. For source packages, all required files are
added automatically as well. Extra files for source package should be in the same directory as *.dsc file.
Example:
+2 -2
View File
@@ -1,8 +1,8 @@
package cmd
import (
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/commander"
"github.com/smira/flag"
)
func makeCmdRepoCopy() *commander.Command {
+9 -7
View File
@@ -2,9 +2,9 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlyRepoCreate(cmd *commander.Command, args []string) error {
@@ -14,11 +14,11 @@ func aptlyRepoCreate(cmd *commander.Command, args []string) error {
return err
}
repo := debian.NewLocalRepo(args[0], cmd.Flag.Lookup("comment").Value.String())
repo := deb.NewLocalRepo(args[0], context.flags.Lookup("comment").Value.String())
repo.DefaultDistribution = context.flags.Lookup("distribution").Value.String()
repo.DefaultComponent = context.flags.Lookup("component").Value.String()
localRepoCollection := debian.NewLocalRepoCollection(context.database)
err = localRepoCollection.Add(repo)
err = context.CollectionFactory().LocalRepoCollection().Add(repo)
if err != nil {
return fmt.Errorf("unable to add local repo: %s", err)
}
@@ -45,6 +45,8 @@ Example:
}
cmd.Flag.String("comment", "", "any text that would be used to described local repository")
cmd.Flag.String("distribution", "", "default distribution when publishing")
cmd.Flag.String("component", "main", "default component when publishing")
return cmd
}
+22 -11
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlyRepoDrop(cmd *commander.Command, args []string) error {
@@ -16,16 +15,28 @@ func aptlyRepoDrop(cmd *commander.Command, args []string) error {
name := args[0]
localRepoCollection := debian.NewLocalRepoCollection(context.database)
repo, err := localRepoCollection.ByName(name)
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to drop: %s", err)
}
force := cmd.Flag.Lookup("force").Value.Get().(bool)
published := context.CollectionFactory().PublishedRepoCollection().ByLocalRepo(repo)
if len(published) > 0 {
fmt.Printf("Local repo `%s` is published currently:\n", repo.Name)
for _, repo := range published {
err = context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
if err != nil {
return fmt.Errorf("unable to load published: %s", err)
}
fmt.Printf(" * %s\n", repo)
}
return fmt.Errorf("unable to drop: local repo is published")
}
force := context.flags.Lookup("force").Value.Get().(bool)
if !force {
snapshotCollection := debian.NewSnapshotCollection(context.database)
snapshots := snapshotCollection.ByLocalRepoSource(repo)
snapshots := context.CollectionFactory().SnapshotCollection().ByLocalRepoSource(repo)
if len(snapshots) > 0 {
fmt.Printf("Local repo `%s` was used to create following snapshots:\n", repo.Name)
@@ -37,7 +48,7 @@ func aptlyRepoDrop(cmd *commander.Command, args []string) error {
}
}
err = localRepoCollection.Drop(repo)
err = context.CollectionFactory().LocalRepoCollection().Drop(repo)
if err != nil {
return fmt.Errorf("unable to drop: %s", err)
}
@@ -53,8 +64,8 @@ func makeCmdRepoDrop() *commander.Command {
UsageLine: "drop <name>",
Short: "delete local repository",
Long: `
Drop deletes information about local repo. Package data is not deleted
(it could be still used by other mirrors or snapshots).
Drop information about deletions from local repo. Package data is not deleted
(since it could be still used by other mirrors or snapshots).
Example:
+68
View File
@@ -0,0 +1,68 @@
package cmd
import (
"fmt"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlyRepoEdit(cmd *commander.Command, args []string) error {
var err error
if len(args) != 1 {
cmd.Usage()
return err
}
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(args[0])
if err != nil {
return fmt.Errorf("unable to edit: %s", err)
}
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if err != nil {
return fmt.Errorf("unable to edit: %s", err)
}
if context.flags.Lookup("comment").Value.String() != "" {
repo.Comment = context.flags.Lookup("comment").Value.String()
}
if context.flags.Lookup("distribution").Value.String() != "" {
repo.DefaultDistribution = context.flags.Lookup("distribution").Value.String()
}
if context.flags.Lookup("component").Value.String() != "" {
repo.DefaultComponent = context.flags.Lookup("component").Value.String()
}
err = context.CollectionFactory().LocalRepoCollection().Update(repo)
if err != nil {
return fmt.Errorf("unable to edit: %s", err)
}
fmt.Printf("Local repo %s successfully updated.\n", repo)
return err
}
func makeCmdRepoEdit() *commander.Command {
cmd := &commander.Command{
Run: aptlyRepoEdit,
UsageLine: "edit <name>",
Short: "edit properties of local repository",
Long: `
Command edit allows to change metadata of local repository:
comment, default distribution and component.
Example:
$ aptly repo edit -distribution=wheezy testing
`,
Flag: *flag.NewFlagSet("aptly-repo-edit", flag.ExitOnError),
}
cmd.Flag.String("comment", "", "any text that would be used to described local repository")
cmd.Flag.String("distribution", "", "default distribution when publishing")
cmd.Flag.String("component", "", "default component when publishing")
return cmd
}
+2 -2
View File
@@ -1,8 +1,8 @@
package cmd
import (
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/commander"
"github.com/smira/flag"
)
func makeCmdRepoImport() *commander.Command {
+33 -21
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"sort"
)
@@ -15,32 +14,44 @@ func aptlyRepoList(cmd *commander.Command, args []string) error {
return err
}
localRepoCollection := debian.NewLocalRepoCollection(context.database)
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
if localRepoCollection.Len() > 0 {
fmt.Printf("List of mirrors:\n")
repos := make([]string, localRepoCollection.Len())
i := 0
localRepoCollection.ForEach(func(repo *debian.LocalRepo) error {
err := localRepoCollection.LoadComplete(repo)
repos := make([]string, context.CollectionFactory().LocalRepoCollection().Len())
i := 0
context.CollectionFactory().LocalRepoCollection().ForEach(func(repo *deb.LocalRepo) error {
if raw {
repos[i] = repo.Name
} else {
err := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if err != nil {
return err
}
repos[i] = fmt.Sprintf(" * %s (packages: %d)", repo.String(), repo.NumPackages())
i++
return nil
})
sort.Strings(repos)
for _, repo := range repos {
fmt.Println(repo)
}
i++
return nil
})
fmt.Printf("\nTo get more information about local repository, run `aptly repo show <name>`.\n")
sort.Strings(repos)
if raw {
for _, repo := range repos {
fmt.Printf("%s\n", repo)
}
} else {
fmt.Printf("No local repositories found, create one with `aptly repo create ...`.\n")
if len(repos) > 0 {
fmt.Printf("List of local repos:\n")
for _, repo := range repos {
fmt.Println(repo)
}
fmt.Printf("\nTo get more information about local repository, run `aptly repo show <name>`.\n")
} else {
fmt.Printf("No local repositories found, create one with `aptly repo create ...`.\n")
}
}
return err
}
@@ -50,14 +61,15 @@ func makeCmdRepoList() *commander.Command {
UsageLine: "list",
Short: "list local repositories",
Long: `
List shows full list of local package repositories.
List command shows full list of local package repositories.
Example:
$ aptly repo list
`,
Flag: *flag.NewFlagSet("aptly-repo-list", flag.ExitOnError),
}
cmd.Flag.Bool("raw", false, "display list in machine-readable format")
return cmd
}
+29 -32
View File
@@ -2,9 +2,9 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"github.com/smira/flag"
"sort"
)
@@ -17,25 +17,23 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
command := cmd.Name()
localRepoCollection := debian.NewLocalRepoCollection(context.database)
dstRepo, err := localRepoCollection.ByName(args[1])
dstRepo, err := context.CollectionFactory().LocalRepoCollection().ByName(args[1])
if err != nil {
return fmt.Errorf("unable to %s: %s", command, err)
}
err = localRepoCollection.LoadComplete(dstRepo)
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(dstRepo)
if err != nil {
return fmt.Errorf("unable to %s: %s", command, err)
}
var (
srcRefList *debian.PackageRefList
srcRepo *debian.LocalRepo
srcRefList *deb.PackageRefList
srcRepo *deb.LocalRepo
)
if command == "copy" || command == "move" {
srcRepo, err = localRepoCollection.ByName(args[0])
srcRepo, err = context.CollectionFactory().LocalRepoCollection().ByName(args[0])
if err != nil {
return fmt.Errorf("unable to %s: %s", command, err)
}
@@ -44,43 +42,42 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to %s: source and destination are the same", command)
}
err = localRepoCollection.LoadComplete(srcRepo)
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(srcRepo)
if err != nil {
return fmt.Errorf("unable to %s: %s", command, err)
}
srcRefList = srcRepo.RefList()
} else if command == "import" {
repoCollection := debian.NewRemoteRepoCollection(context.database)
var srcRemoteRepo *deb.RemoteRepo
srcRepo, err := repoCollection.ByName(args[0])
srcRemoteRepo, err = context.CollectionFactory().RemoteRepoCollection().ByName(args[0])
if err != nil {
return fmt.Errorf("unable to %s: %s", command, err)
}
err = repoCollection.LoadComplete(srcRepo)
err = context.CollectionFactory().RemoteRepoCollection().LoadComplete(srcRemoteRepo)
if err != nil {
return fmt.Errorf("unable to %s: %s", command, err)
}
if srcRepo.RefList() == nil {
if srcRemoteRepo.RefList() == nil {
return fmt.Errorf("unable to %s: mirror not updated", command)
}
srcRefList = srcRepo.RefList()
srcRefList = srcRemoteRepo.RefList()
} else {
panic("unexpected command")
}
context.progress.Printf("Loading packages...\n")
context.Progress().Printf("Loading packages...\n")
packageCollection := debian.NewPackageCollection(context.database)
dstList, err := debian.NewPackageListFromRefList(dstRepo.RefList(), packageCollection, context.progress)
dstList, err := deb.NewPackageListFromRefList(dstRepo.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
if err != nil {
return fmt.Errorf("unable to load packages: %s", err)
}
srcList, err := debian.NewPackageListFromRefList(srcRefList, packageCollection, context.progress)
srcList, err := deb.NewPackageListFromRefList(srcRefList, context.CollectionFactory().PackageCollection(), context.Progress())
if err != nil {
return fmt.Errorf("unable to load packages: %s", err)
}
@@ -89,14 +86,14 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
var architecturesList []string
withDeps := cmd.Flag.Lookup("with-deps").Value.Get().(bool)
withDeps := context.flags.Lookup("with-deps").Value.Get().(bool)
if withDeps {
dstList.PrepareIndex()
// Calculate architectures
if len(context.architecturesList) > 0 {
architecturesList = context.architecturesList
if len(context.ArchitecturesList()) > 0 {
architecturesList = context.ArchitecturesList()
} else {
architecturesList = dstList.Architectures(false)
}
@@ -108,7 +105,7 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
}
}
toProcess, err := srcList.Filter(args[2:], withDeps, dstList, context.dependencyOptions, architecturesList)
toProcess, err := srcList.Filter(args[2:], withDeps, dstList, context.DependencyOptions(), architecturesList)
if err != nil {
return fmt.Errorf("unable to %s: %s", command, err)
}
@@ -123,7 +120,7 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
verb = "imported"
}
err = toProcess.ForEach(func(p *debian.Package) error {
err = toProcess.ForEach(func(p *deb.Package) error {
err = dstList.Add(p)
if err != nil {
return err
@@ -132,27 +129,27 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
if command == "move" {
srcList.Remove(p)
}
context.progress.ColoredPrintf("@g[o]@| %s %s", p, verb)
context.Progress().ColoredPrintf("@g[o]@| %s %s", p, verb)
return nil
})
if err != nil {
return fmt.Errorf("unable to %s: %s", command, err)
}
if cmd.Flag.Lookup("dry-run").Value.Get().(bool) {
context.progress.Printf("\nChanges not saved, as dry run has been requested.\n")
if context.flags.Lookup("dry-run").Value.Get().(bool) {
context.Progress().Printf("\nChanges not saved, as dry run has been requested.\n")
} else {
dstRepo.UpdateRefList(debian.NewPackageRefListFromPackageList(dstList))
dstRepo.UpdateRefList(deb.NewPackageRefListFromPackageList(dstList))
err = localRepoCollection.Update(dstRepo)
err = context.CollectionFactory().LocalRepoCollection().Update(dstRepo)
if err != nil {
return fmt.Errorf("unable to save: %s", err)
}
if command == "move" {
srcRepo.UpdateRefList(debian.NewPackageRefListFromPackageList(srcList))
srcRepo.UpdateRefList(deb.NewPackageRefListFromPackageList(srcList))
err = localRepoCollection.Update(srcRepo)
err = context.CollectionFactory().LocalRepoCollection().Update(srcRepo)
if err != nil {
return fmt.Errorf("unable to save: %s", err)
}
+13 -15
View File
@@ -2,9 +2,9 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlyRepoRemove(cmd *commander.Command, args []string) error {
@@ -16,21 +16,19 @@ func aptlyRepoRemove(cmd *commander.Command, args []string) error {
name := args[0]
localRepoCollection := debian.NewLocalRepoCollection(context.database)
repo, err := localRepoCollection.ByName(name)
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to remove: %s", err)
}
err = localRepoCollection.LoadComplete(repo)
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if err != nil {
return fmt.Errorf("unable to remove: %s", err)
}
context.progress.Printf("Loading packages...\n")
context.Progress().Printf("Loading packages...\n")
packageCollection := debian.NewPackageCollection(context.database)
list, err := debian.NewPackageListFromRefList(repo.RefList(), packageCollection, context.progress)
list, err := deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
if err != nil {
return fmt.Errorf("unable to load packages: %s", err)
}
@@ -41,18 +39,18 @@ func aptlyRepoRemove(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to remove: %s", err)
}
toRemove.ForEach(func(p *debian.Package) error {
toRemove.ForEach(func(p *deb.Package) error {
list.Remove(p)
context.progress.ColoredPrintf("@r[-]@| %s removed", p)
context.Progress().ColoredPrintf("@r[-]@| %s removed", p)
return nil
})
if cmd.Flag.Lookup("dry-run").Value.Get().(bool) {
context.progress.Printf("\nChanges not saved, as dry run has been requested.\n")
if context.flags.Lookup("dry-run").Value.Get().(bool) {
context.Progress().Printf("\nChanges not saved, as dry run has been requested.\n")
} else {
repo.UpdateRefList(debian.NewPackageRefListFromPackageList(list))
repo.UpdateRefList(deb.NewPackageRefListFromPackageList(list))
err = localRepoCollection.Update(repo)
err = context.CollectionFactory().LocalRepoCollection().Update(repo)
if err != nil {
return fmt.Errorf("unable to save: %s", err)
}
+8 -8
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlyRepoShow(cmd *commander.Command, args []string) error {
@@ -16,22 +15,23 @@ func aptlyRepoShow(cmd *commander.Command, args []string) error {
name := args[0]
localRepoCollection := debian.NewLocalRepoCollection(context.database)
repo, err := localRepoCollection.ByName(name)
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to show: %s", err)
}
err = localRepoCollection.LoadComplete(repo)
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if err != nil {
return fmt.Errorf("unable to show: %s", err)
}
fmt.Printf("Name: %s\n", repo.Name)
fmt.Printf("Comment: %s\n", repo.Comment)
fmt.Printf("Default Distribution: %s\n", repo.DefaultDistribution)
fmt.Printf("Default Component: %s\n", repo.DefaultComponent)
fmt.Printf("Number of packages: %d\n", repo.NumPackages())
withPackages := cmd.Flag.Lookup("with-packages").Value.Get().(bool)
withPackages := context.flags.Lookup("with-packages").Value.Get().(bool)
if withPackages {
ListPackagesRefList(repo.RefList())
}
@@ -45,7 +45,7 @@ func makeCmdRepoShow() *commander.Command {
UsageLine: "show <name>",
Short: "show details about local repository",
Long: `
Show shows full information about local package repository.
Show command shows full information about local package repository.
ex:
$ aptly repo show testing
+12 -14
View File
@@ -2,10 +2,10 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/aptly/utils"
"github.com/smira/commander"
"github.com/smira/flag"
"net"
"net/http"
"os"
@@ -15,15 +15,12 @@ import (
func aptlyServe(cmd *commander.Command, args []string) error {
var err error
publishedCollection := debian.NewPublishedRepoCollection(context.database)
snapshotCollection := debian.NewSnapshotCollection(context.database)
if publishedCollection.Len() == 0 {
if context.CollectionFactory().PublishedRepoCollection().Len() == 0 {
fmt.Printf("No published repositories, unable to serve.\n")
return nil
}
listen := cmd.Flag.Lookup("listen").Value.String()
listen := context.flags.Lookup("listen").Value.String()
listenHost, listenPort, err := net.SplitHostPort(listen)
@@ -40,11 +37,11 @@ func aptlyServe(cmd *commander.Command, args []string) error {
fmt.Printf("Serving published repositories, recommended apt sources list:\n\n")
sources := make(sort.StringSlice, 0, publishedCollection.Len())
published := make(map[string]*debian.PublishedRepo, publishedCollection.Len())
sources := make(sort.StringSlice, 0, context.CollectionFactory().PublishedRepoCollection().Len())
published := make(map[string]*deb.PublishedRepo, context.CollectionFactory().PublishedRepoCollection().Len())
err = publishedCollection.ForEach(func(repo *debian.PublishedRepo) error {
err := publishedCollection.LoadComplete(repo, snapshotCollection)
err = context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error {
err := context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
if err != nil {
return err
}
@@ -80,11 +77,12 @@ func aptlyServe(cmd *commander.Command, args []string) error {
}
}
context.database.Close()
publicPath := context.PublishedStorage().PublicPath()
ShutdownContext()
fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen)
err = http.ListenAndServe(listen, http.FileServer(http.Dir(context.publishedStorage.PublicPath())))
err = http.ListenAndServe(listen, http.FileServer(http.Dir(publicPath)))
if err != nil {
return fmt.Errorf("unable to serve: %s", err)
}
+1 -3
View File
@@ -1,8 +1,7 @@
package cmd
import (
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/commander"
)
func makeCmdSnapshot() *commander.Command {
@@ -19,6 +18,5 @@ func makeCmdSnapshot() *commander.Command {
makeCmdSnapshotMerge(),
makeCmdSnapshotDrop(),
},
Flag: *flag.NewFlagSet("aptly-snapshot", flag.ExitOnError),
}
}
+16 -18
View File
@@ -2,52 +2,53 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
)
func aptlySnapshotCreate(cmd *commander.Command, args []string) error {
var (
err error
snapshot *debian.Snapshot
snapshot *deb.Snapshot
)
if len(args) == 4 && args[1] == "from" && args[2] == "mirror" {
// aptly snapshot create snap from mirror mirror
var repo *deb.RemoteRepo
repoName, snapshotName := args[3], args[0]
repoCollection := debian.NewRemoteRepoCollection(context.database)
repo, err := repoCollection.ByName(repoName)
repo, err = context.CollectionFactory().RemoteRepoCollection().ByName(repoName)
if err != nil {
return fmt.Errorf("unable to create snapshot: %s", err)
}
err = repoCollection.LoadComplete(repo)
err = context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
if err != nil {
return fmt.Errorf("unable to create snapshot: %s", err)
}
snapshot, err = debian.NewSnapshotFromRepository(snapshotName, repo)
snapshot, err = deb.NewSnapshotFromRepository(snapshotName, repo)
if err != nil {
return fmt.Errorf("unable to create snapshot: %s", err)
}
} else if len(args) == 4 && args[1] == "from" && args[2] == "repo" {
// aptly snapshot create snap from repo repo
var repo *deb.LocalRepo
localRepoName, snapshotName := args[3], args[0]
localRepoCollection := debian.NewLocalRepoCollection(context.database)
repo, err := localRepoCollection.ByName(localRepoName)
repo, err = context.CollectionFactory().LocalRepoCollection().ByName(localRepoName)
if err != nil {
return fmt.Errorf("unable to create snapshot: %s", err)
}
err = localRepoCollection.LoadComplete(repo)
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if err != nil {
return fmt.Errorf("unable to create snapshot: %s", err)
}
snapshot, err = debian.NewSnapshotFromLocalRepo(snapshotName, repo)
snapshot, err = deb.NewSnapshotFromLocalRepo(snapshotName, repo)
if err != nil {
return fmt.Errorf("unable to create snapshot: %s", err)
}
@@ -55,17 +56,15 @@ func aptlySnapshotCreate(cmd *commander.Command, args []string) error {
// aptly snapshot create snap empty
snapshotName := args[0]
packageList := debian.NewPackageList()
packageList := deb.NewPackageList()
snapshot = debian.NewSnapshotFromPackageList(snapshotName, nil, packageList, "Created as empty")
snapshot = deb.NewSnapshotFromPackageList(snapshotName, nil, packageList, "Created as empty")
} else {
cmd.Usage()
return err
}
snapshotCollection := debian.NewSnapshotCollection(context.database)
err = snapshotCollection.Add(snapshot)
err = context.CollectionFactory().SnapshotCollection().Add(snapshot)
if err != nil {
return fmt.Errorf("unable to add snapshot: %s", err)
}
@@ -97,7 +96,6 @@ Example:
$ aptly snapshot create wheezy-main-today from mirror wheezy-main
`,
Flag: *flag.NewFlagSet("aptly-snapshot-create", flag.ExitOnError),
}
return cmd
+11 -15
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlySnapshotDiff(cmd *commander.Command, args []string) error {
@@ -14,43 +13,40 @@ func aptlySnapshotDiff(cmd *commander.Command, args []string) error {
return err
}
onlyMatching := cmd.Flag.Lookup("only-matching").Value.Get().(bool)
snapshotCollection := debian.NewSnapshotCollection(context.database)
packageCollection := debian.NewPackageCollection(context.database)
onlyMatching := context.flags.Lookup("only-matching").Value.Get().(bool)
// Load <name-a> snapshot
snapshotA, err := snapshotCollection.ByName(args[0])
snapshotA, err := context.CollectionFactory().SnapshotCollection().ByName(args[0])
if err != nil {
return fmt.Errorf("unable to load snapshot A: %s", err)
}
err = snapshotCollection.LoadComplete(snapshotA)
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshotA)
if err != nil {
return fmt.Errorf("unable to load snapshot A: %s", err)
}
// Load <name-b> snapshot
snapshotB, err := snapshotCollection.ByName(args[1])
snapshotB, err := context.CollectionFactory().SnapshotCollection().ByName(args[1])
if err != nil {
return fmt.Errorf("unable to load snapshot B: %s", err)
}
err = snapshotCollection.LoadComplete(snapshotB)
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshotB)
if err != nil {
return fmt.Errorf("unable to load snapshot B: %s", err)
}
// Calculate diff
diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), packageCollection)
diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), context.CollectionFactory().PackageCollection())
if err != nil {
return fmt.Errorf("unable to calculate diff: %s", err)
}
if len(diff) == 0 {
context.progress.Printf("Snapshots are identical.\n")
context.Progress().Printf("Snapshots are identical.\n")
} else {
context.progress.Printf(" Arch | Package | Version in A | Version in B\n")
context.Progress().Printf(" Arch | Package | Version in A | Version in B\n")
for _, pdiff := range diff {
if onlyMatching && (pdiff.Left == nil || pdiff.Right == nil) {
continue
@@ -84,7 +80,7 @@ func aptlySnapshotDiff(cmd *commander.Command, args []string) error {
}
}
context.progress.ColoredPrintf(code+" %-6s | %-40s | %-40s | %-40s", arch, pkg, verA, verB)
context.Progress().ColoredPrintf(code+" %-6s | %-40s | %-40s | %-40s", arch, pkg, verA, verB)
}
}
+9 -12
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlySnapshotDrop(cmd *commander.Command, args []string) error {
@@ -16,19 +15,17 @@ func aptlySnapshotDrop(cmd *commander.Command, args []string) error {
name := args[0]
snapshotCollection := debian.NewSnapshotCollection(context.database)
snapshot, err := snapshotCollection.ByName(name)
snapshot, err := context.CollectionFactory().SnapshotCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to drop: %s", err)
}
publishedRepoCollection := debian.NewPublishedRepoCollection(context.database)
published := publishedRepoCollection.BySnapshot(snapshot)
published := context.CollectionFactory().PublishedRepoCollection().BySnapshot(snapshot)
if len(published) > 0 {
fmt.Printf("Snapshot `%s` is published currently:\n", snapshot.Name)
for _, repo := range published {
err = publishedRepoCollection.LoadComplete(repo, snapshotCollection)
err = context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
if err != nil {
return fmt.Errorf("unable to load published: %s", err)
}
@@ -38,9 +35,9 @@ func aptlySnapshotDrop(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to drop: snapshot is published")
}
force := cmd.Flag.Lookup("force").Value.Get().(bool)
force := context.flags.Lookup("force").Value.Get().(bool)
if !force {
snapshots := snapshotCollection.BySnapshotSource(snapshot)
snapshots := context.CollectionFactory().SnapshotCollection().BySnapshotSource(snapshot)
if len(snapshots) > 0 {
fmt.Printf("Snapshot `%s` was used as a source in following snapshots:\n", snapshot.Name)
for _, snap := range snapshots {
@@ -51,7 +48,7 @@ func aptlySnapshotDrop(cmd *commander.Command, args []string) error {
}
}
err = snapshotCollection.Drop(snapshot)
err = context.CollectionFactory().SnapshotCollection().Drop(snapshot)
if err != nil {
return fmt.Errorf("unable to drop: %s", err)
}
@@ -67,7 +64,7 @@ func makeCmdSnapshotDrop() *commander.Command {
UsageLine: "drop <name>",
Short: "delete snapshot",
Long: `
Drop removes information about snapshot. If snapshot is published,
Drop removes information about a snapshot. If snapshot is published,
it can't be dropped.
Example:
+31 -20
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"sort"
)
@@ -15,28 +14,39 @@ func aptlySnapshotList(cmd *commander.Command, args []string) error {
return err
}
snapshotCollection := debian.NewSnapshotCollection(context.database)
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
if snapshotCollection.Len() > 0 {
fmt.Printf("List of snapshots:\n")
snapshots := make([]string, context.CollectionFactory().SnapshotCollection().Len())
snapshots := make([]string, snapshotCollection.Len())
i := 0
snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
i := 0
context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
if raw {
snapshots[i] = snapshot.Name
} else {
snapshots[i] = snapshot.String()
i++
return nil
})
sort.Strings(snapshots)
for _, snapshot := range snapshots {
fmt.Printf(" * %s\n", snapshot)
}
i++
return nil
})
fmt.Printf("\nTo get more information about snapshot, run `aptly snapshot show <name>`.\n")
sort.Strings(snapshots)
if raw {
for _, snapshot := range snapshots {
fmt.Printf("%s\n", snapshot)
}
} else {
fmt.Printf("\nNo snapshots found, create one with `aptly snapshot create...`.\n")
if len(snapshots) > 0 {
fmt.Printf("List of snapshots:\n")
for _, snapshot := range snapshots {
fmt.Printf(" * %s\n", snapshot)
}
fmt.Printf("\nTo get more information about snapshot, run `aptly snapshot show <name>`.\n")
} else {
fmt.Printf("\nNo snapshots found, create one with `aptly snapshot create...`.\n")
}
}
return err
@@ -54,8 +64,9 @@ Example:
$ aptly snapshot list
`,
Flag: *flag.NewFlagSet("aptly-snapshot-list", flag.ExitOnError),
}
cmd.Flag.Bool("raw", false, "display list in machine-readable format")
return cmd
}
+21 -16
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"strings"
)
@@ -15,26 +14,31 @@ func aptlySnapshotMerge(cmd *commander.Command, args []string) error {
return err
}
snapshotCollection := debian.NewSnapshotCollection(context.database)
sources := make([]*debian.Snapshot, len(args)-1)
sources := make([]*deb.Snapshot, len(args)-1)
for i := 0; i < len(args)-1; i++ {
sources[i], err = snapshotCollection.ByName(args[i+1])
sources[i], err = context.CollectionFactory().SnapshotCollection().ByName(args[i+1])
if err != nil {
return fmt.Errorf("unable to load snapshot: %s", err)
}
err = snapshotCollection.LoadComplete(sources[i])
err = context.CollectionFactory().SnapshotCollection().LoadComplete(sources[i])
if err != nil {
return fmt.Errorf("unable to load snapshot: %s", err)
}
}
latest := context.flags.Lookup("latest").Value.Get().(bool)
overrideMatching := !latest
result := sources[0].RefList()
for i := 1; i < len(sources); i++ {
result = result.Merge(sources[i].RefList(), true)
result = result.Merge(sources[i].RefList(), overrideMatching)
}
if latest {
deb.FilterLatestRefs(result)
}
sourceDescription := make([]string, len(sources))
@@ -43,10 +47,10 @@ func aptlySnapshotMerge(cmd *commander.Command, args []string) error {
}
// Create <destination> snapshot
destination := debian.NewSnapshotFromRefList(args[0], sources, result,
destination := deb.NewSnapshotFromRefList(args[0], sources, result,
fmt.Sprintf("Merged from sources: %s", strings.Join(sourceDescription, ", ")))
err = snapshotCollection.Add(destination)
err = context.CollectionFactory().SnapshotCollection().Add(destination)
if err != nil {
return fmt.Errorf("unable to create snapshot: %s", err)
}
@@ -62,18 +66,19 @@ func makeCmdSnapshotMerge() *commander.Command {
UsageLine: "merge <destination> <source> [<source>...]",
Short: "merges snapshots",
Long: `
Merge merges several <source> snapshots into one <destination> snapshot.
Merge happens from left to right. Packages with the same name-architecture
pair are replaced during merge (package from latest snapshot on the list
wins). If run with only one source snapshot, merge copies <source> into
Merge command merges several <source> snapshots into one <destination> snapshot.
Merge happens from left to right. By default, packages with the same
name-architecture pair are replaced during merge (package from latest snapshot
on the list wins). If run with only one source snapshot, merge copies <source> into
<destination>.
Example:
$ aptly snapshot merge wheezy-w-backports wheezy-main wheezy-backports
`,
Flag: *flag.NewFlagSet("aptly-snapshot-merge", flag.ExitOnError),
}
cmd.Flag.Bool("latest", false, "use only the latest version of each package")
return cmd
}
+35 -37
View File
@@ -2,9 +2,9 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"github.com/smira/flag"
"sort"
"strings"
)
@@ -16,58 +16,55 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
return err
}
noDeps := cmd.Flag.Lookup("no-deps").Value.Get().(bool)
noRemove := cmd.Flag.Lookup("no-remove").Value.Get().(bool)
snapshotCollection := debian.NewSnapshotCollection(context.database)
packageCollection := debian.NewPackageCollection(context.database)
noDeps := context.flags.Lookup("no-deps").Value.Get().(bool)
noRemove := context.flags.Lookup("no-remove").Value.Get().(bool)
// Load <name> snapshot
snapshot, err := snapshotCollection.ByName(args[0])
snapshot, err := context.CollectionFactory().SnapshotCollection().ByName(args[0])
if err != nil {
return fmt.Errorf("unable to pull: %s", err)
}
err = snapshotCollection.LoadComplete(snapshot)
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
if err != nil {
return fmt.Errorf("unable to pull: %s", err)
}
// Load <source> snapshot
source, err := snapshotCollection.ByName(args[1])
source, err := context.CollectionFactory().SnapshotCollection().ByName(args[1])
if err != nil {
return fmt.Errorf("unable to pull: %s", err)
}
err = snapshotCollection.LoadComplete(source)
err = context.CollectionFactory().SnapshotCollection().LoadComplete(source)
if err != nil {
return fmt.Errorf("unable to pull: %s", err)
}
context.progress.Printf("Dependencies would be pulled into snapshot:\n %s\nfrom snapshot:\n %s\nand result would be saved as new snapshot %s.\n",
context.Progress().Printf("Dependencies would be pulled into snapshot:\n %s\nfrom snapshot:\n %s\nand result would be saved as new snapshot %s.\n",
snapshot, source, args[2])
// Convert snapshot to package list
context.progress.Printf("Loading packages (%d)...\n", snapshot.RefList().Len()+source.RefList().Len())
packageList, err := debian.NewPackageListFromRefList(snapshot.RefList(), packageCollection, context.progress)
context.Progress().Printf("Loading packages (%d)...\n", snapshot.RefList().Len()+source.RefList().Len())
packageList, err := deb.NewPackageListFromRefList(snapshot.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
if err != nil {
return fmt.Errorf("unable to load packages: %s", err)
}
sourcePackageList, err := debian.NewPackageListFromRefList(source.RefList(), packageCollection, context.progress)
sourcePackageList, err := deb.NewPackageListFromRefList(source.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
if err != nil {
return fmt.Errorf("unable to load packages: %s", err)
}
context.progress.Printf("Building indexes...\n")
context.Progress().Printf("Building indexes...\n")
packageList.PrepareIndex()
sourcePackageList.PrepareIndex()
// Calculate architectures
var architecturesList []string
if len(context.architecturesList) > 0 {
architecturesList = context.architecturesList
if len(context.ArchitecturesList()) > 0 {
architecturesList = context.ArchitecturesList()
} else {
architecturesList = packageList.Architectures(false)
}
@@ -79,9 +76,9 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
}
// Initial dependencies out of arguments
initialDependencies := make([]debian.Dependency, len(args)-3)
initialDependencies := make([]deb.Dependency, len(args)-3)
for i, arg := range args[3:] {
initialDependencies[i], err = debian.ParseDependency(arg)
initialDependencies[i], err = deb.ParseDependency(arg)
if err != nil {
return fmt.Errorf("unable to parse argument: %s", err)
}
@@ -89,7 +86,7 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
// Perform pull
for _, arch := range architecturesList {
dependencies := make([]debian.Dependency, len(initialDependencies), 128)
dependencies := make([]deb.Dependency, len(initialDependencies), 128)
for i := range dependencies {
dependencies[i] = initialDependencies[i]
dependencies[i].Architecture = arch
@@ -102,34 +99,35 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
// Search for package that can satisfy dependencies
pkg := sourcePackageList.Search(dep)
if pkg == nil {
context.progress.ColoredPrintf("@y[!]@| @!Dependency %s can't be satisfied with source %s@|", &dep, source)
context.Progress().ColoredPrintf("@y[!]@| @!Dependency %s can't be satisfied with source %s@|", &dep, source)
continue
}
if !noRemove {
// Remove all packages with the same name and architecture
for p := packageList.Search(debian.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name}); p != nil; {
for p := packageList.Search(deb.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name}); p != nil; {
packageList.Remove(p)
context.progress.ColoredPrintf("@r[-]@| %s removed", p)
p = packageList.Search(debian.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name})
context.Progress().ColoredPrintf("@r[-]@| %s removed", p)
p = packageList.Search(deb.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name})
}
}
// Add new discovered package
packageList.Add(pkg)
context.progress.ColoredPrintf("@g[+]@| %s added", pkg)
context.Progress().ColoredPrintf("@g[+]@| %s added", pkg)
if noDeps {
continue
}
// Find missing dependencies for single added package
pL := debian.NewPackageList()
pL := deb.NewPackageList()
pL.Add(pkg)
missing, err := pL.VerifyDependencies(context.dependencyOptions, []string{arch}, packageList, nil)
var missing []deb.Dependency
missing, err = pL.VerifyDependencies(context.DependencyOptions(), []string{arch}, packageList, nil)
if err != nil {
context.progress.ColoredPrintf("@y[!]@| @!Error while verifying dependencies for pkg %s: %s@|", pkg, err)
context.Progress().ColoredPrintf("@y[!]@| @!Error while verifying dependencies for pkg %s: %s@|", pkg, err)
}
// Append missing dependencies to the list of dependencies to satisfy
@@ -149,19 +147,19 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
}
}
if cmd.Flag.Lookup("dry-run").Value.Get().(bool) {
context.progress.Printf("\nNot creating snapshot, as dry run was requested.\n")
if context.flags.Lookup("dry-run").Value.Get().(bool) {
context.Progress().Printf("\nNot creating snapshot, as dry run was requested.\n")
} else {
// Create <destination> snapshot
destination := debian.NewSnapshotFromPackageList(args[2], []*debian.Snapshot{snapshot, source}, packageList,
destination := deb.NewSnapshotFromPackageList(args[2], []*deb.Snapshot{snapshot, source}, packageList,
fmt.Sprintf("Pulled into '%s' with '%s' as source, pull request was: '%s'", snapshot.Name, source.Name, strings.Join(args[3:], " ")))
err = snapshotCollection.Add(destination)
err = context.CollectionFactory().SnapshotCollection().Add(destination)
if err != nil {
return fmt.Errorf("unable to create snapshot: %s", err)
}
context.progress.Printf("\nSnapshot %s successfully created.\nYou can run 'aptly publish snapshot %s' to publish snapshot as Debian repository.\n", destination.Name, destination.Name)
context.Progress().Printf("\nSnapshot %s successfully created.\nYou can run 'aptly publish snapshot %s' to publish snapshot as Debian repository.\n", destination.Name, destination.Name)
}
return err
}
@@ -172,10 +170,10 @@ func makeCmdSnapshotPull() *commander.Command {
UsageLine: "pull <name> <source> <destination> <package-name> ...",
Short: "pull packages from another snapshot",
Long: `
Command pull pulls new packages along with its dependencies to snapshot <name>
Command pull pulls new packages along with its' dependencies to snapshot <name>
from snapshot <source>. Pull can upgrade package version in <name> with
versions from <source> following dependencies. New snapshot <destination>
is created as result of this process. Packages could be specified simply
is created as a result of this process. Packages could be specified simply
as 'package-name' or as dependency 'package-name (>= version)'.
Example:
+6 -8
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/commander"
"github.com/smira/flag"
)
func aptlySnapshotShow(cmd *commander.Command, args []string) error {
@@ -16,13 +15,12 @@ func aptlySnapshotShow(cmd *commander.Command, args []string) error {
name := args[0]
snapshotCollection := debian.NewSnapshotCollection(context.database)
snapshot, err := snapshotCollection.ByName(name)
snapshot, err := context.CollectionFactory().SnapshotCollection().ByName(name)
if err != nil {
return fmt.Errorf("unable to show: %s", err)
}
err = snapshotCollection.LoadComplete(snapshot)
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
if err != nil {
return fmt.Errorf("unable to show: %s", err)
}
@@ -32,7 +30,7 @@ func aptlySnapshotShow(cmd *commander.Command, args []string) error {
fmt.Printf("Description: %s\n", snapshot.Description)
fmt.Printf("Number of packages: %d\n", snapshot.NumPackages())
withPackages := cmd.Flag.Lookup("with-packages").Value.Get().(bool)
withPackages := context.flags.Lookup("with-packages").Value.Get().(bool)
if withPackages {
ListPackagesRefList(snapshot.RefList())
}
@@ -46,7 +44,7 @@ func makeCmdSnapshotShow() *commander.Command {
UsageLine: "show <name>",
Short: "shows details about snapshot",
Long: `
Command show displays full information about snapshot.
Command show displays full information about a snapshot.
Example:
+18 -22
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/debian"
"github.com/smira/aptly/deb"
"github.com/smira/commander"
"sort"
)
@@ -15,37 +14,35 @@ func aptlySnapshotVerify(cmd *commander.Command, args []string) error {
return err
}
snapshotCollection := debian.NewSnapshotCollection(context.database)
packageCollection := debian.NewPackageCollection(context.database)
snapshots := make([]*debian.Snapshot, len(args))
snapshots := make([]*deb.Snapshot, len(args))
for i := range snapshots {
snapshots[i], err = snapshotCollection.ByName(args[i])
snapshots[i], err = context.CollectionFactory().SnapshotCollection().ByName(args[i])
if err != nil {
return fmt.Errorf("unable to verify: %s", err)
}
err = snapshotCollection.LoadComplete(snapshots[i])
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshots[i])
if err != nil {
return fmt.Errorf("unable to verify: %s", err)
}
}
context.progress.Printf("Loading packages...\n")
context.Progress().Printf("Loading packages...\n")
packageList, err := debian.NewPackageListFromRefList(snapshots[0].RefList(), packageCollection, context.progress)
packageList, err := deb.NewPackageListFromRefList(snapshots[0].RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
if err != nil {
fmt.Errorf("unable to load packages: %s", err)
}
sourcePackageList := debian.NewPackageList()
sourcePackageList := deb.NewPackageList()
err = sourcePackageList.Append(packageList)
if err != nil {
fmt.Errorf("unable to merge sources: %s", err)
}
var pL *deb.PackageList
for i := 1; i < len(snapshots); i++ {
pL, err := debian.NewPackageListFromRefList(snapshots[i].RefList(), packageCollection, context.progress)
pL, err = deb.NewPackageListFromRefList(snapshots[i].RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
if err != nil {
fmt.Errorf("unable to load packages: %s", err)
}
@@ -60,8 +57,8 @@ func aptlySnapshotVerify(cmd *commander.Command, args []string) error {
var architecturesList []string
if len(context.architecturesList) > 0 {
architecturesList = context.architecturesList
if len(context.ArchitecturesList()) > 0 {
architecturesList = context.ArchitecturesList()
} else {
architecturesList = packageList.Architectures(true)
}
@@ -70,17 +67,17 @@ func aptlySnapshotVerify(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to determine list of architectures, please specify explicitly")
}
context.progress.Printf("Verifying...\n")
context.Progress().Printf("Verifying...\n")
missing, err := packageList.VerifyDependencies(context.dependencyOptions, architecturesList, sourcePackageList, context.progress)
missing, err := packageList.VerifyDependencies(context.DependencyOptions(), architecturesList, sourcePackageList, context.Progress())
if err != nil {
return fmt.Errorf("unable to verify dependencies: %s", err)
}
if len(missing) == 0 {
context.progress.Printf("All dependencies are satisfied.\n")
context.Progress().Printf("All dependencies are satisfied.\n")
} else {
context.progress.Printf("Missing dependencies (%d):\n", len(missing))
context.Progress().Printf("Missing dependencies (%d):\n", len(missing))
deps := make([]string, len(missing))
i := 0
for _, dep := range missing {
@@ -91,7 +88,7 @@ func aptlySnapshotVerify(cmd *commander.Command, args []string) error {
sort.Strings(deps)
for _, dep := range deps {
context.progress.Printf(" %s\n", dep)
context.Progress().Printf(" %s\n", dep)
}
}
@@ -104,7 +101,7 @@ func makeCmdSnapshotVerify() *commander.Command {
UsageLine: "verify <name> [<source> ...]",
Short: "verify dependencies in snapshot",
Long: `
Verify does depenency resolution in snapshot <name>, possibly using additional
Verify does dependency resolution in snapshot <name>, possibly using additional
snapshots <source> as dependency sources. All unsatisfied dependencies are
printed.
@@ -112,7 +109,6 @@ Example:
$ aptly snapshot verify wheezy-main wheezy-contrib wheezy-non-free
`,
Flag: *flag.NewFlagSet("aptly-snapshot-verify", flag.ExitOnError),
}
return cmd
+1 -3
View File
@@ -2,9 +2,8 @@ package cmd
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/aptly"
"github.com/smira/commander"
)
func aptlyVersion(cmd *commander.Command, args []string) error {
@@ -23,6 +22,5 @@ Shows aptly version.
ex:
$ aptly version
`,
Flag: *flag.NewFlagSet("aptly-version", flag.ExitOnError),
}
}
+36
View File
@@ -7,6 +7,8 @@ import (
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/filter"
"github.com/syndtr/goleveldb/leveldb/opt"
"github.com/syndtr/goleveldb/leveldb/storage"
"github.com/syndtr/goleveldb/leveldb/util"
)
// Errors for Storage
@@ -24,6 +26,7 @@ type Storage interface {
Close() error
StartBatch()
FinishBatch() error
CompactDB() error
}
type levelDB struct {
@@ -49,6 +52,25 @@ func OpenDB(path string) (Storage, error) {
return &levelDB{db: db}, nil
}
// RecoverDB recovers LevelDB database from corruption
func RecoverDB(path string) error {
stor, err := storage.OpenFile(path)
if err != nil {
return err
}
db, err := leveldb.Recover(stor, nil)
if err != nil {
return err
}
db.Close()
stor.Close()
return nil
}
// Get key value from database
func (l *levelDB) Get(key []byte) ([]byte, error) {
value, err := l.db.Get(key, nil)
if err != nil {
@@ -61,6 +83,7 @@ func (l *levelDB) Get(key []byte) ([]byte, error) {
return value, nil
}
// Put saves key to database, if key has the same value in DB already, it is not saved
func (l *levelDB) Put(key []byte, value []byte) error {
if l.batch != nil {
l.batch.Put(key, value)
@@ -79,6 +102,7 @@ func (l *levelDB) Put(key []byte, value []byte) error {
return l.db.Put(key, value, nil)
}
// Delete removes key from DB
func (l *levelDB) Delete(key []byte) error {
if l.batch != nil {
l.batch.Delete(key)
@@ -87,6 +111,7 @@ func (l *levelDB) Delete(key []byte) error {
return l.db.Delete(key, nil)
}
// KeysByPrefix returns all keys that start with prefix
func (l *levelDB) KeysByPrefix(prefix []byte) [][]byte {
result := make([][]byte, 0, 20)
@@ -103,6 +128,7 @@ func (l *levelDB) KeysByPrefix(prefix []byte) [][]byte {
return result
}
// FetchByPrefix returns all values with keys that start with prefix
func (l *levelDB) FetchByPrefix(prefix []byte) [][]byte {
result := make([][]byte, 0, 20)
@@ -119,10 +145,14 @@ func (l *levelDB) FetchByPrefix(prefix []byte) [][]byte {
return result
}
// Close finishes DB work
func (l *levelDB) Close() error {
return l.db.Close()
}
// StartBatch starts batch processing of keys
//
// All subsequent Get, Put and Delete would work on batch
func (l *levelDB) StartBatch() {
if l.batch != nil {
panic("batch already started")
@@ -130,6 +160,7 @@ func (l *levelDB) StartBatch() {
l.batch = new(leveldb.Batch)
}
// FinishBatch finalizes the batch, saving operations
func (l *levelDB) FinishBatch() error {
if l.batch == nil {
panic("no batch")
@@ -138,3 +169,8 @@ func (l *levelDB) FinishBatch() error {
l.batch = nil
return err
}
// CompactDB compacts database by merging layers
func (l *levelDB) CompactDB() error {
return l.db.CompactRange(util.Range{})
}
+35 -2
View File
@@ -11,7 +11,8 @@ func Test(t *testing.T) {
}
type LevelDBSuite struct {
db Storage
path string
db Storage
}
var _ = Suite(&LevelDBSuite{})
@@ -19,7 +20,8 @@ var _ = Suite(&LevelDBSuite{})
func (s *LevelDBSuite) SetUpTest(c *C) {
var err error
s.db, err = OpenDB(c.MkDir())
s.path = c.MkDir()
s.db, err = OpenDB(s.path)
c.Assert(err, IsNil)
}
@@ -28,6 +30,29 @@ func (s *LevelDBSuite) TearDownTest(c *C) {
c.Assert(err, IsNil)
}
func (s *LevelDBSuite) TestRecoverDB(c *C) {
var (
key = []byte("key")
value = []byte("value")
)
err := s.db.Put(key, value)
c.Check(err, IsNil)
err = s.db.Close()
c.Check(err, IsNil)
err = RecoverDB(s.path)
c.Check(err, IsNil)
s.db, err = OpenDB(s.path)
c.Check(err, IsNil)
result, err := s.db.Get(key)
c.Assert(err, IsNil)
c.Assert(result, DeepEquals, value)
}
func (s *LevelDBSuite) TestGetPut(c *C) {
var (
key = []byte("key")
@@ -122,3 +147,11 @@ func (s *LevelDBSuite) TestBatch(c *C) {
s.db.StartBatch()
c.Check(func() { s.db.StartBatch() }, Panics, "batch already started")
}
func (s *LevelDBSuite) TestCompactDB(c *C) {
s.db.Put([]byte{0x80, 0x01}, []byte{0x01})
s.db.Put([]byte{0x80, 0x03}, []byte{0x03})
s.db.Put([]byte{0x80, 0x02}, []byte{0x02})
c.Check(s.db.CompactDB(), IsNil)
}
+65
View File
@@ -0,0 +1,65 @@
package deb
import (
"github.com/smira/aptly/database"
)
// CollectionFactory is a single place to generate all desired collections
type CollectionFactory struct {
db database.Storage
packages *PackageCollection
remoteRepos *RemoteRepoCollection
snapshots *SnapshotCollection
localRepos *LocalRepoCollection
publishedRepos *PublishedRepoCollection
}
// NewCollectionFactory creates new factory
func NewCollectionFactory(db database.Storage) *CollectionFactory {
return &CollectionFactory{db: db}
}
// PackageCollection returns (or creates) new PackageCollection
func (factory *CollectionFactory) PackageCollection() *PackageCollection {
if factory.packages == nil {
factory.packages = NewPackageCollection(factory.db)
}
return factory.packages
}
// RemoteRepoCollection returns (or creates) new RemoteRepoCollection
func (factory *CollectionFactory) RemoteRepoCollection() *RemoteRepoCollection {
if factory.remoteRepos == nil {
factory.remoteRepos = NewRemoteRepoCollection(factory.db)
}
return factory.remoteRepos
}
// SnapshotCollection returns (or creates) new SnapshotCollection
func (factory *CollectionFactory) SnapshotCollection() *SnapshotCollection {
if factory.snapshots == nil {
factory.snapshots = NewSnapshotCollection(factory.db)
}
return factory.snapshots
}
// LocalRepoCollection returns (or creates) new LocalRepoCollection
func (factory *CollectionFactory) LocalRepoCollection() *LocalRepoCollection {
if factory.localRepos == nil {
factory.localRepos = NewLocalRepoCollection(factory.db)
}
return factory.localRepos
}
// PublishedRepoCollection returns (or creates) new PublishedRepoCollection
func (factory *CollectionFactory) PublishedRepoCollection() *PublishedRepoCollection {
if factory.publishedRepos == nil {
factory.publishedRepos = NewPublishedRepoCollection(factory.db)
}
return factory.publishedRepos
}
+1 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"archive/tar"
+1 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"github.com/smira/aptly/utils"
+2
View File
@@ -0,0 +1,2 @@
// Package deb implements Debian-specific repository handling
package deb
+1 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
. "launchpad.net/gocheck"
+1 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"bufio"
+1 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"bufio"
+4 -4
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"fmt"
@@ -63,9 +63,9 @@ func NewPackageListFromRefList(reflist *PackageRefList, collection *PackageColle
}
err := reflist.ForEach(func(key []byte) error {
p, err := collection.ByKey(key)
if err != nil {
return fmt.Errorf("unable to load package with key %s: %s", key, err)
p, err2 := collection.ByKey(key)
if err2 != nil {
return fmt.Errorf("unable to load package with key %s: %s", key, err2)
}
if progress != nil {
progress.AddBar(1)
+1 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"errors"
+5 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"bytes"
@@ -17,6 +17,10 @@ type LocalRepo struct {
Name string
// Comment
Comment string
// DefaultDistribution
DefaultDistribution string `codec:",omitempty"`
// DefaultComponent
DefaultComponent string `codec:",omitempty"`
// "Snapshot" of current list of packages
packageRefs *PackageRefList
}
+1 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"errors"
+9 -5
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"fmt"
@@ -388,16 +388,18 @@ func (p *Package) LinkFromPool(publishedStorage aptly.PublishedStorage, packageP
return err
}
relPath, err := publishedStorage.LinkFromPool(prefix, component, poolDir, packagePool, sourcePath)
relPath := filepath.Join("pool", component, poolDir)
publishedDirectory := filepath.Join(prefix, relPath)
err = publishedStorage.LinkFromPool(publishedDirectory, packagePool, sourcePath)
if err != nil {
return err
}
dir := filepath.Dir(relPath)
if p.IsSource {
p.Extra()["Directory"] = dir
p.Extra()["Directory"] = relPath
} else {
p.Files()[i].downloadPath = dir
p.Files()[i].downloadPath = relPath
}
}
@@ -409,6 +411,8 @@ func (p *Package) PoolDirectory() (string, error) {
source := p.Source
if source == "" {
source = p.Name
} else if pos := strings.Index(source, "("); pos != -1 {
source = strings.TrimSpace(source[:pos])
}
if len(source) < 2 {
@@ -1,4 +1,4 @@
package debian
package deb
import (
"bytes"
@@ -1,4 +1,4 @@
package debian
package deb
import (
"github.com/smira/aptly/database"
@@ -1,4 +1,4 @@
package debian
package deb
import (
"strings"
@@ -1,4 +1,4 @@
package debian
package deb
import (
"encoding/binary"
@@ -1,4 +1,4 @@
package debian
package deb
import (
"github.com/smira/aptly/files"
@@ -1,4 +1,4 @@
package debian
package deb
import (
"bytes"
@@ -230,6 +230,12 @@ func (s *PackageSuite) TestPoolDirectory(c *C) {
c.Check(err, IsNil)
c.Check(dir, Equals, "liba/libarena")
p = NewPackageFromControlFile(packageStanza.Copy())
p.Source = "gcc-defaults (1.77)"
dir, err = p.PoolDirectory()
c.Check(err, IsNil)
c.Check(dir, Equals, "g/gcc-defaults")
p = NewPackageFromControlFile(packageStanza.Copy())
p.Source = "l"
_, err = p.PoolDirectory()
+4 -4
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"fmt"
@@ -11,14 +11,14 @@ import (
var ppaRegexp = regexp.MustCompile("^ppa:([^/]+)/(.+)$")
// ParsePPA converts ppa URL like ppa:user/ppa-name to full HTTP url
func ParsePPA(ppaURL string) (url string, distribution string, components []string, err error) {
func ParsePPA(ppaURL string, config *utils.ConfigStructure) (url string, distribution string, components []string, err error) {
matches := ppaRegexp.FindStringSubmatch(ppaURL)
if matches == nil {
err = fmt.Errorf("unable to parse ppa URL: %v", ppaURL)
return
}
distributorID := utils.Config.PpaDistributorID
distributorID := config.PpaDistributorID
if distributorID == "" {
distributorID, err = getDistributorID()
if err != nil {
@@ -27,7 +27,7 @@ func ParsePPA(ppaURL string) (url string, distribution string, components []stri
}
}
codename := utils.Config.PpaCodename
codename := config.PpaCodename
if codename == "" {
codename, err = getCodename()
if err != nil {
+6 -14
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"github.com/smira/aptly/utils"
@@ -6,27 +6,19 @@ import (
)
type PpaSuite struct {
savedConfig utils.ConfigStructure
config utils.ConfigStructure
}
var _ = Suite(&PpaSuite{})
func (s *PpaSuite) SetUpTest(c *C) {
s.savedConfig = utils.Config
}
func (s *PpaSuite) TearDownTest(c *C) {
utils.Config = s.savedConfig
}
func (s *PpaSuite) TestParsePPA(c *C) {
_, _, _, err := ParsePPA("ppa:dedeed")
_, _, _, err := ParsePPA("ppa:dedeed", &s.config)
c.Check(err, ErrorMatches, "unable to parse ppa URL.*")
utils.Config.PpaDistributorID = "debian"
utils.Config.PpaCodename = "wheezy"
s.config.PpaDistributorID = "debian"
s.config.PpaCodename = "wheezy"
url, distribution, components, err := ParsePPA("ppa:user/project")
url, distribution, components, err := ParsePPA("ppa:user/project", &s.config)
c.Check(err, IsNil)
c.Check(url, Equals, "http://ppa.launchpad.net/user/project/debian")
c.Check(distribution, Equals, "wheezy")
+794
View File
@@ -0,0 +1,794 @@
package deb
import (
"bufio"
"bytes"
"code.google.com/p/go-uuid/uuid"
"fmt"
"github.com/smira/aptly/aptly"
"github.com/smira/aptly/database"
"github.com/smira/aptly/utils"
"github.com/ugorji/go/codec"
"log"
"os"
"path/filepath"
"sort"
"strings"
"time"
)
// 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
Component string
Origin string
Label string
// Architectures is a list of all architectures published
Architectures []string
// SourceKind is "local"/"repo"
SourceKind string
// SourceUUID is UUID of either snapshot or local repo
SourceUUID string `codec:"SnapshotUUID"`
// Pointer to snapshot if SourceKind == "snapshot"
snapshot *Snapshot
// Pointer to local repo if SourceKind == "local"
localRepo *LocalRepo
// Package references is SourceKind == "local"
packageRefs *PackageRefList
// True if repo is being re-published
rePublishing bool
}
// NewPublishedRepo creates new published repository
//
// prefix specifies publishing prefix
// distribution, component and architectures are user-defined properties
// source could either be *Snapshot or *LocalRepo
func NewPublishedRepo(prefix string, distribution string, component string, architectures []string, source interface{}, collectionFactory *CollectionFactory) (*PublishedRepo, error) {
var ok bool
result := &PublishedRepo{
UUID: uuid.New(),
Architectures: architectures,
}
// figure out source
result.snapshot, ok = source.(*Snapshot)
if ok {
result.SourceKind = "snapshot"
result.SourceUUID = result.snapshot.UUID
} else {
result.localRepo, ok = source.(*LocalRepo)
if ok {
result.SourceKind = "local"
result.SourceUUID = result.localRepo.UUID
result.packageRefs = result.localRepo.RefList()
} else {
panic("unknown source kind")
}
}
// clean & verify prefix
prefix = filepath.Clean(prefix)
if strings.HasPrefix(prefix, "/") {
prefix = prefix[1:]
}
if strings.HasSuffix(prefix, "/") {
prefix = prefix[:len(prefix)-1]
}
prefix = filepath.Clean(prefix)
for _, part := range strings.Split(prefix, "/") {
if part == ".." || part == "dists" || part == "pool" {
return nil, fmt.Errorf("invalid prefix %s", prefix)
}
}
result.Prefix = prefix
// guessing distribution & component
if component == "" || distribution == "" {
var (
head interface{}
current = []interface{}{source}
rootComponents = []string{}
rootDistributions = []string{}
)
// walk up the tree from current source up to roots (local or remote repos)
// and collect information about distribution and components
for len(current) > 0 {
head, current = current[0], current[1:]
if snapshot, ok := head.(*Snapshot); ok {
for _, uuid := range snapshot.SourceIDs {
if snapshot.SourceKind == "repo" {
remoteRepo, err := collectionFactory.RemoteRepoCollection().ByUUID(uuid)
if err != nil {
continue
}
current = append(current, remoteRepo)
} else if snapshot.SourceKind == "local" {
localRepo, err := collectionFactory.LocalRepoCollection().ByUUID(uuid)
if err != nil {
continue
}
current = append(current, localRepo)
} else if snapshot.SourceKind == "snapshot" {
snap, err := collectionFactory.SnapshotCollection().ByUUID(uuid)
if err != nil {
continue
}
current = append(current, snap)
}
}
} else if localRepo, ok := head.(*LocalRepo); ok {
if localRepo.DefaultDistribution != "" {
rootDistributions = append(rootDistributions, localRepo.DefaultDistribution)
}
if localRepo.DefaultComponent != "" {
rootComponents = append(rootComponents, localRepo.DefaultComponent)
}
} else if remoteRepo, ok := head.(*RemoteRepo); ok {
if remoteRepo.Distribution != "" {
rootDistributions = append(rootDistributions, remoteRepo.Distribution)
}
rootComponents = append(rootComponents, remoteRepo.Components...)
} else {
panic("unknown type")
}
}
if distribution == "" {
sort.Strings(rootDistributions)
if len(rootDistributions) > 0 && rootDistributions[0] == rootDistributions[len(rootDistributions)-1] {
distribution = rootDistributions[0]
} else {
return nil, fmt.Errorf("unable to guess distribution name, please specify explicitly")
}
}
if component == "" {
sort.Strings(rootComponents)
if len(rootComponents) > 0 && rootComponents[0] == rootComponents[len(rootComponents)-1] {
component = rootComponents[0]
} else {
component = "main"
}
}
}
result.Distribution, result.Component = distribution, component
return result, nil
}
// String returns human-readable represenation of PublishedRepo
func (p *PublishedRepo) String() string {
var source string
if p.snapshot != nil {
source = p.snapshot.String()
} else if p.localRepo != nil {
source = p.localRepo.String()
} else {
panic("no snapshot/localRepo")
}
var extra string
if p.Origin != "" {
extra += fmt.Sprintf(", origin: %s", p.Origin)
}
if p.Label != "" {
extra += fmt.Sprintf(", label: %s", p.Label)
}
return fmt.Sprintf("%s/%s (%s%s) [%s] publishes %s", p.Prefix, p.Distribution, p.Component, extra, strings.Join(p.Architectures, ", "), source)
}
// Key returns unique key identifying PublishedRepo
func (p *PublishedRepo) Key() []byte {
return []byte("U" + p.Prefix + ">>" + p.Distribution)
}
// RefKey is a unique id for package reference list
func (p *PublishedRepo) RefKey() []byte {
return []byte("E" + p.UUID)
}
// RefList returns list of package refs in local repo
func (p *PublishedRepo) RefList() *PackageRefList {
if p.SourceKind == "local" {
return p.packageRefs
}
if p.SourceKind == "snapshot" {
return p.snapshot.RefList()
}
panic("unknown source")
}
func (p *PublishedRepo) UpdateLocalRepo() {
if p.SourceKind != "local" {
panic("not local repo publish")
}
p.packageRefs = p.localRepo.RefList()
p.rePublishing = true
}
func (p *PublishedRepo) UpdateSnapshot(snapshot *Snapshot) {
if p.SourceKind != "snapshot" {
panic("not snapshot publish")
}
p.snapshot = snapshot
p.SourceUUID = snapshot.UUID
p.rePublishing = true
}
// 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{})
err := decoder.Decode(p)
if err != nil {
return err
}
// old PublishedRepo were publishing only snapshots
if p.SourceKind == "" {
p.SourceKind = "snapshot"
}
return nil
}
// Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them
func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorage aptly.PublishedStorage,
collectionFactory *CollectionFactory, signer utils.Signer, progress aptly.Progress) error {
err := publishedStorage.MkDir(filepath.Join(p.Prefix, "pool"))
if err != nil {
return err
}
basePath := filepath.Join(p.Prefix, "dists", p.Distribution)
err = publishedStorage.MkDir(basePath)
if err != nil {
return err
}
if progress != nil {
progress.Printf("Loading packages...\n")
}
// Load all packages
list, err := NewPackageListFromRefList(p.RefList(), collectionFactory.PackageCollection(), progress)
if err != nil {
return fmt.Errorf("unable to load packages: %s", err)
}
if list.Len() == 0 {
return fmt.Errorf("source is empty")
}
if !p.rePublishing {
if len(p.Architectures) == 0 {
p.Architectures = list.Architectures(true)
}
if len(p.Architectures) == 0 {
return fmt.Errorf("unable to figure out list of architectures, please supply explicit list")
}
sort.Strings(p.Architectures)
}
var suffix string
if p.rePublishing {
suffix = ".tmp"
}
generatedFiles := map[string]utils.ChecksumInfo{}
renameMap := map[string]string{}
if progress != nil {
progress.Printf("Generating metadata files and linking package files...\n")
}
// For all architectures, generate release file
for _, arch := range p.Architectures {
if progress != nil {
progress.InitBar(int64(list.Len()), false)
}
var relativePath string
if arch == "source" {
relativePath = filepath.Join(p.Component, "source", "Sources")
} else {
relativePath = filepath.Join(p.Component, fmt.Sprintf("binary-%s", arch), "Packages")
}
err = publishedStorage.MkDir(filepath.Dir(filepath.Join(basePath, relativePath)))
if err != nil {
return err
}
var packagesFile *os.File
packagesFile, err = publishedStorage.CreateFile(filepath.Join(basePath, relativePath+suffix))
if err != nil {
return fmt.Errorf("unable to creates Packages file: %s", err)
}
if suffix != "" {
renameMap[filepath.Join(basePath, relativePath+suffix)] = filepath.Join(basePath, relativePath)
}
bufWriter := bufio.NewWriter(packagesFile)
err = list.ForEach(func(pkg *Package) error {
if progress != nil {
progress.AddBar(1)
}
if pkg.MatchesArchitecture(arch) {
err = pkg.LinkFromPool(publishedStorage, packagePool, p.Prefix, p.Component)
if err != nil {
return err
}
err = pkg.Stanza().WriteTo(bufWriter)
if err != nil {
return err
}
err = bufWriter.WriteByte('\n')
if err != nil {
return err
}
pkg.files = nil
pkg.deps = nil
pkg.extra = nil
}
return nil
})
if err != nil {
return fmt.Errorf("unable to process packages: %s", err)
}
err = bufWriter.Flush()
if err != nil {
return fmt.Errorf("unable to write Packages file: %s", err)
}
err = utils.CompressFile(packagesFile)
if err != nil {
return fmt.Errorf("unable to compress Packages files: %s", err)
}
if suffix != "" {
renameMap[filepath.Join(basePath, relativePath+suffix+".gz")] = filepath.Join(basePath, relativePath+".gz")
renameMap[filepath.Join(basePath, relativePath+suffix+".bz2")] = filepath.Join(basePath, relativePath+".bz2")
}
packagesFile.Close()
var checksumInfo utils.ChecksumInfo
checksumInfo, err = publishedStorage.ChecksumsForFile(filepath.Join(basePath, relativePath+suffix))
if err != nil {
return fmt.Errorf("unable to collect checksums: %s", err)
}
generatedFiles[relativePath] = checksumInfo
checksumInfo, err = publishedStorage.ChecksumsForFile(filepath.Join(basePath, relativePath+suffix+".gz"))
if err != nil {
return fmt.Errorf("unable to collect checksums: %s", err)
}
generatedFiles[relativePath+".gz"] = checksumInfo
checksumInfo, err = publishedStorage.ChecksumsForFile(filepath.Join(basePath, relativePath+suffix+".bz2"))
if err != nil {
return fmt.Errorf("unable to collect checksums: %s", err)
}
generatedFiles[relativePath+".bz2"] = checksumInfo
if progress != nil {
progress.ShutdownBar()
}
}
release := make(Stanza)
if p.Origin == "" {
release["Origin"] = p.Prefix + " " + p.Distribution
} else {
release["Origin"] = p.Origin
}
if p.Label == "" {
release["Label"] = p.Prefix + " " + p.Distribution
} else {
release["Label"] = p.Label
}
release["Codename"] = p.Distribution
release["Date"] = time.Now().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST")
release["Components"] = p.Component
release["Architectures"] = strings.Join(utils.StrSlicesSubstract(p.Architectures, []string{"source"}), " ")
release["Description"] = " Generated by aptly\n"
release["MD5Sum"] = "\n"
release["SHA1"] = "\n"
release["SHA256"] = "\n"
for path, info := range generatedFiles {
release["MD5Sum"] += fmt.Sprintf(" %s %8d %s\n", info.MD5, info.Size, path)
release["SHA1"] += fmt.Sprintf(" %s %8d %s\n", info.SHA1, info.Size, path)
release["SHA256"] += fmt.Sprintf(" %s %8d %s\n", info.SHA256, info.Size, path)
}
releaseFile, err := publishedStorage.CreateFile(filepath.Join(basePath, "Release"+suffix))
if err != nil {
return fmt.Errorf("unable to create Release file: %s", err)
}
if suffix != "" {
renameMap[filepath.Join(basePath, "Release"+suffix)] = filepath.Join(basePath, "Release")
}
bufWriter := bufio.NewWriter(releaseFile)
err = release.WriteTo(bufWriter)
if err != nil {
return fmt.Errorf("unable to create Release file: %s", err)
}
err = bufWriter.Flush()
if err != nil {
return fmt.Errorf("unable to create Release file: %s", err)
}
releaseFilename := releaseFile.Name()
releaseFile.Close()
// Signing files might output to console, so flush progress writer first
if progress != nil {
progress.Flush()
}
if signer != nil {
err = signer.DetachedSign(releaseFilename, releaseFilename+".gpg")
if err != nil {
return fmt.Errorf("unable to sign Release file: %s", err)
}
err = signer.ClearSign(releaseFilename, filepath.Join(filepath.Dir(releaseFilename), "InRelease"+suffix))
if err != nil {
return fmt.Errorf("unable to sign Release file: %s", err)
}
if suffix != "" {
renameMap[filepath.Join(basePath, "Release"+suffix+".gpg")] = filepath.Join(basePath, "Release.gpg")
renameMap[filepath.Join(basePath, "InRelease"+suffix)] = filepath.Join(basePath, "InRelease")
}
}
for oldName, newName := range renameMap {
err = publishedStorage.RenameFile(oldName, newName)
if err != nil {
return fmt.Errorf("unable to rename: %s", err)
}
}
return nil
}
// RemoveFiles removes files that were created by Publish
//
// It can remove prefix fully, and part of pool (for specific component)
func (p *PublishedRepo) RemoveFiles(publishedStorage aptly.PublishedStorage, removePrefix, removePoolComponent bool, progress aptly.Progress) error {
// I. Easy: remove whole prefix (meta+packages)
if removePrefix {
err := publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "dists"), progress)
if err != nil {
return err
}
return publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "pool"), progress)
}
// II. Medium: remove metadata, it can't be shared as prefix/distribution as unique
err := publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "dists", p.Distribution), progress)
if err != nil {
return err
}
// III. Complex: there are no other publishes with the same prefix + component
if removePoolComponent {
err = publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "pool", p.Component), progress)
if err != nil {
return err
}
} else {
/// IV: Hard: should have removed published files from the pool + component
/// that are unique to this published repo
}
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) (err error) {
err = collection.db.Put(repo.Key(), repo.Encode())
if err != nil {
return
}
if repo.SourceKind == "local" {
err = collection.db.Put(repo.RefKey(), repo.packageRefs.Encode())
}
return
}
// LoadComplete loads additional information for remote repo
func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, collectionFactory *CollectionFactory) (err error) {
if repo.SourceKind == "snapshot" {
repo.snapshot, err = collectionFactory.SnapshotCollection().ByUUID(repo.SourceUUID)
if err != nil {
return
}
err = collectionFactory.SnapshotCollection().LoadComplete(repo.snapshot)
} else if repo.SourceKind == "local" {
repo.localRepo, err = collectionFactory.LocalRepoCollection().ByUUID(repo.SourceUUID)
if err != nil {
return
}
err = collectionFactory.LocalRepoCollection().LoadComplete(repo.localRepo)
if err != nil {
return
}
var encoded []byte
encoded, err = collection.db.Get(repo.RefKey())
if err != nil {
return err
}
repo.packageRefs = &PackageRefList{}
err = repo.packageRefs.Decode(encoded)
} else {
panic("unknown SourceKind")
}
return err
}
// 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)
}
// BySnapshot looks up repository by snapshot source
func (collection *PublishedRepoCollection) BySnapshot(snapshot *Snapshot) []*PublishedRepo {
result := make([]*PublishedRepo, 0)
for _, r := range collection.list {
if r.SourceKind == "snapshot" && r.SourceUUID == snapshot.UUID {
result = append(result, r)
}
}
return result
}
// ByLocalRepo looks up repository by local repo source
func (collection *PublishedRepoCollection) ByLocalRepo(repo *LocalRepo) []*PublishedRepo {
result := make([]*PublishedRepo, 0)
for _, r := range collection.list {
if r.SourceKind == "local" && r.SourceUUID == repo.UUID {
result = append(result, r)
}
}
return result
}
// 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)
}
// CleanupPrefixComponentFiles removes all unreferenced files in published storage under prefix/component pair
func (collection *PublishedRepoCollection) CleanupPrefixComponentFiles(prefix, component string,
publishedStorage aptly.PublishedStorage, collectionFactory *CollectionFactory, progress aptly.Progress) error {
var err error
referencedFiles := []string{}
if progress != nil {
progress.Printf("Cleaning up prefix %#v component %#v...\n", prefix, component)
}
for _, r := range collection.list {
if r.Prefix == prefix && r.Component == component {
err = collection.LoadComplete(r, collectionFactory)
if err != nil {
return err
}
packageList, err := NewPackageListFromRefList(r.RefList(), collectionFactory.PackageCollection(), progress)
if err != nil {
return err
}
packageList.ForEach(func(p *Package) error {
poolDir, err := p.PoolDirectory()
if err != nil {
return err
}
for _, f := range p.Files() {
referencedFiles = append(referencedFiles, filepath.Join(poolDir, f.Filename))
}
return nil
})
}
}
sort.Strings(referencedFiles)
rootPath := filepath.Join(prefix, "pool", component)
existingFiles, err := publishedStorage.Filelist(rootPath)
if err != nil {
return err
}
sort.Strings(existingFiles)
filesToDelete := utils.StrSlicesSubstract(existingFiles, referencedFiles)
for _, file := range filesToDelete {
err = publishedStorage.Remove(filepath.Join(rootPath, file))
if err != nil {
return err
}
}
return nil
}
// Remove removes published repository, cleaning up directories, files
func (collection *PublishedRepoCollection) Remove(publishedStorage aptly.PublishedStorage, prefix, distribution string,
collectionFactory *CollectionFactory, progress aptly.Progress) error {
repo, err := collection.ByPrefixDistribution(prefix, distribution)
if err != nil {
return err
}
removePrefix := true
removePoolComponent := true
repoPosition := -1
for i, r := range collection.list {
if r == repo {
repoPosition = i
continue
}
if r.Prefix == repo.Prefix {
removePrefix = false
if r.Component == repo.Component {
removePoolComponent = false
}
}
}
err = repo.RemoveFiles(publishedStorage, removePrefix, removePoolComponent, progress)
if err != nil {
return err
}
collection.list[len(collection.list)-1], collection.list[repoPosition], collection.list =
nil, collection.list[len(collection.list)-1], collection.list[:len(collection.list)-1]
if !removePrefix && !removePoolComponent {
err = collection.CleanupPrefixComponentFiles(repo.Prefix, repo.Component, publishedStorage, collectionFactory, progress)
if err != nil {
return err
}
}
err = collection.db.Delete(repo.Key())
if err != nil {
return err
}
return collection.db.Delete(repo.RefKey())
}
+154 -40
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"errors"
@@ -45,12 +45,14 @@ func (n *NullSigner) ClearSign(source string, destination string) error {
type PublishedRepoSuite struct {
PackageListMixinSuite
repo *PublishedRepo
repo, repo2 *PublishedRepo
root string
publishedStorage aptly.PublishedStorage
packagePool aptly.PackagePool
localRepo *LocalRepo
snapshot *Snapshot
db database.Storage
factory *CollectionFactory
packageCollection *PackageCollection
}
@@ -60,6 +62,7 @@ func (s *PublishedRepoSuite) SetUpTest(c *C) {
s.SetUpPackages()
s.db, _ = database.OpenDB(c.MkDir())
s.factory = NewCollectionFactory(s.db)
s.root = c.MkDir()
s.publishedStorage = files.NewPublishedStorage(s.root)
@@ -67,16 +70,24 @@ func (s *PublishedRepoSuite) SetUpTest(c *C) {
repo, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{}, false)
repo.packageRefs = s.reflist
s.factory.RemoteRepoCollection().Add(repo)
s.localRepo = NewLocalRepo("local1", "comment1")
s.localRepo.packageRefs = s.reflist
s.factory.LocalRepoCollection().Add(s.localRepo)
s.snapshot, _ = NewSnapshotFromRepository("snap", repo)
s.factory.SnapshotCollection().Add(s.snapshot)
s.repo, _ = NewPublishedRepo("ppa", "squeeze", "main", nil, s.snapshot)
s.packageCollection = NewPackageCollection(s.db)
s.packageCollection = s.factory.PackageCollection()
s.packageCollection.Update(s.p1)
s.packageCollection.Update(s.p2)
s.packageCollection.Update(s.p3)
s.repo, _ = NewPublishedRepo("ppa", "squeeze", "main", nil, s.snapshot, s.factory)
s.repo2, _ = NewPublishedRepo("ppa", "maverick", "main", nil, s.localRepo, s.factory)
poolPath, _ := s.packagePool.Path(s.p1.Files()[0].Filename, s.p1.Files()[0].Checksums.MD5)
err := os.MkdirAll(filepath.Dir(poolPath), 0755)
f, err := os.Create(poolPath)
@@ -88,6 +99,20 @@ func (s *PublishedRepoSuite) TearDownTest(c *C) {
s.db.Close()
}
func (s *PublishedRepoSuite) TestNewPublishedRepo(c *C) {
c.Check(s.repo.snapshot, Equals, s.snapshot)
c.Check(s.repo.SourceKind, Equals, "snapshot")
c.Check(s.repo.SourceUUID, Equals, s.snapshot.UUID)
c.Check(s.repo2.localRepo, Equals, s.localRepo)
c.Check(s.repo2.SourceKind, Equals, "local")
c.Check(s.repo2.SourceUUID, Equals, s.localRepo.UUID)
c.Check(s.repo2.packageRefs.Len(), Equals, 3)
c.Check(s.repo.RefList().Len(), Equals, 3)
c.Check(s.repo2.RefList().Len(), Equals, 3)
}
func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) {
for _, t := range []struct {
@@ -144,7 +169,7 @@ func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) {
errorExpected: "invalid prefix .*",
},
} {
repo, err := NewPublishedRepo(t.prefix, "squeeze", "main", nil, s.snapshot)
repo, err := NewPublishedRepo(t.prefix, "squeeze", "main", nil, s.snapshot, s.factory)
if t.errorExpected != "" {
c.Check(err, ErrorMatches, t.errorExpected)
} else {
@@ -153,8 +178,42 @@ func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) {
}
}
func (s *PublishedRepoSuite) TestDistributionComponentGuessing(c *C) {
repo, err := NewPublishedRepo("ppa", "", "", nil, s.snapshot, s.factory)
c.Check(err, IsNil)
c.Check(repo.Distribution, Equals, "squeeze")
c.Check(repo.Component, Equals, "main")
repo, err = NewPublishedRepo("ppa", "wheezy", "", nil, s.snapshot, s.factory)
c.Check(err, IsNil)
c.Check(repo.Distribution, Equals, "wheezy")
c.Check(repo.Component, Equals, "main")
repo, err = NewPublishedRepo("ppa", "", "non-free", nil, s.snapshot, s.factory)
c.Check(err, IsNil)
c.Check(repo.Distribution, Equals, "squeeze")
c.Check(repo.Component, Equals, "non-free")
repo, err = NewPublishedRepo("ppa", "squeeze", "", nil, s.localRepo, s.factory)
c.Check(err, IsNil)
c.Check(repo.Distribution, Equals, "squeeze")
c.Check(repo.Component, Equals, "main")
repo, err = NewPublishedRepo("ppa", "", "main", nil, s.localRepo, s.factory)
c.Check(err, ErrorMatches, "unable to guess distribution name, please specify explicitly")
s.localRepo.DefaultDistribution = "precise"
s.localRepo.DefaultComponent = "contrib"
s.factory.LocalRepoCollection().Update(s.localRepo)
repo, err = NewPublishedRepo("ppa", "", "", nil, s.localRepo, s.factory)
c.Check(err, IsNil)
c.Check(repo.Distribution, Equals, "precise")
c.Check(repo.Component, Equals, "contrib")
}
func (s *PublishedRepoSuite) TestPublish(c *C) {
err := s.repo.Publish(s.packagePool, s.publishedStorage, s.packageCollection, &NullSigner{}, nil)
err := s.repo.Publish(s.packagePool, s.publishedStorage, s.factory, &NullSigner{}, nil)
c.Assert(err, IsNil)
c.Check(s.repo.Architectures, DeepEquals, []string{"i386"})
@@ -191,27 +250,46 @@ func (s *PublishedRepoSuite) TestPublish(c *C) {
}
func (s *PublishedRepoSuite) TestPublishNoSigner(c *C) {
err := s.repo.Publish(s.packagePool, s.publishedStorage, s.packageCollection, nil, nil)
err := s.repo.Publish(s.packagePool, s.publishedStorage, s.factory, nil, nil)
c.Assert(err, IsNil)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/squeeze/Release"), PathExists)
}
func (s *PublishedRepoSuite) TestPublishLocalRepo(c *C) {
err := s.repo2.Publish(s.packagePool, s.publishedStorage, s.factory, nil, nil)
c.Assert(err, IsNil)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/maverick/Release"), PathExists)
}
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")
repo, _ := NewPublishedRepo("", "squeeze", "main", nil, s.snapshot)
"ppa/squeeze (main) [] publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
c.Check(s.repo2.String(), Equals,
"ppa/maverick (main) [] publishes [local1]: comment1")
repo, _ := NewPublishedRepo("", "squeeze", "main", []string{"s390"}, s.snapshot, s.factory)
c.Check(repo.String(), Equals,
"./squeeze (main) publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
repo, _ = NewPublishedRepo("", "squeeze", "main", []string{"i386", "amd64"}, s.snapshot)
"./squeeze (main) [s390] publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
repo, _ = NewPublishedRepo("", "squeeze", "main", []string{"i386", "amd64"}, s.snapshot, s.factory)
c.Check(repo.String(), Equals,
"./squeeze (main) [i386, amd64] publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
repo.Origin = "myorigin"
c.Check(repo.String(), Equals,
"./squeeze (main, origin: myorigin) [i386, amd64] publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
repo.Label = "mylabel"
c.Check(repo.String(), Equals,
"./squeeze (main, origin: myorigin, label: mylabel) [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) TestRefKey(c *C) {
c.Check(s.repo.RefKey(), DeepEquals, []byte("E"+s.repo.UUID))
}
func (s *PublishedRepoSuite) TestEncodeDecode(c *C) {
encoded := s.repo.Encode()
repo := &PublishedRepo{}
@@ -220,23 +298,35 @@ func (s *PublishedRepoSuite) TestEncodeDecode(c *C) {
s.repo.snapshot = nil
c.Assert(err, IsNil)
c.Assert(repo, DeepEquals, s.repo)
encoded2 := s.repo2.Encode()
repo2 := &PublishedRepo{}
err = repo2.Decode(encoded2)
s.repo2.localRepo = nil
s.repo2.packageRefs = nil
c.Assert(err, IsNil)
c.Assert(repo2, DeepEquals, s.repo2)
}
type PublishedRepoCollectionSuite struct {
PackageListMixinSuite
db database.Storage
snapshotCollection *SnapshotCollection
collection *PublishedRepoCollection
snap1, snap2 *Snapshot
repo1, repo2, repo3 *PublishedRepo
db database.Storage
factory *CollectionFactory
snapshotCollection *SnapshotCollection
collection *PublishedRepoCollection
snap1, snap2 *Snapshot
localRepo *LocalRepo
repo1, repo2, repo3, repo4 *PublishedRepo
}
var _ = Suite(&PublishedRepoCollectionSuite{})
func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) {
s.db, _ = database.OpenDB(c.MkDir())
s.factory = NewCollectionFactory(s.db)
s.snapshotCollection = NewSnapshotCollection(s.db)
s.snapshotCollection = s.factory.SnapshotCollection()
s.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1")
s.snap2 = NewSnapshotFromPackageList("snap2", []*Snapshot{}, NewPackageList(), "desc2")
@@ -244,11 +334,15 @@ func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) {
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.localRepo = NewLocalRepo("local1", "comment1")
s.factory.LocalRepoCollection().Add(s.localRepo)
s.collection = NewPublishedRepoCollection(s.db)
s.repo1, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap1, s.factory)
s.repo2, _ = NewPublishedRepo("", "anaconda", "main", []string{}, s.snap2, s.factory)
s.repo3, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap2, s.factory)
s.repo4, _ = NewPublishedRepo("ppa", "precise", "main", []string{}, s.localRepo, s.factory)
s.collection = s.factory.PublishedRepoCollection()
}
func (s *PublishedRepoCollectionSuite) TearDownTest(c *C) {
@@ -265,11 +359,12 @@ func (s *PublishedRepoCollectionSuite) TestAddByPrefixDistribution(c *C) {
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)
c.Assert(s.collection.Add(s.repo4), IsNil)
r, err = s.collection.ByPrefixDistribution("ppa", "anaconda")
c.Assert(err, IsNil)
err = s.collection.LoadComplete(r, s.snapshotCollection)
err = s.collection.LoadComplete(r, s.factory)
c.Assert(err, IsNil)
c.Assert(r.String(), Equals, s.repo1.String())
@@ -277,7 +372,7 @@ func (s *PublishedRepoCollectionSuite) TestAddByPrefixDistribution(c *C) {
r, err = collection.ByPrefixDistribution("ppa", "anaconda")
c.Assert(err, IsNil)
err = s.collection.LoadComplete(r, s.snapshotCollection)
err = s.collection.LoadComplete(r, s.factory)
c.Assert(err, IsNil)
c.Assert(r.String(), Equals, s.repo1.String())
}
@@ -291,20 +386,30 @@ func (s *PublishedRepoCollectionSuite) TestByUUID(c *C) {
r, err = s.collection.ByUUID(s.repo1.UUID)
c.Assert(err, IsNil)
err = s.collection.LoadComplete(r, s.snapshotCollection)
err = s.collection.LoadComplete(r, s.factory)
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)
c.Assert(s.collection.Update(s.repo4), 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(s.collection.LoadComplete(r, s.factory), IsNil)
c.Assert(r.snapshot.UUID, Equals, s.repo1.snapshot.UUID)
c.Assert(r.RefList().Len(), Equals, 0)
r, err = collection.ByPrefixDistribution("ppa", "precise")
c.Assert(err, IsNil)
c.Assert(r.localRepo, IsNil)
c.Assert(s.collection.LoadComplete(r, s.factory), IsNil)
c.Assert(r.localRepo.UUID, Equals, s.repo4.localRepo.UUID)
c.Assert(r.packageRefs.Len(), Equals, 0)
c.Assert(r.RefList().Len(), Equals, 0)
}
func (s *PublishedRepoCollectionSuite) TestForEachAndLen(c *C) {
@@ -336,9 +441,17 @@ func (s *PublishedRepoCollectionSuite) TestBySnapshot(c *C) {
c.Check(s.collection.BySnapshot(s.snap2), DeepEquals, []*PublishedRepo{s.repo2})
}
func (s *PublishedRepoCollectionSuite) TestByLocalRepo(c *C) {
c.Check(s.collection.Add(s.repo1), IsNil)
c.Check(s.collection.Add(s.repo4), IsNil)
c.Check(s.collection.ByLocalRepo(s.localRepo), DeepEquals, []*PublishedRepo{s.repo4})
}
type PublishedRepoRemoveSuite struct {
PackageListMixinSuite
db database.Storage
factory *CollectionFactory
snapshotCollection *SnapshotCollection
collection *PublishedRepoCollection
root string
@@ -351,19 +464,20 @@ var _ = Suite(&PublishedRepoRemoveSuite{})
func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) {
s.db, _ = database.OpenDB(c.MkDir())
s.factory = NewCollectionFactory(s.db)
s.snapshotCollection = NewSnapshotCollection(s.db)
s.snapshotCollection = s.factory.SnapshotCollection()
s.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1")
s.snapshotCollection.Add(s.snap1)
s.repo1, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap1)
s.repo2, _ = NewPublishedRepo("", "anaconda", "main", []string{}, s.snap1)
s.repo3, _ = NewPublishedRepo("ppa", "meduza", "main", []string{}, s.snap1)
s.repo4, _ = NewPublishedRepo("ppa", "osminog", "contrib", []string{}, s.snap1)
s.repo1, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap1, s.factory)
s.repo2, _ = NewPublishedRepo("", "anaconda", "main", []string{}, s.snap1, s.factory)
s.repo3, _ = NewPublishedRepo("ppa", "meduza", "main", []string{}, s.snap1, s.factory)
s.repo4, _ = NewPublishedRepo("ppa", "osminog", "contrib", []string{}, s.snap1, s.factory)
s.collection = NewPublishedRepoCollection(s.db)
s.collection = s.factory.PublishedRepoCollection()
s.collection.Add(s.repo1)
s.collection.Add(s.repo2)
s.collection.Add(s.repo3)
@@ -385,7 +499,7 @@ func (s *PublishedRepoRemoveSuite) TearDownTest(c *C) {
}
func (s *PublishedRepoRemoveSuite) TestRemoveFilesOnlyDist(c *C) {
s.repo1.RemoveFiles(s.publishedStorage, false, false)
s.repo1.RemoveFiles(s.publishedStorage, false, false, nil)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
@@ -397,7 +511,7 @@ func (s *PublishedRepoRemoveSuite) TestRemoveFilesOnlyDist(c *C) {
}
func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPool(c *C) {
s.repo1.RemoveFiles(s.publishedStorage, false, true)
s.repo1.RemoveFiles(s.publishedStorage, false, true, nil)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
@@ -409,7 +523,7 @@ func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPool(c *C) {
}
func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPrefix(c *C) {
s.repo1.RemoveFiles(s.publishedStorage, true, true)
s.repo1.RemoveFiles(s.publishedStorage, true, true, nil)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), Not(PathExists))
@@ -421,7 +535,7 @@ func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPrefix(c *C) {
}
func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPrefixRoot(c *C) {
s.repo2.RemoveFiles(s.publishedStorage, true, true)
s.repo2.RemoveFiles(s.publishedStorage, true, true, nil)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
@@ -432,7 +546,7 @@ func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPrefixRoot(c *C) {
}
func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2(c *C) {
err := s.collection.Remove(s.publishedStorage, "ppa", "anaconda")
err := s.collection.Remove(s.publishedStorage, "ppa", "anaconda", s.factory, nil)
c.Check(err, IsNil)
_, err = s.collection.ByPrefixDistribution("ppa", "anaconda")
@@ -450,10 +564,10 @@ func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2(c *C) {
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
err = s.collection.Remove(s.publishedStorage, "ppa", "anaconda")
err = s.collection.Remove(s.publishedStorage, "ppa", "anaconda", s.factory, nil)
c.Check(err, ErrorMatches, ".*not found")
err = s.collection.Remove(s.publishedStorage, "ppa", "meduza")
err = s.collection.Remove(s.publishedStorage, "ppa", "meduza", s.factory, nil)
c.Check(err, IsNil)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
@@ -466,7 +580,7 @@ func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2(c *C) {
}
func (s *PublishedRepoRemoveSuite) TestRemoveRepo3(c *C) {
err := s.collection.Remove(s.publishedStorage, ".", "anaconda")
err := s.collection.Remove(s.publishedStorage, ".", "anaconda", s.factory, nil)
c.Check(err, IsNil)
_, err = s.collection.ByPrefixDistribution(".", "anaconda")
+58 -5
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"bytes"
@@ -219,9 +219,12 @@ func (l *PackageRefList) Diff(r *PackageRefList, packageCollection *PackageColle
return
}
// Merge merges reflist r into current reflist. If overrideMatching, merge replaces matching packages (by architecture/name)
// with reference from r, otherwise all packages are saved.
// Merge merges reflist r into current reflist. If overrideMatching, merge
// replaces matching packages (by architecture/name) with reference from r.
// Otherwise, all packages are saved.
func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching bool) (result *PackageRefList) {
var overriddenArch, overridenName []byte
// pointer to left and right reflists
il, ir := 0, 0
// length of reflists
@@ -253,6 +256,8 @@ func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching bool) (result
result.Refs = append(result.Refs, l.Refs[il])
il++
ir++
overridenName = nil
overriddenArch = nil
} else {
if overrideMatching {
partsL := bytes.Split(rl, []byte(" "))
@@ -261,11 +266,19 @@ func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching bool) (result
partsR := bytes.Split(rr, []byte(" "))
archR, nameR := partsR[0][1:], partsR[1]
if bytes.Compare(archL, archR) == 0 && bytes.Compare(nameL, nameR) == 0 {
if bytes.Equal(archL, overriddenArch) && bytes.Equal(nameL, overridenName) {
// this package has already been overriden on the right
il++
continue
}
if bytes.Equal(archL, archR) && bytes.Equal(nameL, nameR) {
// override with package from the right
result.Refs = append(result.Refs, r.Refs[ir])
il++
ir++
overriddenArch = archL
overridenName = nameL
continue
}
}
@@ -277,10 +290,50 @@ func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching bool) (result
} else {
result.Refs = append(result.Refs, r.Refs[ir])
ir++
overridenName = nil
overriddenArch = nil
}
}
}
return
}
// FilterLatestRefs takes in a reflist with potentially multiples of the same
// packages and reduces it to only the latest of each package. The operations
// are done in-place. This implements a "latest wins" approach which can be used
// while merging two or more snapshots together.
func FilterLatestRefs(r *PackageRefList) {
var (
lastArch, lastName, lastVer []byte
arch, name, ver []byte
parts [][]byte
)
for i := 0; i < len(r.Refs); i++ {
parts = bytes.Split(r.Refs[i][1:], []byte(" "))
arch, name, ver = parts[0], parts[1], parts[2]
if bytes.Equal(arch, lastArch) && bytes.Equal(name, lastName) {
// Two packages are identical, check version and only one wins
vres := CompareVersions(string(ver), string(lastVer))
// Remove the older refs from the result
if vres > 0 {
// ver[i] > ver[i-1], remove element i-1
r.Refs = append(r.Refs[:i-1], r.Refs[i:]...)
} else {
// ver[i] < ver[i-1], remove element i
r.Refs = append(r.Refs[:i], r.Refs[i+1:]...)
arch, name, ver = lastArch, lastName, lastVer
}
// Compensate for the reduced set
i -= 1
}
lastArch, lastName, lastVer = arch, name, ver
}
return
}
+38 -9
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"errors"
@@ -14,6 +14,14 @@ type PackageRefListSuite struct {
var _ = Suite(&PackageRefListSuite{})
func toStrSlice(reflist *PackageRefList) (result []string) {
result = make([]string, reflist.Len())
for i, r := range reflist.Refs {
result[i] = string(r)
}
return
}
func (s *PackageRefListSuite) SetUpTest(c *C) {
s.list = NewPackageList()
@@ -250,14 +258,6 @@ func (s *PackageRefListSuite) TestMerge(c *C) {
reflistA := NewPackageRefListFromPackageList(listA)
reflistB := NewPackageRefListFromPackageList(listB)
toStrSlice := func(reflist *PackageRefList) (result []string) {
result = make([]string, reflist.Len())
for i, r := range reflist.Refs {
result[i] = string(r)
}
return
}
mergeAB := reflistA.Merge(reflistB, true)
mergeBA := reflistB.Merge(reflistA, true)
@@ -273,3 +273,32 @@ func (s *PackageRefListSuite) TestMerge(c *C) {
c.Check(toStrSlice(mergeBAall), DeepEquals,
[]string{"Pall data 1.1~bp1", "Pamd64 app 1.1~bp2", "Pi386 app 1.1~bp1", "Pi386 app 1.1~bp2", "Pi386 dpkg 1.0", "Pi386 dpkg 1.7", "Pi386 lib 1.0", "Psparc xyz 1.0"})
}
func (s *PackageRefListSuite) TestFilterLatestRefs(c *C) {
packages := []*Package{
&Package{Name: "lib", Version: "1.0", Architecture: "i386"},
&Package{Name: "lib", Version: "1.2~bp1", Architecture: "i386"},
&Package{Name: "lib", Version: "1.2", Architecture: "i386"},
&Package{Name: "dpkg", Version: "1.2", Architecture: "i386"},
&Package{Name: "dpkg", Version: "1.3", Architecture: "i386"},
&Package{Name: "dpkg", Version: "1.3~bp2", Architecture: "i386"},
&Package{Name: "dpkg", Version: "1.5", Architecture: "i386"},
&Package{Name: "dpkg", Version: "1.6", Architecture: "i386"},
}
rl := NewPackageList()
rl.Add(packages[0])
rl.Add(packages[1])
rl.Add(packages[2])
rl.Add(packages[3])
rl.Add(packages[4])
rl.Add(packages[5])
rl.Add(packages[6])
rl.Add(packages[7])
result := NewPackageRefListFromPackageList(rl)
FilterLatestRefs(result)
c.Check(toStrSlice(result), DeepEquals,
[]string{"Pi386 dpkg 1.6", "Pi386 lib 1.2"})
}
+24 -18
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"bytes"
@@ -13,6 +13,7 @@ import (
"net/url"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"time"
@@ -66,9 +67,11 @@ func NewRemoteRepo(name string, archiveRoot string, distribution string, compone
return nil, err
}
if result.Distribution == "." || result.Distribution == "./" {
if strings.HasSuffix(result.Distribution, "/") || strings.HasPrefix(result.Distribution, ".") {
// flat repo
result.Distribution = ""
if !strings.HasPrefix(result.Distribution, ".") {
result.Distribution = "./" + result.Distribution
}
result.Architectures = nil
if len(result.Components) > 0 {
return nil, fmt.Errorf("components aren't supported for flat repos")
@@ -106,7 +109,9 @@ func (repo *RemoteRepo) String() string {
// IsFlat determines if repository is flat
func (repo *RemoteRepo) IsFlat() bool {
return repo.Distribution == ""
// aptly < 0.5.1 had Distribution = "" for flat repos
// aptly >= 0.5.1 had Distribution = "./[path]/" for flat repos
return repo.Distribution == "" || (strings.HasPrefix(repo.Distribution, ".") && strings.HasSuffix(repo.Distribution, "/"))
}
// NumPackages return number of packages retrived from remote repo
@@ -129,7 +134,7 @@ func (repo *RemoteRepo) ReleaseURL(name string) *url.URL {
if !repo.IsFlat() {
path = &url.URL{Path: fmt.Sprintf("dists/%s/%s", repo.Distribution, name)}
} else {
path = &url.URL{Path: name}
path = &url.URL{Path: filepath.Join(repo.Distribution, name)}
}
return repo.archiveRootURL.ResolveReference(path)
@@ -137,13 +142,13 @@ func (repo *RemoteRepo) ReleaseURL(name string) *url.URL {
// FlatBinaryURL returns URL to Packages files for flat repo
func (repo *RemoteRepo) FlatBinaryURL() *url.URL {
path := &url.URL{Path: "Packages"}
path := &url.URL{Path: filepath.Join(repo.Distribution, "Packages")}
return repo.archiveRootURL.ResolveReference(path)
}
// FlatSourcesURL returns URL to Sources files for flat repo
func (repo *RemoteRepo) FlatSourcesURL() *url.URL {
path := &url.URL{Path: "Sources"}
path := &url.URL{Path: filepath.Join(repo.Distribution, "Sources")}
return repo.archiveRootURL.ResolveReference(path)
}
@@ -170,8 +175,8 @@ func (repo *RemoteRepo) PackageURL(filename string) *url.URL {
// Fetch updates information about repository
func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier utils.Verifier) error {
var (
release *os.File
err error
release, inrelease, releasesig *os.File
err error
)
if verifier == nil {
@@ -182,7 +187,7 @@ func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier utils.Verifier) error
}
} else {
// 1. try InRelease file
inrelease, err := http.DownloadTemp(d, repo.ReleaseURL("InRelease").String())
inrelease, err = http.DownloadTemp(d, repo.ReleaseURL("InRelease").String())
if err != nil {
goto splitsignature
}
@@ -209,7 +214,7 @@ func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier utils.Verifier) error
return err
}
releasesig, err := http.DownloadTemp(d, repo.ReleaseURL("Release.gpg").String())
releasesig, err = http.DownloadTemp(d, repo.ReleaseURL("Release.gpg").String())
if err != nil {
return err
}
@@ -275,7 +280,8 @@ ok:
return fmt.Errorf("unparseable hash sum line: %#v", line)
}
size, err := strconv.ParseInt(parts[1], 10, 64)
var size int64
size, err = strconv.ParseInt(parts[1], 10, 64)
if err != nil {
return fmt.Errorf("unable to parse size: %s", err)
}
@@ -314,7 +320,7 @@ ok:
}
// Download downloads all repo files
func (repo *RemoteRepo) Download(progress aptly.Progress, d aptly.Downloader, packageCollection *PackageCollection, packagePool aptly.PackagePool, ignoreMismatch bool) error {
func (repo *RemoteRepo) Download(progress aptly.Progress, d aptly.Downloader, collectionFactory *CollectionFactory, packagePool aptly.PackagePool, ignoreMismatch bool) error {
list := NewPackageList()
progress.Printf("Downloading & parsing package files...\n")
@@ -378,7 +384,7 @@ func (repo *RemoteRepo) Download(progress aptly.Progress, d aptly.Downloader, pa
return err
}
err = packageCollection.Update(p)
err = collectionFactory.PackageCollection().Update(p)
if err != nil {
return err
}
@@ -395,9 +401,9 @@ func (repo *RemoteRepo) Download(progress aptly.Progress, d aptly.Downloader, pa
downloadSize := int64(0)
err := list.ForEach(func(p *Package) error {
list, err := p.DownloadList(packagePool)
if err != nil {
return err
list, err2 := p.DownloadList(packagePool)
if err2 != nil {
return err2
}
p.files = nil
@@ -421,7 +427,7 @@ func (repo *RemoteRepo) Download(progress aptly.Progress, d aptly.Downloader, pa
// free up package list, we don't need it after this point
list = nil
progress.Printf("Download queue: %d items, %.2f GiB size\n", count, float64(downloadSize)/(1024.0*1024.0*1024.0))
progress.Printf("Download queue: %d items (%s)\n", count, utils.HumanBytes(downloadSize))
progress.InitBar(downloadSize, true)
+19 -14
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"errors"
@@ -72,7 +72,7 @@ type RemoteRepoSuite struct {
downloader *http.FakeDownloader
progress aptly.Progress
db database.Storage
packageCollection *PackageCollection
collectionFactory *CollectionFactory
packagePool aptly.PackagePool
}
@@ -84,7 +84,7 @@ func (s *RemoteRepoSuite) SetUpTest(c *C) {
s.downloader = http.NewFakeDownloader().ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile)
s.progress = console.NewProgress()
s.db, _ = database.OpenDB(c.MkDir())
s.packageCollection = NewPackageCollection(s.db)
s.collectionFactory = NewCollectionFactory(s.db)
s.packagePool = files.NewPackagePool(c.MkDir())
s.SetUpPackages()
s.progress.Start()
@@ -101,10 +101,15 @@ func (s *RemoteRepoSuite) TestInvalidURL(c *C) {
}
func (s *RemoteRepoSuite) TestFlatCreation(c *C) {
c.Check(s.flat.Distribution, Equals, "")
c.Check(s.flat.IsFlat(), Equals, true)
c.Check(s.flat.Distribution, Equals, "./")
c.Check(s.flat.Architectures, IsNil)
c.Check(s.flat.Components, IsNil)
flat2, _ := NewRemoteRepo("flat2", "http://pkg.jenkins-ci.org/debian-stable", "binary/", []string{}, []string{}, false)
c.Check(flat2.IsFlat(), Equals, true)
c.Check(flat2.Distribution, Equals, "./binary/")
_, err := NewRemoteRepo("fl", "http://some.repo/", "./", []string{"main"}, []string{}, false)
c.Check(err, ErrorMatches, "components aren't supported for flat repos")
}
@@ -246,12 +251,12 @@ func (s *RemoteRepoSuite) TestDownload(c *C) {
s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages", examplePackagesFile)
s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb", "xyz")
err = s.repo.Download(s.progress, s.downloader, s.packageCollection, s.packagePool, false)
err = s.repo.Download(s.progress, s.downloader, s.collectionFactory, s.packagePool, false)
c.Assert(err, IsNil)
c.Assert(s.downloader.Empty(), Equals, true)
c.Assert(s.repo.packageRefs, NotNil)
pkg, err := s.packageCollection.ByKey(s.repo.packageRefs.Refs[0])
pkg, err := s.collectionFactory.PackageCollection().ByKey(s.repo.packageRefs.Refs[0])
c.Assert(err, IsNil)
result, err := pkg.VerifyFiles(s.packagePool)
@@ -279,12 +284,12 @@ func (s *RemoteRepoSuite) TestDownloadWithSources(c *C) {
s.downloader.AnyExpectResponse("http://mirror.yandex.ru/debian/pool/main/a/access-modifier-checker/access-modifier-checker_1.0.orig.tar.gz", "abcd")
s.downloader.AnyExpectResponse("http://mirror.yandex.ru/debian/pool/main/a/access-modifier-checker/access-modifier-checker_1.0-4.debian.tar.gz", "abcde")
err = s.repo.Download(s.progress, s.downloader, s.packageCollection, s.packagePool, false)
err = s.repo.Download(s.progress, s.downloader, s.collectionFactory, s.packagePool, false)
c.Assert(err, IsNil)
c.Assert(s.downloader.Empty(), Equals, true)
c.Assert(s.repo.packageRefs, NotNil)
pkg, err := s.packageCollection.ByKey(s.repo.packageRefs.Refs[0])
pkg, err := s.collectionFactory.PackageCollection().ByKey(s.repo.packageRefs.Refs[0])
c.Assert(err, IsNil)
result, err := pkg.VerifyFiles(s.packagePool)
@@ -293,7 +298,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSources(c *C) {
c.Check(pkg.Name, Equals, "amanda-client")
pkg, err = s.packageCollection.ByKey(s.repo.packageRefs.Refs[1])
pkg, err = s.collectionFactory.PackageCollection().ByKey(s.repo.packageRefs.Refs[1])
c.Assert(err, IsNil)
result, err = pkg.VerifyFiles(s.packagePool)
@@ -314,12 +319,12 @@ func (s *RemoteRepoSuite) TestDownloadFlat(c *C) {
err := s.flat.Fetch(downloader, nil)
c.Assert(err, IsNil)
err = s.flat.Download(s.progress, downloader, s.packageCollection, s.packagePool, false)
err = s.flat.Download(s.progress, downloader, s.collectionFactory, s.packagePool, false)
c.Assert(err, IsNil)
c.Assert(downloader.Empty(), Equals, true)
c.Assert(s.flat.packageRefs, NotNil)
pkg, err := s.packageCollection.ByKey(s.flat.packageRefs.Refs[0])
pkg, err := s.collectionFactory.PackageCollection().ByKey(s.flat.packageRefs.Refs[0])
c.Assert(err, IsNil)
result, err := pkg.VerifyFiles(s.packagePool)
@@ -348,12 +353,12 @@ func (s *RemoteRepoSuite) TestDownloadWithSourcesFlat(c *C) {
err := s.flat.Fetch(downloader, nil)
c.Assert(err, IsNil)
err = s.flat.Download(s.progress, downloader, s.packageCollection, s.packagePool, false)
err = s.flat.Download(s.progress, downloader, s.collectionFactory, s.packagePool, false)
c.Assert(err, IsNil)
c.Assert(downloader.Empty(), Equals, true)
c.Assert(s.flat.packageRefs, NotNil)
pkg, err := s.packageCollection.ByKey(s.flat.packageRefs.Refs[0])
pkg, err := s.collectionFactory.PackageCollection().ByKey(s.flat.packageRefs.Refs[0])
c.Assert(err, IsNil)
result, err := pkg.VerifyFiles(s.packagePool)
@@ -362,7 +367,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSourcesFlat(c *C) {
c.Check(pkg.Name, Equals, "amanda-client")
pkg, err = s.packageCollection.ByKey(s.flat.packageRefs.Refs[1])
pkg, err = s.collectionFactory.PackageCollection().ByKey(s.flat.packageRefs.Refs[1])
c.Assert(err, IsNil)
result, err = pkg.VerifyFiles(s.packagePool)
+1 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"bytes"
@@ -1,4 +1,4 @@
package debian
package deb
import (
"errors"
+1 -1
View File
@@ -1,4 +1,4 @@
package debian
package deb
import (
"fmt"
@@ -1,4 +1,4 @@
package debian
package deb
import (
. "launchpad.net/gocheck"
-2
View File
@@ -1,2 +0,0 @@
// Package debian implements Debian-specific repository handling
package debian
-467
View File
@@ -1,467 +0,0 @@
package debian
import (
"bufio"
"bytes"
"code.google.com/p/go-uuid/uuid"
"fmt"
"github.com/smira/aptly/aptly"
"github.com/smira/aptly/database"
"github.com/smira/aptly/utils"
"github.com/ugorji/go/codec"
"log"
"path/filepath"
"sort"
"strings"
"time"
)
// 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
Component string
// Architectures is a list of all architectures published
Architectures []string
// Snapshot as a source of publishing
SnapshotUUID string
snapshot *Snapshot
}
// NewPublishedRepo creates new published repository
func NewPublishedRepo(prefix string, distribution string, component string, architectures []string, snapshot *Snapshot) (*PublishedRepo, error) {
prefix = filepath.Clean(prefix)
if strings.HasPrefix(prefix, "/") {
prefix = prefix[1:]
}
if strings.HasSuffix(prefix, "/") {
prefix = prefix[:len(prefix)-1]
}
prefix = filepath.Clean(prefix)
for _, component := range strings.Split(prefix, "/") {
if component == ".." || component == "dists" || component == "pool" {
return nil, fmt.Errorf("invalid prefix %s", prefix)
}
}
return &PublishedRepo{
UUID: uuid.New(),
Prefix: prefix,
Distribution: distribution,
Component: component,
Architectures: architectures,
SnapshotUUID: snapshot.UUID,
snapshot: snapshot,
}, nil
}
// String returns human-readable represenation of PublishedRepo
func (p *PublishedRepo) String() string {
var archs string
if len(p.Architectures) > 0 {
archs = fmt.Sprintf(" [%s]", strings.Join(p.Architectures, ", "))
}
return fmt.Sprintf("%s/%s (%s)%s publishes %s", p.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(packagePool aptly.PackagePool, publishedStorage aptly.PublishedStorage, packageCollection *PackageCollection, signer utils.Signer, progress aptly.Progress) error {
err := publishedStorage.MkDir(filepath.Join(p.Prefix, "pool"))
if err != nil {
return err
}
basePath := filepath.Join(p.Prefix, "dists", p.Distribution)
err = publishedStorage.MkDir(basePath)
if err != nil {
return err
}
if progress != nil {
progress.Printf("Loading packages...\n")
}
// Load all packages
list, err := NewPackageListFromRefList(p.snapshot.RefList(), packageCollection, progress)
if err != nil {
return fmt.Errorf("unable to load packages: %s", err)
}
if list.Len() == 0 {
return fmt.Errorf("snapshot is empty")
}
if len(p.Architectures) == 0 {
p.Architectures = list.Architectures(true)
}
if len(p.Architectures) == 0 {
return fmt.Errorf("unable to figure out list of architectures, please supply explicit list")
}
sort.Strings(p.Architectures)
generatedFiles := map[string]utils.ChecksumInfo{}
if progress != nil {
progress.Printf("Generating metadata files and linking package files...\n")
}
// For all architectures, generate release file
for _, arch := range p.Architectures {
if progress != nil {
progress.InitBar(int64(list.Len()), false)
}
var relativePath string
if arch == "source" {
relativePath = filepath.Join(p.Component, "source", "Sources")
} else {
relativePath = filepath.Join(p.Component, fmt.Sprintf("binary-%s", arch), "Packages")
}
err = publishedStorage.MkDir(filepath.Dir(filepath.Join(basePath, relativePath)))
if err != nil {
return err
}
packagesFile, err := publishedStorage.CreateFile(filepath.Join(basePath, relativePath))
if err != nil {
return fmt.Errorf("unable to creates Packages file: %s", err)
}
bufWriter := bufio.NewWriter(packagesFile)
err = list.ForEach(func(pkg *Package) error {
if progress != nil {
progress.AddBar(1)
}
if pkg.MatchesArchitecture(arch) {
err = pkg.LinkFromPool(publishedStorage, packagePool, p.Prefix, p.Component)
if err != nil {
return err
}
err = pkg.Stanza().WriteTo(bufWriter)
if err != nil {
return err
}
err = bufWriter.WriteByte('\n')
if err != nil {
return err
}
pkg.files = nil
pkg.deps = nil
pkg.extra = nil
}
return nil
})
if err != nil {
return fmt.Errorf("unable to process packages: %s", err)
}
err = bufWriter.Flush()
if err != nil {
return fmt.Errorf("unable to write Packages file: %s", err)
}
err = utils.CompressFile(packagesFile)
if err != nil {
return fmt.Errorf("unable to compress Packages files: %s", err)
}
packagesFile.Close()
checksumInfo, err := publishedStorage.ChecksumsForFile(filepath.Join(basePath, relativePath))
if err != nil {
return fmt.Errorf("unable to collect checksums: %s", err)
}
generatedFiles[relativePath] = checksumInfo
checksumInfo, err = publishedStorage.ChecksumsForFile(filepath.Join(basePath, relativePath+".gz"))
if err != nil {
return fmt.Errorf("unable to collect checksums: %s", err)
}
generatedFiles[relativePath+".gz"] = checksumInfo
checksumInfo, err = publishedStorage.ChecksumsForFile(filepath.Join(basePath, relativePath+".bz2"))
if err != nil {
return fmt.Errorf("unable to collect checksums: %s", err)
}
generatedFiles[relativePath+".bz2"] = checksumInfo
if progress != nil {
progress.ShutdownBar()
}
}
release := make(Stanza)
release["Origin"] = p.Prefix + " " + p.Distribution
release["Label"] = p.Prefix + " " + p.Distribution
release["Codename"] = p.Distribution
release["Date"] = time.Now().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST")
release["Components"] = p.Component
release["Architectures"] = strings.Join(utils.StrSlicesSubstract(p.Architectures, []string{"source"}), " ")
release["Description"] = " Generated by aptly\n"
release["MD5Sum"] = "\n"
release["SHA1"] = "\n"
release["SHA256"] = "\n"
for path, info := range generatedFiles {
release["MD5Sum"] += fmt.Sprintf(" %s %8d %s\n", info.MD5, info.Size, path)
release["SHA1"] += fmt.Sprintf(" %s %8d %s\n", info.SHA1, info.Size, path)
release["SHA256"] += fmt.Sprintf(" %s %8d %s\n", info.SHA256, info.Size, path)
}
releaseFile, err := publishedStorage.CreateFile(filepath.Join(basePath, "Release"))
if err != nil {
return fmt.Errorf("unable to create Release file: %s", err)
}
bufWriter := bufio.NewWriter(releaseFile)
err = release.WriteTo(bufWriter)
if err != nil {
return fmt.Errorf("unable to create Release file: %s", err)
}
err = bufWriter.Flush()
if err != nil {
return fmt.Errorf("unable to create Release file: %s", err)
}
releaseFilename := releaseFile.Name()
releaseFile.Close()
// Signing files might output to console, so flush progress writer first
if progress != nil {
progress.Flush()
}
if signer != nil {
err = signer.DetachedSign(releaseFilename, releaseFilename+".gpg")
if err != nil {
return fmt.Errorf("unable to sign Release file: %s", err)
}
err = signer.ClearSign(releaseFilename, filepath.Join(filepath.Dir(releaseFilename), "InRelease"))
if err != nil {
return fmt.Errorf("unable to sign Release file: %s", err)
}
}
return nil
}
// RemoveFiles removes files that were created by Publish
//
// It can remove prefix fully, and part of pool (for specific component)
func (p *PublishedRepo) RemoveFiles(publishedStorage aptly.PublishedStorage, removePrefix, removePoolComponent bool) error {
if removePrefix {
err := publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "dists"))
if err != nil {
return err
}
return publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "pool"))
}
err := publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "dists", p.Distribution))
if err != nil {
return err
}
if removePoolComponent {
err = publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "pool", p.Component))
if err != nil {
return err
}
}
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)
}
// BySnapshot looks up repository by snapshot source
func (collection *PublishedRepoCollection) BySnapshot(snapshot *Snapshot) []*PublishedRepo {
result := make([]*PublishedRepo, 0)
for _, r := range collection.list {
if r.SnapshotUUID == snapshot.UUID {
result = append(result, r)
}
}
return result
}
// 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)
}
// Remove removes published repository, cleaning up directories, files
func (collection *PublishedRepoCollection) Remove(publishedStorage aptly.PublishedStorage, prefix, distribution string) error {
repo, err := collection.ByPrefixDistribution(prefix, distribution)
if err != nil {
return err
}
removePrefix := true
removePoolComponent := true
repoPosition := -1
for i, r := range collection.list {
if r == repo {
repoPosition = i
continue
}
if r.Prefix == repo.Prefix {
removePrefix = false
if r.Component == repo.Component {
removePoolComponent = false
}
}
}
err = repo.RemoveFiles(publishedStorage, removePrefix, removePoolComponent)
if err != nil {
return err
}
collection.list[len(collection.list)-1], collection.list[repoPosition], collection.list =
nil, collection.list[len(collection.list)-1], collection.list[:len(collection.list)-1]
return collection.db.Delete(repo.Key())
}
+40 -15
View File
@@ -1,7 +1,6 @@
package files
import (
"fmt"
"github.com/smira/aptly/aptly"
"github.com/smira/aptly/utils"
"os"
@@ -38,46 +37,72 @@ func (storage *PublishedStorage) CreateFile(path string) (*os.File, error) {
return os.Create(filepath.Join(storage.rootPath, path))
}
// RemoveDirs removes directory structure under public path
func (storage *PublishedStorage) RemoveDirs(path string) error {
// Remove removes single file under public path
func (storage *PublishedStorage) Remove(path string) error {
filepath := filepath.Join(storage.rootPath, path)
fmt.Printf("Removing %s...\n", filepath)
return os.Remove(filepath)
}
// RemoveDirs removes directory structure under public path
func (storage *PublishedStorage) RemoveDirs(path string, progress aptly.Progress) error {
filepath := filepath.Join(storage.rootPath, path)
if progress != nil {
progress.Printf("Removing %s...\n", filepath)
}
return os.RemoveAll(filepath)
}
// LinkFromPool links package file from pool to dist's pool location
//
// prefix is publishing prefix for this repo (e.g. empty or "ppa/")
// component is component name when publishing (e.g. main)
// poolDirectory is desired location in pool (like liba/libav/)
// publishedDirectory is desired location in pool (like prefix/pool/component/liba/libav/)
// sourcePool is instance of aptly.PackagePool
// sourcePath is filepath to package file in package pool
//
// LinkFromPool returns relative path for the published file to be included in package index
func (storage *PublishedStorage) LinkFromPool(prefix string, component string, poolDirectory string, sourcePool aptly.PackagePool, sourcePath string) (string, error) {
func (storage *PublishedStorage) LinkFromPool(publishedDirectory string, sourcePool aptly.PackagePool, sourcePath string) error {
// verify that package pool is local pool is filesystem pool
_ = sourcePool.(*PackagePool)
baseName := filepath.Base(sourcePath)
relPath := filepath.Join("pool", component, poolDirectory, baseName)
poolPath := filepath.Join(storage.rootPath, prefix, "pool", component, poolDirectory)
poolPath := filepath.Join(storage.rootPath, publishedDirectory)
err := os.MkdirAll(poolPath, 0755)
if err != nil {
return "", err
return err
}
_, err = os.Stat(filepath.Join(poolPath, baseName))
if err == nil { // already exists, skip
return relPath, nil
return nil
}
err = os.Link(sourcePath, filepath.Join(poolPath, baseName))
return relPath, err
return os.Link(sourcePath, filepath.Join(poolPath, baseName))
}
// Filelist returns list of files under prefix
func (storage *PublishedStorage) Filelist(prefix string) ([]string, error) {
root := filepath.Join(storage.rootPath, prefix)
result := []string{}
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
result = append(result, path[len(root)+1:])
}
return nil
})
return result, err
}
// ChecksumsForFile proxies requests to utils.ChecksumsForFile, joining public path
func (storage *PublishedStorage) ChecksumsForFile(path string) (utils.ChecksumInfo, error) {
return utils.ChecksumsForFile(filepath.Join(storage.rootPath, path))
}
// RenameFile renames (moves) file
func (storage *PublishedStorage) RenameFile(oldName, newName string) error {
return os.Rename(filepath.Join(storage.rootPath, oldName), filepath.Join(storage.rootPath, newName))
}
+49 -3
View File
@@ -44,6 +44,38 @@ func (s *PublishedStorageSuite) TestCreateFile(c *C) {
c.Assert(err, IsNil)
}
func (s *PublishedStorageSuite) TestFilelist(c *C) {
err := s.storage.MkDir("ppa/pool/main/a/ab/")
c.Assert(err, IsNil)
file, err := s.storage.CreateFile("ppa/pool/main/a/ab/a.deb")
c.Assert(err, IsNil)
defer file.Close()
file2, err := s.storage.CreateFile("ppa/pool/main/a/ab/b.deb")
c.Assert(err, IsNil)
defer file2.Close()
list, err := s.storage.Filelist("ppa/pool/main/")
c.Check(err, IsNil)
c.Check(list, DeepEquals, []string{"a/ab/a.deb", "a/ab/b.deb"})
}
func (s *PublishedStorageSuite) TestRenameFile(c *C) {
err := s.storage.MkDir("ppa/dists/squeeze/")
c.Assert(err, IsNil)
file, err := s.storage.CreateFile("ppa/dists/squeeze/Release")
c.Assert(err, IsNil)
defer file.Close()
err = s.storage.RenameFile("ppa/dists/squeeze/Release", "ppa/dists/squeeze/InRelease")
c.Check(err, IsNil)
_, err = os.Stat(filepath.Join(s.storage.rootPath, "ppa/dists/squeeze/InRelease"))
c.Assert(err, IsNil)
}
func (s *PublishedStorageSuite) TestRemoveDirs(c *C) {
err := s.storage.MkDir("ppa/dists/squeeze/")
c.Assert(err, IsNil)
@@ -52,7 +84,22 @@ func (s *PublishedStorageSuite) TestRemoveDirs(c *C) {
c.Assert(err, IsNil)
defer file.Close()
err = s.storage.RemoveDirs("ppa/dists/")
err = s.storage.RemoveDirs("ppa/dists/", nil)
_, err = os.Stat(filepath.Join(s.storage.rootPath, "ppa/dists/squeeze/Release"))
c.Assert(err, NotNil)
c.Assert(os.IsNotExist(err), Equals, true)
}
func (s *PublishedStorageSuite) TestRemove(c *C) {
err := s.storage.MkDir("ppa/dists/squeeze/")
c.Assert(err, IsNil)
file, err := s.storage.CreateFile("ppa/dists/squeeze/Release")
c.Assert(err, IsNil)
defer file.Close()
err = s.storage.Remove("ppa/dists/squeeze/Release")
_, err = os.Stat(filepath.Join(s.storage.rootPath, "ppa/dists/squeeze/Release"))
c.Assert(err, NotNil)
@@ -108,9 +155,8 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) {
err = ioutil.WriteFile(t.sourcePath, []byte("Contents"), 0644)
c.Assert(err, IsNil)
path, err := s.storage.LinkFromPool(t.prefix, t.component, t.poolDirectory, pool, t.sourcePath)
err = s.storage.LinkFromPool(filepath.Join(t.prefix, "pool", t.component, t.poolDirectory), pool, t.sourcePath)
c.Assert(err, IsNil)
c.Assert(path, Equals, t.expectedFilename)
st, err := os.Stat(filepath.Join(s.storage.rootPath, t.prefix, t.expectedFilename))
c.Assert(err, IsNil)
+8 -1
View File
@@ -28,6 +28,7 @@ type downloaderImpl struct {
unpause chan bool
progress aptly.Progress
threads int
client *http.Client
}
// downloadTask represents single item in queue
@@ -50,6 +51,12 @@ func NewDownloader(threads int, progress aptly.Progress) aptly.Downloader {
unpause: make(chan bool),
threads: threads,
progress: progress,
client: &http.Client{
Transport: &http.Transport{
DisableCompression: true,
Proxy: http.ProxyFromEnvironment,
},
},
}
for i := 0; i < downloader.threads; i++ {
@@ -105,7 +112,7 @@ func (downloader *downloaderImpl) DownloadWithChecksum(url string, destination s
func (downloader *downloaderImpl) handleTask(task *downloadTask) {
downloader.progress.Printf("Downloading %s...\n", task.url)
resp, err := http.Get(task.url)
resp, err := downloader.client.Get(task.url)
if err != nil {
task.result <- err
return
+13 -72
View File
@@ -2,96 +2,37 @@ package main
import (
"fmt"
"github.com/gonuts/commander"
"github.com/smira/aptly/cmd"
"github.com/smira/aptly/utils"
"os"
"path/filepath"
)
var (
returnCode = 0
errorMessage string
)
func fatal(err error) {
errorMessage = fmt.Sprintf("ERROR: %s\n", err)
returnCode = 1
}
func loadConfig(command *commander.Command) error {
var err error
configLocation := command.Flag.Lookup("config").Value.String()
if configLocation != "" {
err = utils.LoadConfig(configLocation, &utils.Config)
if err != nil {
return err
}
} else {
configLocations := []string{
filepath.Join(os.Getenv("HOME"), ".aptly.conf"),
"/etc/aptly.conf",
}
for _, configLocation := range configLocations {
err = utils.LoadConfig(configLocation, &utils.Config)
if err == nil {
break
}
if !os.IsNotExist(err) {
fatal(fmt.Errorf("error loading config file %s: %s", configLocation, err))
return nil
}
}
if err != nil {
fmt.Printf("Config file not found, creating default config at %s\n\n", configLocations[0])
utils.SaveConfig(configLocations[0], &utils.Config)
}
}
return nil
}
func main() {
defer func() {
if errorMessage != "" {
fmt.Print(errorMessage)
}
if returnCode != 0 {
os.Exit(returnCode)
if r := recover(); r != nil {
fatal, ok := r.(*cmd.FatalError)
if !ok {
panic(r)
}
fmt.Println("ERROR:", fatal.Message)
os.Exit(fatal.ReturnCode)
}
}()
command := cmd.RootCommand()
err := command.Flag.Parse(os.Args[1:])
flags, args, err := command.ParseFlags(os.Args[1:])
if err != nil {
fatal(err)
return
cmd.Fatal(err)
}
err = loadConfig(command)
err = cmd.InitContext(flags)
if err != nil {
fatal(err)
return
}
if returnCode != 0 {
return
}
err = cmd.InitContext(command)
if err != nil {
fatal(err)
return
cmd.Fatal(err)
}
defer cmd.ShutdownContext()
err = command.Dispatch(command.Flag.Args())
err = command.Dispatch(args)
if err != nil {
fatal(err)
return
cmd.Fatal(err)
}
}
+276 -69
View File
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "APTLY" "1" "March 2014" "" ""
.TH "APTLY" "1" "May 2014" "" ""
.
.SH "NAME"
\fBaptly\fR \- Debian repository management tool
@@ -10,7 +10,7 @@
Common command format:
.
.P
\fBaptly\fR [\fIglobal options\fR\.\.\.] \fIcommand\fR \fIsubcommand\fR [\fIoptions\fR\.\.\.] \fIarguments\fR
\fBaptly\fR [\fIglobal options\fR\|\.\|\.\|\.] \fIcommand\fR \fIsubcommand\fR [\fIoptions\fR\|\.\|\.\|\.] \fIarguments\fR
.
.P
aptly has integrated help that matches contents of this manual page, to get help, prepend \fBhelp\fR to command name:
@@ -22,7 +22,7 @@ aptly has integrated help that matches contents of this manual page, to get help
aptly is a tool to create partial and full mirrors of remote repositories, manage local repositories, filter them, merge, upgrade individual packages, take snapshots and publish them back as Debian repositories\.
.
.P
aptly goal is to establish repeatiblity and controlled changes in package environment\. aptly allows to fix set of packages in repository, so that package installation and upgrade becomes deterministic\. At the same time aptly allows to perform controlled, fine\-grained changes in repository contents to transition your package environment to new version\.
aptly\(cqs goal is to establish repeatability and controlled changes in a package\-centric environment\. aptly allows to fix a set of packages in a repository, so that package installation and upgrade becomes deterministic\. At the same time aptly allows to perform controlled, fine\-grained changes in repository contents to transition your package environment to new version\.
.
.SH "CONFIGURATION"
aptly looks for configuration file in \fB/etc/aptly\.conf\fR and \fB~/\.aptly\.conf\fR, if no config file found, new one is created\. If \fB\-config=\fR flag is specified, aptly would use config file at specified location\. Also aptly needs root directory for database, package and published repository storage\. If not specified, directory defaults to \fB~/\.aptly\fR, it will be created if missing\.
@@ -86,11 +86,11 @@ follow dependency from binary package to source package
.
.TP
\fBgpgDisableSign\fR
don\'t sign published repositories with gpg(1), also can be disabled on per\-repo basis using \fB\-skip\-signing\fR flag when publishing
don\(cqt sign published repositories with gpg(1), also can be disabled on per\-repo basis using \fB\-skip\-signing\fR flag when publishing
.
.TP
\fBgpgDisableVerify\fR
don\'t verify remote mirrors with gpg(1), also can be disabled on per\-mirror basis using \fB\-ignore\-signatures\fR flag when creating and updating mirrors
don\(cqt verify remote mirrors with gpg(1), also can be disabled on per\-mirror basis using \fB\-ignore\-signatures\fR flag when creating and updating mirrors
.
.TP
\fBdownloadSourcePackages\fR
@@ -134,7 +134,7 @@ version and architecture conditions combined\.
When specified on command line, condition may have to be quoted according to shell rules, so that it stays single argument:
.
.P
\fBaptly repo import percona stable \'mysql\-client (>= 3\.6)\'\fR
\fBaptly repo import percona stable \(cqmysql\-client (>= 3\.6)\(cq\fR
.
.SH "GLOBAL OPTIONS"
.
@@ -147,12 +147,8 @@ list of architectures to consider during (comma\-separated), default to all avai
location of configuration file (default locations are /etc/aptly\.conf, ~/\.aptly\.conf)
.
.TP
\-\fBcpuprofile\fR=
write cpu profile to file
.
.TP
\-\fBdep\-follow\-all\-variants\fR=false
when processing dependencies, follow a & b if depdency is \'a|b\'
when processing dependencies, follow a & b if depdency is \(cqa|b\(cq
.
.TP
\-\fBdep\-follow\-recommends\fR=false
@@ -166,23 +162,11 @@ when processing dependencies, follow from binary to Source packages
\-\fBdep\-follow\-suggests\fR=false
when processing dependencies, follow Suggests
.
.TP
\-\fBmeminterval\fR=100ms
memory stats dump interval
.
.TP
\-\fBmemprofile\fR=
write memory profile to this file
.
.TP
\-\fBmemstats\fR=
write memory stats periodically to this file
.
.SH "CREATE NEW MIRROR"
\fBaptly\fR \fBmirror\fR \fBcreate\fR \fIname\fR \fIarchive url\fR \fIdistribution\fR [\fIcomponent1\fR \.\.\.]
\fBaptly\fR \fBmirror\fR \fBcreate\fR \fIname\fR \fIarchive url\fR \fIdistribution\fR [\fIcomponent1\fR \|\.\|\.\|\.]
.
.P
Creates mirror \fIname\fR of remote repository, aptly supports both regular and flat Debian repositories exported via HTTP\. aptly would try download Release file from remote repository and verify its signature\.
Creates mirror \fIname\fR of remote repository, aptly supports both regular and flat Debian repositories exported via HTTP\. aptly would try download Release file from remote repository and verify its\(cq signature\. Command line format resembles apt utlitily sources\.list(5)\.
.
.P
PPA urls could specified in short format:
@@ -223,11 +207,18 @@ Example:
.P
$ aptly mirror list
.
.P
Options:
.
.TP
\-\fBraw\fR=false
display list in machine\-readable format
.
.SH "SHOW DETAILS ABOUT MIRROR"
\fBaptly\fR \fBmirror\fR \fBshow\fR \fIname\fR
.
.P
Shows detailed information about mirror\.
Shows detailed information about the mirror\.
.
.P
Example:
@@ -246,7 +237,7 @@ show detailed list of packages and versions stored in the mirror
\fBaptly\fR \fBmirror\fR \fBdrop\fR \fIname\fR
.
.P
Drop deletes information about remote repository mirror \fIname\fR\. Package data is not deleted (it could be still used by other mirrors or snapshots)\. If mirror is used as source to create a snapshot, aptly would refuse to delete such mirror, use flag \-force to override\.
Drop deletes information about remote repository mirror \fIname\fR\. Package data is not deleted (since it could still be used by other mirrors or snapshots)\. If mirror is used as source to create a snapshot, aptly would refuse to delete such mirror, use flag \-force to override\.
.
.P
Example:
@@ -265,7 +256,7 @@ force mirror deletion even if used by snapshots
\fBaptly\fR \fBmirror\fR \fBupdate\fR \fIname\fR
.
.P
Updates remote mirror (downloads package files and meta information)\. When mirror is created, this command should be run for the first time to fetch mirror contents\. This command could be run many times to get updated repository contents\. If interrupted, command could be restarted safely\.
Updates remote mirror (downloads package files and meta information)\. When mirror is created, this command should be run for the first time to fetch mirror contents\. This command can be run multiple times to get updated repository contents\. If interrupted, command can be safely restarted\.
.
.P
Example:
@@ -292,7 +283,7 @@ gpg keyring to use when verifying Release file (could be specified multiple time
\fBaptly\fR \fBrepo\fR \fBadd\fR \fIname\fR
.
.P
Command adds packages to local repository from \.deb (binary packages) and \.dsc (source packages) files\. When importing from directory aptly would do recursive scan looking for all files matching \fI\.deb or\fR\.dsc patterns\. Every file discovered would be analyzed to extract metadata, package would be created and added to database\. Files would be imported to internal package pool\. For source packages, all required files are added as well automatically\. Extra files for source package should be in the same directory as *\.dsc file\.
Command adds packages to local repository from \.deb (binary packages) and \.dsc (source packages) files\. When importing from directory aptly would do recursive scan looking for all files matching \fI\.deb or\fR\.dsc patterns\. Every file discovered would be analyzed to extract metadata, package would then be created and added to the database\. Files would be imported to internal package pool\. For source packages, all required files are added automatically as well\. Extra files for source package should be in the same directory as *\.dsc file\.
.
.P
Example:
@@ -308,7 +299,7 @@ Options:
remove files that have been imported successfully into repository
.
.SH "COPY PACKAGES BETWEEN LOCAL REPOSITORIES"
\fBaptly\fR \fBrepo\fR \fBcopy\fR \fIsrc\-name\fR \fIdst\-name\fR \fIpackage\-spec\fR \fB\.\.\.\fR
\fBaptly\fR \fBrepo\fR \fBcopy\fR \fIsrc\-name\fR \fIdst\-name\fR \fIpackage\-spec\fR \fB\|\.\|\.\|\.\fR
.
.P
Command copy copies packages matching \fIpackage\-spec\fR from local repo \fIsrc\-name\fR to local repo \fIdst\-name\fR\.
@@ -317,14 +308,14 @@ Command copy copies packages matching \fIpackage\-spec\fR from local repo \fIsrc
Example:
.
.P
$ aptly repo copy testing stable \'myapp (=0\.1\.12)\'
$ aptly repo copy testing stable \(cqmyapp (=0\.1\.12)\(cq
.
.P
Options:
.
.TP
\-\fBdry\-run\fR=false
don\'t copy, just show what would be copied
don\(cqt copy, just show what would be copied
.
.TP
\-\fBwith\-deps\fR=false
@@ -349,11 +340,19 @@ Options:
\-\fBcomment\fR=
any text that would be used to described local repository
.
.TP
\-\fBcomponent\fR=main
default component when publishing
.
.TP
\-\fBdistribution\fR=
default distribution when publishing
.
.SH "DELETE LOCAL REPOSITORY"
\fBaptly\fR \fBrepo\fR \fBdrop\fR \fIname\fR
.
.P
Drop deletes information about local repo\. Package data is not deleted (it could be still used by other mirrors or snapshots)\.
Drop information about deletions from local repo\. Package data is not deleted (since it could be still used by other mirrors or snapshots)\.
.
.P
Example:
@@ -368,8 +367,35 @@ Options:
\-\fBforce\fR=false
force local repo deletion even if used by snapshots
.
.SH "EDIT PROPERTIES OF LOCAL REPOSITORY"
\fBaptly\fR \fBrepo\fR \fBedit\fR \fIname\fR
.
.P
Command edit allows to change metadata of local repository: comment, default distribution and component\.
.
.P
Example:
.
.P
$ aptly repo edit \-distribution=wheezy testing
.
.P
Options:
.
.TP
\-\fBcomment\fR=
any text that would be used to described local repository
.
.TP
\-\fBcomponent\fR=
default component when publishing
.
.TP
\-\fBdistribution\fR=
default distribution when publishing
.
.SH "IMPORT PACKAGES FROM MIRROR TO LOCAL REPOSITORY"
\fBaptly\fR \fBrepo\fR \fBimport\fR \fIsrc\-mirror\fR \fIdst\-repo\fR \fIpackage\-spec\fR \fB\.\.\.\fR
\fBaptly\fR \fBrepo\fR \fBimport\fR \fIsrc\-mirror\fR \fIdst\-repo\fR \fIpackage\-spec\fR \fB\|\.\|\.\|\.\fR
.
.P
Command import looks up packages matching \fIpackage\-spec\fR in mirror \fIsrc\-mirror\fR and copies them to local repo \fIdst\-repo\fR\.
@@ -385,7 +411,7 @@ Options:
.
.TP
\-\fBdry\-run\fR=false
don\'t import, just show what would be imported
don\(cqt import, just show what would be imported
.
.TP
\-\fBwith\-deps\fR=false
@@ -395,7 +421,7 @@ follow dependencies when processing package\-spec
\fBaptly\fR \fBrepo\fR \fBlist\fR
.
.P
List shows full list of local package repositories\.
List command shows full list of local package repositories\.
.
.P
Example:
@@ -403,8 +429,15 @@ Example:
.P
$ aptly repo list
.
.P
Options:
.
.TP
\-\fBraw\fR=false
display list in machine\-readable format
.
.SH "MOVE PACKAGES BETWEEN LOCAL REPOSITORIES"
\fBaptly\fR \fBrepo\fR \fBmove\fR \fIsrc\-name\fR \fIdst\-name\fR \fIpackage\-spec\fR \fB\.\.\.\fR
\fBaptly\fR \fBrepo\fR \fBmove\fR \fIsrc\-name\fR \fIdst\-name\fR \fIpackage\-spec\fR \fB\|\.\|\.\|\.\fR
.
.P
Command move moves packages matching \fIpackage\-spec\fR from local repo \fIsrc\-name\fR to local repo \fIdst\-name\fR\.
@@ -413,43 +446,43 @@ Command move moves packages matching \fIpackage\-spec\fR from local repo \fIsrc\
Example:
.
.P
$ aptly repo move testing stable \'myapp (=0\.1\.12)\'
$ aptly repo move testing stable \(cqmyapp (=0\.1\.12)\(cq
.
.P
Options:
.
.TP
\-\fBdry\-run\fR=false
don\'t move, just show what would be moved
don\(cqt move, just show what would be moved
.
.TP
\-\fBwith\-deps\fR=false
follow dependencies when processing package\-spec
.
.SH "REMOVE PACKAGES FROM LOCAL REPOSITORY"
\fBaptly\fR \fBrepo\fR \fBremove\fR \fIname\fR \fIpackage\-spec\fR \fB\.\.\.\fR
\fBaptly\fR \fBrepo\fR \fBremove\fR \fIname\fR \fIpackage\-spec\fR \fB\|\.\|\.\|\.\fR
.
.P
Commands removes packages matching \fIpackage\-spec\fR from local repository \fIname\fR\. If removed packages are not referenced by other repos or snapshots, they can be removed completely (including files) by running \'aptly db cleanup\'\.
Commands removes packages matching \fIpackage\-spec\fR from local repository \fIname\fR\. If removed packages are not referenced by other repos or snapshots, they can be removed completely (including files) by running \(cqaptly db cleanup\(cq\.
.
.P
Example:
.
.P
$ aptly repo remove testing \'myapp (=0\.1\.12)\'
$ aptly repo remove testing \(cqmyapp (=0\.1\.12)\(cq
.
.P
Options:
.
.TP
\-\fBdry\-run\fR=false
don\'t remove, just show what would be removed
don\(cqt remove, just show what would be removed
.
.SH "SHOW DETAILS ABOUT LOCAL REPOSITORY"
\fBaptly\fR \fBrepo\fR \fBshow\fR \fIname\fR
.
.P
Show shows full information about local package repository\.
Show command shows full information about local package repository\.
.
.P
ex: $ aptly repo show testing
@@ -491,11 +524,18 @@ Example:
.P
$ aptly snapshot list
.
.P
Options:
.
.TP
\-\fBraw\fR=false
display list in machine\-readable format
.
.SH "SHOWS DETAILS ABOUT SNAPSHOT"
\fBaptly\fR \fBsnapshot\fR \fBshow\fR \fIname\fR
.
.P
Command show displays full information about snapshot\.
Command show displays full information about a snapshot\.
.
.P
Example:
@@ -518,10 +558,10 @@ Options:
show list of packages
.
.SH "VERIFY DEPENDENCIES IN SNAPSHOT"
\fBaptly\fR \fBsnapshot\fR \fBverify\fR \fIname\fR [\fIsource\fR \.\.\.]
\fBaptly\fR \fBsnapshot\fR \fBverify\fR \fIname\fR [\fIsource\fR \|\.\|\.\|\.]
.
.P
Verify does depenency resolution in snapshot \fIname\fR, possibly using additional snapshots \fIsource\fR as dependency sources\. All unsatisfied dependencies are printed\.
Verify does dependency resolution in snapshot \fIname\fR, possibly using additional snapshots \fIsource\fR as dependency sources\. All unsatisfied dependencies are printed\.
.
.P
Example:
@@ -537,10 +577,10 @@ $ aptly snapshot verify wheezy\-main wheezy\-contrib wheezy\-non\-free
.IP "" 0
.
.SH "PULL PACKAGES FROM ANOTHER SNAPSHOT"
\fBaptly\fR \fBsnapshot\fR \fBpull\fR \fIname\fR \fIsource\fR \fIdestination\fR \fIpackage\-name\fR \fB\.\.\.\fR
\fBaptly\fR \fBsnapshot\fR \fBpull\fR \fIname\fR \fIsource\fR \fIdestination\fR \fIpackage\-name\fR \fB\|\.\|\.\|\.\fR
.
.P
Command pull pulls new packages along with its dependencies to snapshot \fIname\fR from snapshot \fIsource\fR\. Pull can upgrade package version in \fIname\fR with versions from \fIsource\fR following dependencies\. New snapshot \fIdestination\fR is created as result of this process\. Packages could be specified simply as \'package\-name\' or as dependency \'package\-name (>= version)\'\.
Command pull pulls new packages along with its\(cq dependencies to snapshot \fIname\fR from snapshot \fIsource\fR\. Pull can upgrade package version in \fIname\fR with versions from \fIsource\fR following dependencies\. New snapshot \fIdestination\fR is created as a result of this process\. Packages could be specified simply as \(cqpackage\-name\(cq or as dependency \(cqpackage\-name (>= version)\(cq\.
.
.P
Example:
@@ -560,15 +600,15 @@ Options:
.
.TP
\-\fBdry\-run\fR=false
don\'t create destination snapshot, just show what would be pulled
don\(cqt create destination snapshot, just show what would be pulled
.
.TP
\-\fBno\-deps\fR=false
don\'t process dependencies, just pull listed packages
don\(cqt process dependencies, just pull listed packages
.
.TP
\-\fBno\-remove\fR=false
don\'t remove other package versions when pulling package
don\(cqt remove other package versions when pulling package
.
.SH "DIFFERENCE BETWEEN TWO SNAPSHOTS"
\fBaptly\fR \fBsnapshot\fR \fBdiff\fR \fIname\-a\fR \fIname\-b\fR
@@ -594,13 +634,13 @@ Options:
.
.TP
\-\fBonly\-matching\fR=false
display diff only for matching packages (don\'t display missing packages)
display diff only for matching packages (don\(cqt display missing packages)
.
.SH "MERGES SNAPSHOTS"
\fBaptly\fR \fBsnapshot\fR \fBmerge\fR \fIdestination\fR \fIsource\fR [\fIsource\fR\.\.\.]
\fBaptly\fR \fBsnapshot\fR \fBmerge\fR \fIdestination\fR \fIsource\fR [\fIsource\fR\|\.\|\.\|\.]
.
.P
Merge merges several \fIsource\fR snapshots into one \fIdestination\fR snapshot\. Merge happens from left to right\. Packages with the same name\-architecture pair are replaced during merge (package from latest snapshot on the list wins)\. If run with only one source snapshot, merge copies \fIsource\fR into \fIdestination\fR\.
Merge command merges several \fIsource\fR snapshots into one \fIdestination\fR snapshot\. Merge happens from left to right\. By default, packages with the same name\-architecture pair are replaced during merge (package from latest snapshot on the list wins)\. If run with only one source snapshot, merge copies \fIsource\fR into \fIdestination\fR\.
.
.P
Example:
@@ -615,11 +655,18 @@ $ aptly snapshot merge wheezy\-w\-backports wheezy\-main wheezy\-backports
.
.IP "" 0
.
.P
Options:
.
.TP
\-\fBlatest\fR=false
use only the latest version of each package
.
.SH "DELETE SNAPSHOT"
\fBaptly\fR \fBsnapshot\fR \fBdrop\fR \fIname\fR
.
.P
Drop removes information about snapshot\. If snapshot is published, it can\'t be dropped\.
Drop removes information about a snapshot\. If snapshot is published, it can\(cqt be dropped\.
.
.P
Example:
@@ -641,11 +688,113 @@ Options:
\-\fBforce\fR=false
remove snapshot even if it was used as source for other snapshots
.
.SH "REMOVE PUBLISHED REPOSITORY"
\fBaptly\fR \fBpublish\fR \fBdrop\fR \fIdistribution\fR [\fIprefix\fR]
.
.P
Command removes whatever has been published under specified \fIprefix\fR and \fIdistribution\fR name\.
.
.P
Example:
.
.IP "" 4
.
.nf
$ aptly publish drop wheezy
.
.fi
.
.IP "" 0
.
.SH "LIST OF PUBLISHED REPOSITORIES"
\fBaptly\fR \fBpublish\fR \fBlist\fR
.
.P
Display list of currently published snapshots\.
.
.P
Example:
.
.IP "" 4
.
.nf
$ aptly publish list
.
.fi
.
.IP "" 0
.
.P
Options:
.
.TP
\-\fBraw\fR=false
display list in machine\-readable format
.
.SH "PUBLISH LOCAL REPOSITORY"
\fBaptly\fR \fBpublish\fR \fBrepo\fR \fIname\fR [\fIprefix\fR]
.
.P
Command publishes current state of local repository ready to be consumed by apt tools\. Published repostiories appear under rootDir/public directory\. Valid GPG key is required for publishing\.
.
.P
It is not recommended to publish local repositories directly unless the repository is for testing purposes and changes happen frequently\. For production usage please take snapshot of repository and publish it using publish snapshot command\.
.
.P
Example:
.
.IP "" 4
.
.nf
$ aptly publish repo testing
.
.fi
.
.IP "" 0
.
.P
Options:
.
.TP
\-\fBcomponent\fR=
component name to publish
.
.TP
\-\fBdistribution\fR=
distribution name to publish
.
.TP
\-\fBgpg\-key\fR=
GPG key ID to use when signing the release
.
.TP
\-\fBkeyring\fR=
GPG keyring to use (instead of default)
.
.TP
\-\fBlabel\fR=
label to publish
.
.TP
\-\fBorigin\fR=
origin name to publish
.
.TP
\-\fBsecret\-keyring\fR=
GPG secret keyring to use (instead of default)
.
.TP
\-\fBskip\-signing\fR=false
don\(cqt sign Release files with GPG
.
.SH "PUBLISH SNAPSHOT"
\fBaptly\fR \fBpublish\fR \fBsnapshot\fR \fIname\fR [\fIprefix\fR]
.
.P
Command publish publishes snapshot as Debian repository ready to be consumed by apt tools\. Published repostiories appear under rootDir/public directory\. Valid GPG key is required for publishing\.
Command publishes snapshot as Debian repository ready to be consumed by apt tools\. Published repostiories appear under rootDir/public directory\. Valid GPG key is required for publishing\.
.
.P
Example:
@@ -680,18 +829,26 @@ GPG key ID to use when signing the release
GPG keyring to use (instead of default)
.
.TP
\-\fBlabel\fR=
label to publish
.
.TP
\-\fBorigin\fR=
origin name to publish
.
.TP
\-\fBsecret\-keyring\fR=
GPG secret keyring to use (instead of default)
.
.TP
\-\fBskip\-signing\fR=false
don\'t sign Release files with GPG
don\(cqt sign Release files with GPG
.
.SH "LIST OF PUBLISHED REPOSITORIES"
\fBaptly\fR \fBpublish\fR \fBlist\fR
.SH "UPDATE PUBLISHED REPOSITORY BY SWITCHING TO NEW SNAPSHOT"
\fBaptly\fR \fBpublish\fR \fBswitch\fR \fIdistribution\fR [\fIprefix\fR] \fInew\-snapshot\fR
.
.P
Display list of currently published snapshots\.
Command switches in\-place published repository with new snapshot contents\. All publishing parameters are preserved (architecture list, distribution, component)\.
.
.P
Example:
@@ -700,17 +857,36 @@ Example:
.
.nf
$ aptly publish list
$ aptly publish update wheezy ppa wheezy\-7\.5
.
.fi
.
.IP "" 0
.
.SH "REMOVE PUBLISHED REPOSITORY"
\fBaptly\fR \fBpublish\fR \fBdrop\fR \fIdistribution\fR [\fIprefix\fR]
.P
Options:
.
.TP
\-\fBgpg\-key\fR=
GPG key ID to use when signing the release
.
.TP
\-\fBkeyring\fR=
GPG keyring to use (instead of default)
.
.TP
\-\fBsecret\-keyring\fR=
GPG secret keyring to use (instead of default)
.
.TP
\-\fBskip\-signing\fR=false
don\(cqt sign Release files with GPG
.
.SH "UPDATE PUBLISHED LOCAL REPOSITORY"
\fBaptly\fR \fBpublish\fR \fBupdate\fR \fIdistribution\fR [\fIprefix\fR]
.
.P
Command removes whatever has been published under specified \fIprefix\fR and \fIdistribution\fR name\.
Command re\-publishes (updates) published local repository\. \fIdistribution\fR and \fIprefix\fR should be occupied with local repository published using command aptly publish repo\. Update happens in\-place with minimum possible downtime for published repository\.
.
.P
Example:
@@ -719,17 +895,36 @@ Example:
.
.nf
$ aptly publish drop wheezy
$ aptly publish update wheezy ppa
.
.fi
.
.IP "" 0
.
.P
Options:
.
.TP
\-\fBgpg\-key\fR=
GPG key ID to use when signing the release
.
.TP
\-\fBkeyring\fR=
GPG keyring to use (instead of default)
.
.TP
\-\fBsecret\-keyring\fR=
GPG secret keyring to use (instead of default)
.
.TP
\-\fBskip\-signing\fR=false
don\(cqt sign Release files with GPG
.
.SH "CLEANUP DB AND PACKAGE POOL"
\fBaptly\fR \fBdb\fR \fBcleanup\fR
.
.P
Database cleanup removes information about unreferenced packages and removes files in the package pool that aren\'t used by packages anymore
Database cleanup removes information about unreferenced packages and removes files in the package pool that aren\(cqt used by packages anymore
.
.P
Example:
@@ -737,11 +932,23 @@ Example:
.P
$ aptly db cleanup
.
.SH "RECOVER DB AFTER CRASH"
\fBaptly\fR \fBdb\fR \fBrecover\fR
.
.P
Database recover does its\(cq best to recover the database after a crash\. It is recommended to backup the DB before running recover\.
.
.P
Example:
.
.P
$ aptly db recover
.
.SH "HTTP SERVE PUBLISHED REPOSITORIES"
\fBaptly\fR \fBserve\fR
.
.P
Command serve starts embedded HTTP server (not suitable for real production usage) to serve contents of public/ subdirectory of aptly\'s root that contains published repositories\.
Command serve starts embedded HTTP server (not suitable for real production usage) to serve contents of public/ subdirectory of aptly\(cqs root that contains published repositories\.
.
.P
Example:
@@ -760,7 +967,7 @@ host:port for HTTP listening
\fBaptly\fR \fBgraph\fR
.
.P
Command graph displays relationship between mirrors, local repositories, snapshots and published repositories using graphviz package to render graph as image\.
Command graph displays relationship between mirrors, local repositories, snapshots and published repositories using graphviz package to render graph as an image\.
.
.P
Example:
+2 -2
View File
@@ -2,9 +2,9 @@ package main
import (
"fmt"
"github.com/gonuts/commander"
"github.com/gonuts/flag"
"github.com/smira/aptly/cmd"
"github.com/smira/commander"
"github.com/smira/flag"
"log"
"os"
"os/exec"
+112
View File
@@ -0,0 +1,112 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.9 (GNU/Linux)
mQGiBEmFQG0RBACXScOxb6BTV6rQE/tcJopAEWsdvmE0jNIRWjDDzB7HovX6Anrq
n7+Vq4spAReSFbBVaYiiOx2cGDymj2dyx2i9NAI/9/cQXJOU+RPdDzHVlO1Edksp
5rKn0cGPWY5sLxRf8s/tO5oyKgwCVgTaB5a8gBHaoGms3nNC4YYf+lqlpwCgjbti
3u1iMIx6Rs+dG0+xw1oi5FUD/2tLJMx7vCUQHhPRupeYFPoD8vWpcbGb5nHfHi4U
8/x4qZspAIwvXtGw0UBHildGpqe9onp22Syadn/7JgMWhHoFw5Ke/rTMlxREL7pa
TiXuagD2G84tjJ66oJP1FigslJzrnG61y85V7THL61OFqDg6IOP4onbsdqHby4VD
zZj9A/9uQxIn5250AGLNpARStAcNPJNJbHOQuv0iF3vnG8uO7/oscB0TYb8/juxr
hs9GdSN0U0BxENR+8KWy5lttpqLMKlKRknQYy34UstQiyFgAQ9Epncu9uIbVDgWt
y7utnqXN033EyYkcWx5EhLAgHkC7wSzeSWABV3JSXN7CeeOif7QiS29oc3VrZSBL
YXdhZ3VjaGkgPGtrQGtvaHN1a2Uub3JnPohjBBMRAgAjAhsDBgsJCAcDAgQVAggD
BBYCAwECHgECF4AFAko/7vYCGQEACgkQm30y8tUFguabhgCgi54IQR4rpJZ/uUHe
ZB879zUWTQwAniQDBO+Zly7Fsvm0Mcvqvl02UzxCtC1Lb2hzdWtlIEthd2FndWNo
aSA8a29oc3VrZS5rYXdhZ3VjaGlAc3VuLmNvbT6IYAQTEQIAIAUCSj/qbQIbAwYL
CQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEJt9MvLVBYLm38gAoIGR2+TQeJaCeEa8
CQhZYzDoiJkQAJ0cpmD+0VA+leOAr5LEccNVd70Z/dHNy83JARAAAQEAAAAAAAAA
AAAAAAD/2P/gABBKRklGAAEBAQBgAGAAAP/hAGBFeGlmAABJSSoACAAAAAQAMQEC
ABkAAAA+AAAAEFEBAAEAAAABQ5AAEVEEAAEAAAASCwAAElEEAAEAAAASCwAAAAAA
AE1hY3JvbWVkaWEgRmlyZXdvcmtzIDQuMAAA/9sAQwAIBgYHBgUIBwcHCQkICgwU
DQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy
/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy
MjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgArgCWAwEiAAIRAQMRAf/EAB8AAAEF
AQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQEC
AwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkq
NDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqS
k5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk
5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkK
C//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGx
wQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFla
Y2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2
t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQAC
EQMRAD8A9wEj/wB9vzpfMf8Avt+dRinCpGSeY398/nS72/vH86YKBQBJvb+8fzpd
7f3j+dMFLQA/e394/nS7j6n86ZSimA7cfU07cfU1HnFOFADtx9aXJ9TTKUUxD8n1
pc+9Mp1AC5ozSUtAC0maKKADNFJ2ooAoCnCmilzWZQ6lFJSimAopaQUtAC54rOvN
dsLCTZPPGrdwXAry/wCKHxXfRppND0Mq16Bie5PIi9lHdv5V8/X+rXt/O8tzcyyy
MclnYkk0avYdl1PqPxT8VtH8NwqwzdXEuSkaHoB61wjftCXhlzHosBjHZpSCa8PW
O7uhuAkcDueaaYbhOqMMe1L5lcvWx9U+FPjJ4f8AEU0dpdhtLvXOFWdgY3PoH6fg
cV6MrZGa+EklIOJOPqK9i+G3xem0TytI8QSSXGnHCQXJO57f2Pqn6indrclq+x9G
5pwNVoLiO4hSaGRZIpFDKynIYHuKmBqyB+aWmg0uaAFopKKAFoozRQBQFLSUorMo
UUtJSigB1ZHijWovD/hu+1KZlUQxErnu3YfnWsK8k+Pt60PhaxtAxAnuOQO4UE0P
YaWp8/Xd1LeTz3Mzl5pnLuxPJJNa+i+HDclZZ1yp5C1Q0axa+1BEx8i8mvS7S3WG
NQo6elcWLxDprljuelgsOp+/IgtdCiVFVYx07CnXHhyNgflA/Ct+1BwOKmkVq8xS
m9bnr2S0sec6n4UVo2KKNw6Vx9xby2U3lSAj617NcR5J4zmua1/Q4r+1JVQJU5Ui
uzD4qUXyz2OHFYWM1zR3Ol+CHj0xXX/CKajMTHKd1g7H7r94/oeo9wR3r3tWr4ht
pZtNv4bmElZ7eVZUIOPmU5/pX2dpOpR6tpFnqMQxHdQpMoz03DOK9ePY8OaszUDU
+oFNSg0yUOopKWgAoo6mikBRpwptLWZY4UoptLTELXin7QbD7PoiFv45Gx+Ar2uv
FP2g7dfsejXOfm8x48evGf6UmNbnm3hCBls57sJuYnYg9TXSyW2uIgNpJbs5GWDj
gewrP8EJu0XIHKyNV2+j1txM0MzIQV8oIQN3POSenHTg15VSV6z2+Z7dGNqKt26G
hpeo6rC3lajZxKOgdG6/hW5NcoIC4HOOhrmbJb1IokuZWkfbmUsQQGz2xW5OAbAE
Y3d/es5TtJo6oRbjcx7uXVryXbblIIv723JqN9PuUdLhJ2aQf6xW6OP6VBqS6jcQ
sLS4aOQHCqH2qVx64znP8verWn2d/DKrPOzxbFBWQ5O7HJyOxParv7t7oxcfeasz
z3xBaC01uZV4RxvAr6X+F0rv8NdCMj7iICAfQBjgV87+NYzHr6jHHlA/rX0H8LFa
P4baLu3DMTHDDtvOPwr1sM7xR4mK0m/U7lTUyniqyGp1NbtHOmSUuaaDS1JQuaKS
ikBTpaQUVmUOpabS0xC15f8AF7wxc+IEsJI3VI4Nyrkfxtjn6YH616hWL4ptDd6B
cBTh0+cH0xUVL8j5dzSk0prm2PD/AAnYvp+ltazDbNHM6yD3BrpEiWToOKzPLktr
mRiSwlO7J9atQ3bFsCvGnJSlzM+gpLlXKJcpDAegGT+ZqYgPYAgVnz3DpKW8pJW6
AM2MUranci38vy4gBz/9alGF3dG0ppKzZYs0ilB4BwauOixggVlW9w8sivsWJuhC
nOanmun83bimtNCZPS5g6/osOta3Zq8giRImMjeoyMAe5Oa940SxTStFsbCM/JbQ
JGv0AryTTLRLzXIwwDOWVAvfGecCvZx19q9fAttPyPBzCyatuyyhqZTxVdDU612M
4ESg04GowacDUFjqKQc0UDKlLSUtZFC0UUCmAtMmiSeF4pBlHBVh7U6imI878Y+G
rbTbGC7tFf5WKyFmz1rimZoy2wZJGQBXter2C6lpc9qw++vy/XtXiMoe3upLeTiS
Nipry8XSUJJpaHq4Os5JpvUoC4uJr1rYIkJC7vMuGCgj2rZ/4Ry/aHzvtdltO4Ei
TPTH+NUrhFlUB1yQODVB8RjyRboR6hiAfqM4rCLTPR6aSt8rktzJc2l7HZgRXLOu
4SQPkKPU1fUtu3SHJUc/WqlvGIULKo3kdhgCr+lwfb9ZtLItxLIAx9upp25pKKMq
klFN3PTfDenR2mjWbtEvnsm8sVG4buevXpit1aiUAcAYHapVr6GMVGKij5iUnKTk
ydKnU1ClSikwRIKcD60wU4GpLQ7PpRSUUhlaikpc1kWLRSUUxC5ozSZozTA5Txn8
QtF8DxRDUDLPeTDdFaQAFyucbiTwo+vXsK8huNZHiVJddtbY2/mysfJL7iAD0JwM
1h/F+X7V8RtUKybzEUj5PTCjj8KseD2S304WbzxPJ9/CsDjcM4/DvXLjF+6TXc7M
F/EafY1YNThkVcttccMpqY3trtx8ufeoJbK3acrLECPcUsmj2EUYfyw27kcmvOjY
9NuS6kc+pxp8seWc8Koq7pWox+HLiHWdQSR0gO90jALYxjAzjnmsxbnTbCXMssMK
r6nk/h1rH17xLY3lpJa25dw4wWxgfrW9KnOU04owqziotSZ7r4S8daT4xFwunpcR
S24DPHOoBweMjBOa6pDXzn8JNej0nxdFbSKqwX6/ZtzHG1s5U59yMfjX0SpwcGvc
Wp4MlZltDUoNV42qYGpYIlFOzUYNOBqSx4opBzRSArUtNqrqWqWOj2D32pXcVrap
96WVsDPoO5PsOayNC5TXkWKJpZHVI0GWd2AVR7k9K8Z8R/HTazweHNPBHQXd4Ovu
sY/9mP4V5Trvi7XPETltW1S4uVzkRM2I1+iDCj8qtRYWPfvEXxh8L6GJIrWZ9Vu1
48u1/wBWD7yHj8s15Jr/AMYfFGtyOlvdDS7c5xFZnace7n5j+n0rz1n3Hmmk4zzV
KKFcdNPI7s0jM7sxZmY5LE9ST61CsrI25SQR3BwacWzwRUZX0qiblgaheq25bucH
18w086tqDrta9uCvp5hqng56UDmp5I9iueXcmDsxyzEn1JqROvNQKD7VKCqDJOas
kuRuMgjp711+n/FHxVpyIsWqNPHEAojukWQEe5PP61wvnEj0B4ApykZJJ7UDPfvD
Hxp0+/dLfXbYWMp4E8RLxH6jqv616laXtve26XFrPFPC/KyRsGU/iK+MBICcDitn
QPFWseHbvztMv5YM/eTOUb6qeDRcXKj7CV8ing1434V+NtpezR2niC3W0Y8fa4cm
PP8AtL1H1Ga9atrqG6gSe3mjmhcZSSNgysPYikTZouCiow4xRRYLmRr+tW/h7Qrv
Vbkbo7dCwQHBdugUfU4r5Y8TeKtV8Tak15qlwztk+XEDiOFf7qL2H6nvXr3x01n7
Po2n6SjfNcymaQf7K8D9T+leBzPuT3H8qiC0NHoNeYnvURc4phPNITmrJuLu5pSa
Z3pRyKYhM80oOaaetAoAkzwKTd6Cm5pBQA8EnqTijOSeOKaT2oHSgY7cTTg1Rilp
AS7/AGpc4UA96iHJApXbk0wJ0kOeDXTeGPGer+GbtZNOunWMnLwscxv9V/ya5T7q
D1NOEhQYHU9/Siw0z7A8KeJ7XxToceo2ymNs7JoicmNx1HuOcg0V5j8A9RQnWNKl
lVARHcruOOfut/7LRTViJaPQ5b42agbrx29uGytrAiAehPJ/nXmrNu2H14NdD481
A6j401S6zkPMQPoOP6VzQOcj0OaiGxctxpNA5obqfrQKokSlWkzQDzQAMOaSnN1F
JQAtFFFAAKKKO9AC0UlGaBj0HemjlvrTkOEY03vQIe7YJP4CkTBfn6mkbkA/Wkzg
YHU9aYGtpl7Pau8kEzxMwwShwcUVUtWIU4oqbXLTFv3M0jSkksWJP481SU/Pk1Ym
b7/1FViMY96diWKwy5+tITTm+7mo6BC0DrR2oHWgB7dBTac3SmUALS0lKOtACUua
KKACm0vSk70ASLxF9TSYzznrQf8AVqKTPH40wHHHQfjTM55pTwp9+KQdKALEL7Is
+poph4Cr6Cigdz//2YhgBBMRAgAgBQJKP/cgAhsDBgsJCAcDAgQVAggDBBYCAwEC
HgECF4AACgkQm30y8tUFgua3awCdFQlChLgn/n4tb4jLe1RgxOxHxosAn2Cn2oNh
sZ91wUb4d5JuH88TCupsuQINBEmFQG0QCADqAXWgiis4yi96os3QZmK5809ojjTT
nlICgbztrT55cMVTDBc9SneyRQlC0cS+M1z4Do6lj81sNJdJiBPqTYYA1+exTFvs
5zCxPInDP3hvqXxHTP142XN1hdzt53R7smn8O0wyO+RCBUb44e9NkusvBd5UP3Je
449hnpXJ4WO3cVMFm4ghxs7ERlpAi5NTEsVVdM8dqHbZJtk8gbzdAHH0ybiAXmWy
LFGZDuuKiFAkqm/Wled7id6N+cPx107dwBclwPxzfEYKEqJ1YDDHoDlyfx4012y1
53e5sGyah/IPBYrrLMfG+Wmiwr5nCX0tmwOcyukuE94hbzJCX2wBdbWLAAMGCACz
l3cuM4lGt/wr5liM4gotXpZAopY+EnbLIBuOHFXXR7HnyAgST1jH/AUbafvPjyDh
EkFDyUP14XtHNIAqsN1UpuyYbM90bMPAWXJxrazMsSF+Tv5yIxHiy4cc1pjoqHA2
kwqIGHmTxYzOPOS19ZWQAtevoTE6pCARphY0dzpscCWaXGs/ZqNAhjL96WLYV1Oo
Ut+9mTnOcs6Vuxaxp2wN2S5DK1S9gdIxWEc8wMUPiQe8CYk0OySdORIblMs3bGqD
FoM5HcBAZP1YlXitPH2nIRv0DtOQGMQOCkqUWmQuQAUgKV+YO86lO4S7EhTET/GP
sQb6P7efm/Cs8wbq/wyIiEkEGBECAAkFAkmFQG0CGwwACgkQm30y8tUFgua2mACe
JNBW4snDC4OzjKU6QT386/GA9ssAn3vLzSwn8N1xv5MihWGr5kVzvaE2
=cjdq
-----END PGP PUBLIC KEY BLOCK-----
+7 -1
View File
@@ -77,6 +77,7 @@ class BaseTest(object):
"ppaCodename": "",
}
configOverride = {}
environmentOverride = {}
fixtureDBDir = os.path.join(os.environ["HOME"], "aptly-fixture-db")
fixturePoolDir = os.path.join(os.environ["HOME"], "aptly-fixture-pool")
@@ -135,7 +136,8 @@ class BaseTest(object):
self.run_cmd(["gpg", "--no-default-keyring", "--trust-model", "always", "--batch", "--keyring", "aptlytest.gpg", "--import",
os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files", "debian-archive-keyring.gpg"),
os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files", "launchpad.key"),
os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files", "flat.key")])
os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files", "flat.key"),
os.path.join(os.path.dirname(inspect.getsourcefile(BaseTest)), "files", "jenkins.key")])
if hasattr(self, "fixtureCmds"):
for cmd in self.fixtureCmds:
@@ -160,6 +162,7 @@ class BaseTest(object):
command = shlex.split(command)
environ = os.environ.copy()
environ["LC_ALL"] = "C"
environ.update(self.environmentOverride)
proc = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=environ)
output, _ = proc.communicate()
#print "CMD %s: %.2f" % (" ".join(command), time.time()-start)
@@ -192,6 +195,9 @@ class BaseTest(object):
with open(os.path.join(os.environ["HOME"], ".aptly", path), "r") as f:
return f.read()
def delete_file(self, path):
os.unlink(os.path.join(os.environ["HOME"], ".aptly", path))
def check_file_contents(self, path, gold_name, match_prepare=None):
contents = self.read_file(path)
+1 -1
View File
@@ -1 +1 @@
aptly version: 0.4.1
aptly version: 0.5.1
+1 -23
View File
@@ -1,23 +1 @@
aptly - Debian repository management tool
Commands:
db manage aptly's internal database and package pool
graph render graph of relationships
mirror manage mirrors of remote repositories
publish manage published repositories
repo manage local package repositories
serve HTTP serve published repositories
snapshot manage snapshots of repositories
version display version
Use "aptly help <command>" for more information about a command.
Options:
-architectures="": list of architectures to consider during (comma-separated), default to all available
-config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)
-dep-follow-all-variants=false: when processing dependencies, follow a & b if depdency is 'a|b'
-dep-follow-recommends=false: when processing dependencies, follow Recommends
-dep-follow-source=false: when processing dependencies, follow from binary to Source packages
-dep-follow-suggests=false: when processing dependencies, follow Suggests
No mirrors found, create one with `aptly mirror create ...`.
+5 -4
View File
@@ -12,7 +12,7 @@ class CreateConfigTest(BaseTest):
"""
new file is generated if missing
"""
runCmd = "aptly"
runCmd = "aptly mirror list"
checkedFile = os.path.join(os.environ["HOME"], ".aptly.conf")
check = BaseTest.check_file
@@ -24,7 +24,7 @@ class BadConfigTest(BaseTest):
"""
broken config file
"""
runCmd = "aptly"
runCmd = "aptly mirror list"
expectedCode = 1
gold_processor = BaseTest.expand_environ
@@ -41,7 +41,8 @@ class ConfigInFileTest(BaseTest):
"""
config in other file test
"""
runCmd = ["aptly", "-config=%s" % (os.path.join(os.path.dirname(inspect.getsourcefile(BadConfigTest)), "aptly.conf"), )]
runCmd = ["aptly", "mirror", "list",
"-config=%s" % (os.path.join(os.path.dirname(inspect.getsourcefile(BadConfigTest)), "aptly.conf"), )]
prepare = BaseTest.prepare_remove_all
outputMatchPrepare = lambda _, s: re.sub(r' -(cpuprofile|memprofile|memstats|meminterval)=.*\n', '', s, flags=re.MULTILINE)
@@ -51,6 +52,6 @@ class ConfigInMissingFileTest(BaseTest):
"""
config in other file test
"""
runCmd = ["aptly", "-config=nosuchfile.conf"]
runCmd = ["aptly", "mirror", "list", "-config=nosuchfile.conf"]
expectedCode = 1
prepare = BaseTest.prepare_remove_all
+3 -3
View File
@@ -3,9 +3,9 @@ repositories, manage local repositories, filter them, merge,
upgrade individual packages, take snapshots and publish them
back as Debian repositories.
aptly goal is to establish repeatiblity and controlled changes
in package environment. aptly allows to fix set of packages in
repository, so that package installation and upgrade becomes
aptly's goal is to establish repeatability and controlled changes
in a package-centric environment. aptly allows to fix a set of packages
in a repository, so that package installation and upgrade becomes
deterministic. At the same time aptly allows to perform controlled,
fine-grained changes in repository contents to transition your
package environment to new version.
+8 -1
View File
@@ -1,7 +1,8 @@
Usage: aptly mirror create <name> <archive url> <distribution> [<component1> ...]
Creates mirror <name> of remote repository, aptly supports both regular and flat Debian repositories exported
via HTTP. aptly would try download Release file from remote repository and verify its signature.
via HTTP. aptly would try download Release file from remote repository and verify its' signature. Command
line format resembles apt utlitily sources.list(5).
PPA urls could specified in short format:
@@ -12,6 +13,12 @@ Example:
$ aptly mirror create wheezy-main http://mirror.yandex.ru/debian/ wheezy main
Options:
-architectures="": list of architectures to consider during (comma-separated), default to all available
-config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)
-dep-follow-all-variants=false: when processing dependencies, follow a & b if depdency is 'a|b'
-dep-follow-recommends=false: when processing dependencies, follow Recommends
-dep-follow-source=false: when processing dependencies, follow from binary to Source packages
-dep-follow-suggests=false: when processing dependencies, follow Suggests
-ignore-signatures=false: disable verification of Release file signatures
-keyring=: gpg keyring to use when verifying Release file (could be specified multiple times)
-with-sources=false: download source packages in addition to binary packages
+6
View File
@@ -4,6 +4,12 @@ aptly mirror create - create new mirror
Options:
-architectures="": list of architectures to consider during (comma-separated), default to all available
-config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)
-dep-follow-all-variants=false: when processing dependencies, follow a & b if depdency is 'a|b'
-dep-follow-recommends=false: when processing dependencies, follow Recommends
-dep-follow-source=false: when processing dependencies, follow from binary to Source packages
-dep-follow-suggests=false: when processing dependencies, follow Suggests
-ignore-signatures=false: disable verification of Release file signatures
-keyring=: gpg keyring to use when verifying Release file (could be specified multiple times)
-with-sources=false: download source packages in addition to binary packages
+8
View File
@@ -10,3 +10,11 @@ Commands:
Use "mirror help <command>" for more information about a command.
Options:
-architectures="": list of architectures to consider during (comma-separated), default to all available
-config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)
-dep-follow-all-variants=false: when processing dependencies, follow a & b if depdency is 'a|b'
-dep-follow-recommends=false: when processing dependencies, follow Recommends
-dep-follow-source=false: when processing dependencies, follow from binary to Source packages
-dep-follow-suggests=false: when processing dependencies, follow Suggests
+8
View File
@@ -10,3 +10,11 @@ Commands:
Use "mirror help <command>" for more information about a command.
Options:
-architectures="": list of architectures to consider during (comma-separated), default to all available
-config="": location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)
-dep-follow-all-variants=false: when processing dependencies, follow a & b if depdency is 'a|b'
-dep-follow-recommends=false: when processing dependencies, follow Recommends
-dep-follow-source=false: when processing dependencies, follow from binary to Source packages
-dep-follow-suggests=false: when processing dependencies, follow Suggests
@@ -10,10 +10,10 @@ Information from release file:
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
Codename: wheezy
Components: main contrib non-free
Date: Sat, 08 Feb 2014 10:36:03 UTC
Description: Debian 7.4 Released 08 February 2014
Date: Sat, 26 Apr 2014 09:27:11 UTC
Description: Debian 7.5 Released 26 April 2014
Label: Debian
Origin: Debian
Suite: stable
Version: 7.4
Version: 7.5
@@ -1,6 +1,6 @@
Name: mirror14
Archive Root URL: http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/
Distribution:
Distribution: ./
Components:
Architectures:
Download Sources: no
@@ -10,10 +10,10 @@ Information from release file:
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
Codename: wheezy
Components: main contrib non-free
Date: Sat, 08 Feb 2014 10:36:03 UTC
Description: Debian 7.4 Released 08 February 2014
Date: Sat, 26 Apr 2014 09:27:11 UTC
Description: Debian 7.5 Released 26 April 2014
Label: Debian
Origin: Debian
Suite: stable
Version: 7.4
Version: 7.5

Some files were not shown because too many files have changed in this diff Show More