mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-01 04:40:38 +00:00
Compare commits
116 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b5d025f141 | |||
| 3c7a2281b2 | |||
| be3ad21fbe | |||
| 5301e8a341 | |||
| 49eed59238 | |||
| 3e78240b39 | |||
| 10bbefeb25 | |||
| 35eac72226 | |||
| 5371f94b7a | |||
| 53adf39d89 | |||
| bc7972ff68 | |||
| 21e8aa5519 | |||
| f0825d93be | |||
| 9e538d9475 | |||
| 042602f991 | |||
| e8a894bc88 | |||
| 59647fe6d0 | |||
| 37a6fb336a | |||
| 7c2faafa91 | |||
| 87295c6580 | |||
| 4ce4923f58 | |||
| 2a83596307 | |||
| 5f29cb202a | |||
| 3800f2c957 | |||
| 6c3b2f686e | |||
| 708fd800df | |||
| 385ac1afd0 | |||
| d9f8673286 | |||
| d1cc562f3c | |||
| e6992d822d | |||
| 0d8debe7b6 | |||
| 89eafd1b21 | |||
| 1a735e849b | |||
| a93052aa8a | |||
| 133d67bffa | |||
| 60d48e890c | |||
| dbcfd6f58b | |||
| cd369f5fa0 | |||
| 992a5cee37 | |||
| fb8686a634 | |||
| cc8baec317 | |||
| 1200e9cc95 | |||
| 3342ce490a | |||
| 4541e0bdae | |||
| 522684aabb | |||
| 8963cd8027 | |||
| 9445f3a0fa | |||
| d69eaeff4e | |||
| 1bac201687 | |||
| 45335da0ed | |||
| b10aeacfc0 | |||
| d9f4686e2c | |||
| 7eb2fdf425 | |||
| c70c196420 | |||
| e81f86f942 | |||
| 6352ce30ed | |||
| cefc3cc2dc | |||
| 376bb69803 | |||
| e33f5792e1 | |||
| 8d214e6d12 | |||
| 73761c311e | |||
| b85f46547b | |||
| 108dc235a7 | |||
| 90dd21b270 | |||
| ce615facf9 | |||
| a8cf83774a | |||
| 470571c7db | |||
| 55807412a1 | |||
| c106e66cff | |||
| d6fd4e46a0 | |||
| b34707faed | |||
| e4de1738ce | |||
| ff045f9a48 | |||
| fd662c9275 | |||
| 83b2e0250d | |||
| 3db7125932 | |||
| efcce4ef3c | |||
| d90f8dba7f | |||
| 173dd775bc | |||
| 4afa3126e4 | |||
| 5a6ccb7259 | |||
| 2c3553ef0b | |||
| 400d0da7d4 | |||
| 4caeea49b1 | |||
| f648c9547c | |||
| d84226a054 | |||
| 006d173d4f | |||
| 6ca62a9d50 | |||
| c7dcc8ff59 | |||
| 4c237ed1b1 | |||
| ec866eb403 | |||
| 53e73c52a4 | |||
| 0f8f43b9f0 | |||
| 7f2f435e2d | |||
| c325119081 | |||
| 3b16ca156a | |||
| 22014206d7 | |||
| 9ff49ff24a | |||
| 37ea845fd9 | |||
| 1a88876e63 | |||
| 1a60ac6aa0 | |||
| a0497058ee | |||
| 140c925079 | |||
| 5bd5e0a827 | |||
| 3c32cd3884 | |||
| 32717e92ba | |||
| c2fc2f9988 | |||
| 1189bca5a4 | |||
| 2315c00ae1 | |||
| e5de8b9353 | |||
| 099806aa82 | |||
| 6a42aad322 | |||
| b13e50a570 | |||
| dff0ab2fa3 | |||
| a7f135a441 | |||
| c71a57169c |
@@ -2,7 +2,6 @@ language: go
|
||||
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.2.1
|
||||
- tip
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
@@ -1,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
"github.com/smira/aptly/utils"
|
||||
@@ -0,0 +1,2 @@
|
||||
// Package deb implements Debian-specific repository handling
|
||||
package deb
|
||||
@@ -1,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
. "launchpad.net/gocheck"
|
||||
@@ -1,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@@ -1,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@@ -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,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -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,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -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()
|
||||
@@ -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 {
|
||||
@@ -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
@@ -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())
|
||||
}
|
||||
@@ -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")
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"})
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -1,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -1,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -1,4 +1,4 @@
|
||||
package debian
|
||||
package deb
|
||||
|
||||
import (
|
||||
. "launchpad.net/gocheck"
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
// Package debian implements Debian-specific repository handling
|
||||
package debian
|
||||
Vendored
-467
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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 @@
|
||||
aptly version: 0.4.1
|
||||
aptly version: 0.5.1
|
||||
|
||||
@@ -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 ...`.
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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
Reference in New Issue
Block a user