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:
|
go:
|
||||||
- 1.1
|
- 1.1
|
||||||
- 1.2
|
|
||||||
- 1.2.1
|
- 1.2.1
|
||||||
- tip
|
- 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/gographviz', :commit => '212766062629'
|
||||||
gom 'code.google.com/p/snappy-go/snappy', :commit => '12e4b4183793'
|
gom 'code.google.com/p/snappy-go/snappy', :commit => '12e4b4183793'
|
||||||
gom 'github.com/cheggaaa/pb', :commit => '74be7a1388046f374ac36e93d46f5d56e856f827'
|
gom 'github.com/cheggaaa/pb', :commit => '74be7a1388046f374ac36e93d46f5d56e856f827'
|
||||||
gom 'github.com/gonuts/commander', :commit => 'f8ba4e959ca914268227c3ebbd7f6bf0bb35541a'
|
gom 'github.com/smira/commander', :commit => '082a3ce267a8225a8ccf94deaf18901223d38fed'
|
||||||
gom 'github.com/gonuts/flag', :commit => '741a6cbd37a30dedc93f817e7de6aaf0ca38a493'
|
gom 'github.com/smira/flag', :commit => '0d0aac2addb39050f45e92c5a6252926096dc841'
|
||||||
gom 'github.com/mkrautz/goar', :commit => '36eb5f3452b1283a211fa35bc00c646fd0db5c4b'
|
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/ugorji/go/codec', :commit => '71c2886f5a673a35f909803f38ece5810165097b'
|
||||||
gom 'github.com/wsxiaoys/terminal/color', :commit => '5668e431776a7957528361f90ce828266c69ed08'
|
gom 'github.com/wsxiaoys/terminal/color', :commit => '5668e431776a7957528361f90ce828266c69ed08'
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
GOVERSION=$(shell go version | awk '{print $$3;}')
|
GOVERSION=$(shell go version | awk '{print $$3;}')
|
||||||
PACKAGES=database debian files http utils
|
PACKAGES=database deb files http utils
|
||||||
ALL_PACKAGES=aptly cmd console database debian files http utils
|
ALL_PACKAGES=aptly cmd console database deb files http utils
|
||||||
BINPATH=$(abspath ./_vendor/bin)
|
BINPATH=$(abspath ./_vendor/bin)
|
||||||
GOM_ENVIRONMENT=-test
|
GOM_ENVIRONMENT=-test
|
||||||
PYTHON?=python
|
PYTHON?=python
|
||||||
@@ -61,4 +61,27 @@ mem.png: mem.dat mem.gp
|
|||||||
gnuplot mem.gp
|
gnuplot mem.gp
|
||||||
open mem.png
|
open mem.png
|
||||||
|
|
||||||
.PHONY: coverage.out
|
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
|
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/>`_.
|
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)::
|
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
|
mkdir -p $GOPATH/src/github.com/smira/aptly
|
||||||
git clone https://github.com/smira/aptly $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
|
cd $GOPATH/src/github.com/smira/aptly
|
||||||
gom install
|
gom -production install
|
||||||
gom build -o $GOPATH/bin/aptly
|
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``
|
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 creates file for writing under public path
|
||||||
CreateFile(path string) (*os.File, error)
|
CreateFile(path string) (*os.File, error)
|
||||||
// RemoveDirs removes directory structure under public path
|
// 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 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 proxies requests to utils.ChecksumsForFile, joining public path
|
||||||
ChecksumsForFile(path string) (utils.ChecksumInfo, error)
|
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
|
// Progress is a progress displaying entity, it allows progress bars & simple prints
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
package aptly
|
package aptly
|
||||||
|
|
||||||
// Version of aptly
|
// Version of aptly
|
||||||
const Version = "0.4.1"
|
const Version = "0.5.1"
|
||||||
|
|
||||||
// Enable debugging features?
|
// Enable debugging features?
|
||||||
const EnableDebug = false
|
const EnableDebug = false
|
||||||
|
|||||||
+10
-12
@@ -3,28 +3,26 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/debian"
|
"github.com/smira/aptly/deb"
|
||||||
|
"github.com/smira/commander"
|
||||||
|
"github.com/smira/flag"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListPackagesRefList shows list of packages in PackageRefList
|
// 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")
|
fmt.Printf("Packages:\n")
|
||||||
|
|
||||||
if reflist == nil {
|
if reflist == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
packageCollection := debian.NewPackageCollection(context.database)
|
|
||||||
|
|
||||||
err = reflist.ForEach(func(key []byte) error {
|
err = reflist.ForEach(func(key []byte) error {
|
||||||
p, err := packageCollection.ByKey(key)
|
p, err2 := context.CollectionFactory().PackageCollection().ByKey(key)
|
||||||
if err != nil {
|
if err2 != nil {
|
||||||
return err
|
return err2
|
||||||
}
|
}
|
||||||
fmt.Printf(" %s\n", p)
|
fmt.Printf(" %s\n", p)
|
||||||
return nil
|
return nil
|
||||||
@@ -47,9 +45,9 @@ repositories, manage local repositories, filter them, merge,
|
|||||||
upgrade individual packages, take snapshots and publish them
|
upgrade individual packages, take snapshots and publish them
|
||||||
back as Debian repositories.
|
back as Debian repositories.
|
||||||
|
|
||||||
aptly goal is to establish repeatiblity and controlled changes
|
aptly's goal is to establish repeatability and controlled changes
|
||||||
in package environment. aptly allows to fix set of packages in
|
in a package-centric environment. aptly allows to fix a set of packages
|
||||||
repository, so that package installation and upgrade becomes
|
in a repository, so that package installation and upgrade becomes
|
||||||
deterministic. At the same time aptly allows to perform controlled,
|
deterministic. At the same time aptly allows to perform controlled,
|
||||||
fine-grained changes in repository contents to transition your
|
fine-grained changes in repository contents to transition your
|
||||||
package environment to new version.`,
|
package environment to new version.`,
|
||||||
|
|||||||
+207
-77
@@ -2,14 +2,14 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/console"
|
"github.com/smira/aptly/console"
|
||||||
"github.com/smira/aptly/database"
|
"github.com/smira/aptly/database"
|
||||||
"github.com/smira/aptly/debian"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/smira/aptly/files"
|
"github.com/smira/aptly/files"
|
||||||
"github.com/smira/aptly/http"
|
"github.com/smira/aptly/http"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
|
"github.com/smira/flag"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -18,13 +18,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common context shared by all commands
|
// AptlyContext is a common context shared by all commands
|
||||||
var context struct {
|
type AptlyContext struct {
|
||||||
|
flags *flag.FlagSet
|
||||||
|
configLoaded bool
|
||||||
|
|
||||||
progress aptly.Progress
|
progress aptly.Progress
|
||||||
downloader aptly.Downloader
|
downloader aptly.Downloader
|
||||||
database database.Storage
|
database database.Storage
|
||||||
packagePool aptly.PackagePool
|
packagePool aptly.PackagePool
|
||||||
publishedStorage aptly.PublishedStorage
|
publishedStorage aptly.PublishedStorage
|
||||||
|
collectionFactory *deb.CollectionFactory
|
||||||
dependencyOptions int
|
dependencyOptions int
|
||||||
architecturesList []string
|
architecturesList []string
|
||||||
// Debug features
|
// Debug features
|
||||||
@@ -33,92 +37,161 @@ var context struct {
|
|||||||
fileMemStats *os.File
|
fileMemStats *os.File
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitContext initializes context with default settings
|
var context *AptlyContext
|
||||||
func InitContext(cmd *commander.Command) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
context.dependencyOptions = 0
|
// FatalError is type for panicking to abort execution with non-zero
|
||||||
if utils.Config.DepFollowSuggests || cmd.Flag.Lookup("dep-follow-suggests").Value.Get().(bool) {
|
// exit code and print meaningful explanation
|
||||||
context.dependencyOptions |= debian.DepFollowSuggests
|
type FatalError struct {
|
||||||
}
|
ReturnCode int
|
||||||
if utils.Config.DepFollowRecommends || cmd.Flag.Lookup("dep-follow-recommends").Value.Get().(bool) {
|
Message string
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
context.architecturesList = utils.Config.Architectures
|
// Fatal panics and aborts execution with exit code 1
|
||||||
optionArchitectures := cmd.Flag.Lookup("architectures").Value.String()
|
func Fatal(err error) {
|
||||||
if optionArchitectures != "" {
|
panic(&FatalError{ReturnCode: 1, Message: err.Error()})
|
||||||
context.architecturesList = strings.Split(optionArchitectures, ",")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
context.progress = console.NewProgress()
|
// Config loads and returns current configuration
|
||||||
context.progress.Start()
|
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 {
|
if err != nil {
|
||||||
return err
|
Fatal(err)
|
||||||
}
|
}
|
||||||
pprof.StartCPUProfile(context.fileCPUProfile)
|
} else {
|
||||||
}
|
configLocations := []string{
|
||||||
|
filepath.Join(os.Getenv("HOME"), ".aptly.conf"),
|
||||||
memprofile := cmd.Flag.Lookup("memprofile").Value.String()
|
"/etc/aptly.conf",
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.fileMemStats.WriteString("# Time\tHeapSys\tHeapAlloc\tHeapIdle\tHeapReleased\n")
|
for _, configLocation := range configLocations {
|
||||||
|
err = utils.LoadConfig(configLocation, &utils.Config)
|
||||||
go func() {
|
if err == nil {
|
||||||
var stats runtime.MemStats
|
break
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
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
|
// ShutdownContext shuts context down
|
||||||
@@ -149,3 +222,60 @@ func ShutdownContext() {
|
|||||||
context.progress.Shutdown()
|
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
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeCmdDb() *commander.Command {
|
func makeCmdDb() *commander.Command {
|
||||||
@@ -11,7 +10,7 @@ func makeCmdDb() *commander.Command {
|
|||||||
Short: "manage aptly's internal database and package pool",
|
Short: "manage aptly's internal database and package pool",
|
||||||
Subcommands: []*commander.Command{
|
Subcommands: []*commander.Command{
|
||||||
makeCmdDbCleanup(),
|
makeCmdDbCleanup(),
|
||||||
|
makeCmdDbRecover(),
|
||||||
},
|
},
|
||||||
Flag: *flag.NewFlagSet("aptly-db", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-41
@@ -2,10 +2,9 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
|
"github.com/smira/commander"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,12 +18,11 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// collect information about references packages...
|
// collect information about references packages...
|
||||||
existingPackageRefs := debian.NewPackageRefList()
|
existingPackageRefs := deb.NewPackageRefList()
|
||||||
|
|
||||||
context.progress.Printf("Loading mirrors, local repos and snapshots...\n")
|
context.Progress().Printf("Loading mirrors, local repos and snapshots...\n")
|
||||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
err = context.CollectionFactory().RemoteRepoCollection().ForEach(func(repo *deb.RemoteRepo) error {
|
||||||
err = repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
|
err := context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
|
||||||
err := repoCollection.LoadComplete(repo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -37,9 +35,8 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
localRepoCollection := debian.NewLocalRepoCollection(context.database)
|
err = context.CollectionFactory().LocalRepoCollection().ForEach(func(repo *deb.LocalRepo) error {
|
||||||
err = localRepoCollection.ForEach(func(repo *debian.LocalRepo) error {
|
err := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
|
||||||
err := localRepoCollection.LoadComplete(repo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -52,9 +49,8 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
err = context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
|
||||||
err = snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
|
err := context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
|
||||||
err := snapshotCollection.LoadComplete(snapshot)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -66,44 +62,45 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ... and compare it to the list of all packages
|
// ... and compare it to the list of all packages
|
||||||
context.progress.Printf("Loading list of all packages...\n")
|
context.Progress().Printf("Loading list of all packages...\n")
|
||||||
packageCollection := debian.NewPackageCollection(context.database)
|
allPackageRefs := context.CollectionFactory().PackageCollection().AllPackageRefs()
|
||||||
allPackageRefs := packageCollection.AllPackageRefs()
|
|
||||||
|
|
||||||
toDelete := allPackageRefs.Substract(existingPackageRefs)
|
toDelete := allPackageRefs.Substract(existingPackageRefs)
|
||||||
|
|
||||||
// delete packages that are no longer referenced
|
// 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 {
|
err = toDelete.ForEach(func(ref []byte) error {
|
||||||
return packageCollection.DeleteByKey(ref)
|
return context.CollectionFactory().PackageCollection().DeleteByKey(ref)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = context.database.FinishBatch()
|
err = db.FinishBatch()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to write to DB: %s", err)
|
return fmt.Errorf("unable to write to DB: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// now, build a list of files that should be present in Repository (package pool)
|
// 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())
|
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 {
|
err = existingPackageRefs.ForEach(func(key []byte) error {
|
||||||
pkg, err := packageCollection.ByKey(key)
|
pkg, err2 := context.CollectionFactory().PackageCollection().ByKey(key)
|
||||||
if err != nil {
|
if err2 != nil {
|
||||||
return err
|
return err2
|
||||||
}
|
}
|
||||||
paths, err := pkg.FilepathList(context.packagePool)
|
paths, err2 := pkg.FilepathList(context.PackagePool())
|
||||||
if err != nil {
|
if err2 != nil {
|
||||||
return err
|
return err2
|
||||||
}
|
}
|
||||||
referencedFiles = append(referencedFiles, paths...)
|
referencedFiles = append(referencedFiles, paths...)
|
||||||
context.progress.AddBar(1)
|
context.Progress().AddBar(1)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -112,11 +109,11 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(referencedFiles)
|
sort.Strings(referencedFiles)
|
||||||
context.progress.ShutdownBar()
|
context.Progress().ShutdownBar()
|
||||||
|
|
||||||
// build a list of files in the package pool
|
// build a list of files in the package pool
|
||||||
context.progress.Printf("Building list of files in package pool...\n")
|
context.Progress().Printf("Building list of files in package pool...\n")
|
||||||
existingFiles, err := context.packagePool.FilepathList(context.progress)
|
existingFiles, err := context.PackagePool().FilepathList(context.Progress())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to collect file paths: %s", err)
|
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)
|
filesToDelete := utils.StrSlicesSubstract(existingFiles, referencedFiles)
|
||||||
|
|
||||||
// delete files that are no longer referenced
|
// 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 {
|
if len(filesToDelete) > 0 {
|
||||||
context.progress.InitBar(int64(len(filesToDelete)), false)
|
context.Progress().InitBar(int64(len(filesToDelete)), false)
|
||||||
totalSize := int64(0)
|
|
||||||
|
var size, totalSize int64
|
||||||
for _, file := range filesToDelete {
|
for _, file := range filesToDelete {
|
||||||
size, err := context.packagePool.Remove(file)
|
size, err = context.PackagePool().Remove(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
context.progress.AddBar(1)
|
context.Progress().AddBar(1)
|
||||||
totalSize += size
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +161,6 @@ Example:
|
|||||||
|
|
||||||
$ aptly db cleanup
|
$ aptly db cleanup
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-db-cleanup", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
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"
|
"bytes"
|
||||||
"code.google.com/p/gographviz"
|
"code.google.com/p/gographviz"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@@ -29,10 +28,8 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
fmt.Printf("Loading mirrors...\n")
|
fmt.Printf("Loading mirrors...\n")
|
||||||
|
|
||||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
err = context.CollectionFactory().RemoteRepoCollection().ForEach(func(repo *deb.RemoteRepo) error {
|
||||||
|
err := context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
|
||||||
err = repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
|
|
||||||
err := repoCollection.LoadComplete(repo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -55,10 +52,8 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
fmt.Printf("Loading local repos...\n")
|
fmt.Printf("Loading local repos...\n")
|
||||||
|
|
||||||
localRepoCollection := debian.NewLocalRepoCollection(context.database)
|
err = context.CollectionFactory().LocalRepoCollection().ForEach(func(repo *deb.LocalRepo) error {
|
||||||
|
err := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
|
||||||
err = localRepoCollection.ForEach(func(repo *debian.LocalRepo) error {
|
|
||||||
err := localRepoCollection.LoadComplete(repo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -80,15 +75,13 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
fmt.Printf("Loading snapshots...\n")
|
fmt.Printf("Loading snapshots...\n")
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
|
||||||
|
|
||||||
snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
|
|
||||||
existingNodes[snapshot.UUID] = true
|
existingNodes[snapshot.UUID] = true
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
err = snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
|
err = context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
|
||||||
err := snapshotCollection.LoadComplete(snapshot)
|
err := context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -122,9 +115,7 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
fmt.Printf("Loading published repos...\n")
|
fmt.Printf("Loading published repos...\n")
|
||||||
|
|
||||||
publishedCollection := debian.NewPublishedRepoCollection(context.database)
|
context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error {
|
||||||
|
|
||||||
publishedCollection.ForEach(func(repo *debian.PublishedRepo) error {
|
|
||||||
graph.AddNode("aptly", graphvizEscape(repo.UUID), map[string]string{
|
graph.AddNode("aptly", graphvizEscape(repo.UUID), map[string]string{
|
||||||
"shape": "Mrecord",
|
"shape": "Mrecord",
|
||||||
"style": "filled",
|
"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, ", "))),
|
"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 {
|
if exists {
|
||||||
graph.AddEdge(graphvizEscape(repo.SnapshotUUID), "", graphvizEscape(repo.UUID), "", true, nil)
|
graph.AddEdge(graphvizEscape(repo.SourceUUID), "", graphvizEscape(repo.UUID), "", true, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -198,13 +189,12 @@ func makeCmdGraph() *commander.Command {
|
|||||||
Long: `
|
Long: `
|
||||||
Command graph displays relationship between mirrors, local repositories,
|
Command graph displays relationship between mirrors, local repositories,
|
||||||
snapshots and published repositories using graphviz package to render
|
snapshots and published repositories using graphviz package to render
|
||||||
graph as image.
|
graph as an image.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
$ aptly graph
|
$ aptly graph
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-graph", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|||||||
+7
-8
@@ -1,19 +1,21 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gonuts/commander"
|
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
|
"github.com/smira/commander"
|
||||||
|
"github.com/smira/flag"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getVerifier(cmd *commander.Command) (utils.Verifier, error) {
|
func getVerifier(flags *flag.FlagSet) (utils.Verifier, error) {
|
||||||
if utils.Config.GpgDisableVerify || cmd.Flag.Lookup("ignore-signatures").Value.Get().(bool) {
|
if context.Config().GpgDisableVerify || flags.Lookup("ignore-signatures").Value.Get().(bool) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyRings := flags.Lookup("keyring").Value.Get().([]string)
|
||||||
|
|
||||||
verifier := &utils.GpgVerifier{}
|
verifier := &utils.GpgVerifier{}
|
||||||
for _, keyRing := range keyRings.keyRings {
|
for _, keyRing := range keyRings {
|
||||||
verifier.AddKeyring(keyRing)
|
verifier.AddKeyring(keyRing)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +44,6 @@ func (k *keyRingsFlag) String() string {
|
|||||||
return strings.Join(k.keyRings, ",")
|
return strings.Join(k.keyRings, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyRings = keyRingsFlag{}
|
|
||||||
|
|
||||||
func makeCmdMirror() *commander.Command {
|
func makeCmdMirror() *commander.Command {
|
||||||
return &commander.Command{
|
return &commander.Command{
|
||||||
UsageLine: "mirror",
|
UsageLine: "mirror",
|
||||||
@@ -55,6 +55,5 @@ func makeCmdMirror() *commander.Command {
|
|||||||
makeCmdMirrorDrop(),
|
makeCmdMirrorDrop(),
|
||||||
makeCmdMirrorUpdate(),
|
makeCmdMirrorUpdate(),
|
||||||
},
|
},
|
||||||
Flag: *flag.NewFlagSet("aptly-mirror", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-14
@@ -2,10 +2,9 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
"github.com/smira/flag"
|
||||||
"github.com/smira/aptly/utils"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,7 +15,7 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
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 (
|
var (
|
||||||
mirrorName, archiveURL, distribution string
|
mirrorName, archiveURL, distribution string
|
||||||
@@ -25,7 +24,7 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
mirrorName = args[0]
|
mirrorName = args[0]
|
||||||
if len(args) == 2 {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -33,24 +32,22 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error {
|
|||||||
archiveURL, distribution, components = args[1], args[2], args[3:]
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create mirror: %s", err)
|
return fmt.Errorf("unable to create mirror: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
verifier, err := getVerifier(cmd)
|
verifier, err := getVerifier(context.flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to initialize GPG verifier: %s", err)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to fetch mirror: %s", err)
|
return fmt.Errorf("unable to fetch mirror: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
err = context.CollectionFactory().RemoteRepoCollection().Add(repo)
|
||||||
|
|
||||||
err = repoCollection.Add(repo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to add mirror: %s", err)
|
return fmt.Errorf("unable to add mirror: %s", err)
|
||||||
}
|
}
|
||||||
@@ -66,7 +63,8 @@ func makeCmdMirrorCreate() *commander.Command {
|
|||||||
Short: "create new mirror",
|
Short: "create new mirror",
|
||||||
Long: `
|
Long: `
|
||||||
Creates mirror <name> of remote repository, aptly supports both regular and flat Debian repositories exported
|
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:
|
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("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.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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-10
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/flag"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlyMirrorDrop(cmd *commander.Command, args []string) error {
|
func aptlyMirrorDrop(cmd *commander.Command, args []string) error {
|
||||||
@@ -16,16 +15,14 @@ func aptlyMirrorDrop(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
repo, err := context.CollectionFactory().RemoteRepoCollection().ByName(name)
|
||||||
repo, err := repoCollection.ByName(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to drop: %s", err)
|
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 {
|
if !force {
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
snapshots := context.CollectionFactory().SnapshotCollection().ByRemoteRepoSource(repo)
|
||||||
snapshots := snapshotCollection.ByRemoteRepoSource(repo)
|
|
||||||
|
|
||||||
if len(snapshots) > 0 {
|
if len(snapshots) > 0 {
|
||||||
fmt.Printf("Mirror `%s` was used to create following snapshots:\n", repo.Name)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to drop: %s", err)
|
return fmt.Errorf("unable to drop: %s", err)
|
||||||
}
|
}
|
||||||
@@ -54,7 +51,7 @@ func makeCmdMirrorDrop() *commander.Command {
|
|||||||
Short: "delete mirror",
|
Short: "delete mirror",
|
||||||
Long: `
|
Long: `
|
||||||
Drop deletes information about remote repository mirror <name>. Package data is not deleted
|
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.
|
to create a snapshot, aptly would refuse to delete such mirror, use flag -force to override.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|||||||
+30
-19
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,26 +14,37 @@ func aptlyMirrorList(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
|
||||||
|
|
||||||
if repoCollection.Len() > 0 {
|
repos := make([]string, context.CollectionFactory().RemoteRepoCollection().Len())
|
||||||
fmt.Printf("List of mirrors:\n")
|
i := 0
|
||||||
repos := make([]string, repoCollection.Len())
|
context.CollectionFactory().RemoteRepoCollection().ForEach(func(repo *deb.RemoteRepo) error {
|
||||||
i := 0
|
if raw {
|
||||||
repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
|
repos[i] = repo.Name
|
||||||
|
} else {
|
||||||
repos[i] = repo.String()
|
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 {
|
} 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
|
return err
|
||||||
}
|
}
|
||||||
@@ -51,8 +61,9 @@ Example:
|
|||||||
|
|
||||||
$ aptly mirror list
|
$ aptly mirror list
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-mirror-list", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flag.Bool("raw", false, "display list in machine-readable format")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-8
@@ -2,10 +2,9 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
|
"github.com/smira/commander"
|
||||||
|
"github.com/smira/flag"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,13 +17,12 @@ func aptlyMirrorShow(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
repo, err := context.CollectionFactory().RemoteRepoCollection().ByName(name)
|
||||||
repo, err := repoCollection.ByName(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to show: %s", err)
|
return fmt.Errorf("unable to show: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = repoCollection.LoadComplete(repo)
|
err = context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to show: %s", err)
|
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])
|
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 withPackages {
|
||||||
if repo.LastDownloadDate.IsZero() {
|
if repo.LastDownloadDate.IsZero() {
|
||||||
fmt.Printf("Unable to show package list, mirror hasn't been downloaded yet.\n")
|
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>",
|
UsageLine: "show <name>",
|
||||||
Short: "show details about mirror",
|
Short: "show details about mirror",
|
||||||
Long: `
|
Long: `
|
||||||
Shows detailed information about mirror.
|
Shows detailed information about the mirror.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|||||||
+13
-17
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/flag"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
|
func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
|
||||||
@@ -16,42 +15,39 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
repo, err := context.CollectionFactory().RemoteRepoCollection().ByName(name)
|
||||||
repo, err := repoCollection.ByName(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to update: %s", err)
|
return fmt.Errorf("unable to update: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = repoCollection.LoadComplete(repo)
|
err = context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to update: %s", err)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to initialize GPG verifier: %s", err)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to update: %s", err)
|
return fmt.Errorf("unable to update: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
packageCollection := debian.NewPackageCollection(context.database)
|
err = repo.Download(context.Progress(), context.Downloader(), context.CollectionFactory(), context.PackagePool(), ignoreMismatch)
|
||||||
|
|
||||||
err = repo.Download(context.progress, context.downloader, packageCollection, context.packagePool, ignoreMismatch)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to update: %s", err)
|
return fmt.Errorf("unable to update: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = repoCollection.Update(repo)
|
err = context.CollectionFactory().RemoteRepoCollection().Update(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to update: %s", err)
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +58,8 @@ func makeCmdMirrorUpdate() *commander.Command {
|
|||||||
Short: "update mirror",
|
Short: "update mirror",
|
||||||
Long: `
|
Long: `
|
||||||
Updates remote mirror (downloads package files and meta information). When mirror is created,
|
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
|
this command should be run for the first time to fetch mirror contents. This command can be
|
||||||
run many times to get updated repository contents. If interrupted, command could be restarted safely.
|
run multiple times to get updated repository contents. If interrupted, command can be safely restarted.
|
||||||
|
|
||||||
Example:
|
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-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.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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-9
@@ -1,19 +1,19 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gonuts/commander"
|
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
|
"github.com/smira/commander"
|
||||||
|
"github.com/smira/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getSigner(cmd *commander.Command) (utils.Signer, error) {
|
func getSigner(flags *flag.FlagSet) (utils.Signer, error) {
|
||||||
if cmd.Flag.Lookup("skip-signing").Value.Get().(bool) || utils.Config.GpgDisableSign {
|
if flags.Lookup("skip-signing").Value.Get().(bool) || context.Config().GpgDisableSign {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
signer := &utils.GpgSigner{}
|
signer := &utils.GpgSigner{}
|
||||||
signer.SetKey(cmd.Flag.Lookup("gpg-key").Value.String())
|
signer.SetKey(flags.Lookup("gpg-key").Value.String())
|
||||||
signer.SetKeyRing(cmd.Flag.Lookup("keyring").Value.String(), cmd.Flag.Lookup("secret-keyring").Value.String())
|
signer.SetKeyRing(flags.Lookup("keyring").Value.String(), flags.Lookup("secret-keyring").Value.String())
|
||||||
|
|
||||||
err := signer.Init()
|
err := signer.Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -29,10 +29,12 @@ func makeCmdPublish() *commander.Command {
|
|||||||
UsageLine: "publish",
|
UsageLine: "publish",
|
||||||
Short: "manage published repositories",
|
Short: "manage published repositories",
|
||||||
Subcommands: []*commander.Command{
|
Subcommands: []*commander.Command{
|
||||||
makeCmdPublishSnapshot(),
|
|
||||||
makeCmdPublishList(),
|
|
||||||
makeCmdPublishDrop(),
|
makeCmdPublishDrop(),
|
||||||
|
makeCmdPublishList(),
|
||||||
|
makeCmdPublishRepo(),
|
||||||
|
makeCmdPublishSnapshot(),
|
||||||
|
makeCmdPublishSwitch(),
|
||||||
|
makeCmdPublishUpdate(),
|
||||||
},
|
},
|
||||||
Flag: *flag.NewFlagSet("aptly-publish", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-8
@@ -2,9 +2,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlyPublishDrop(cmd *commander.Command, args []string) error {
|
func aptlyPublishDrop(cmd *commander.Command, args []string) error {
|
||||||
@@ -21,14 +19,13 @@ func aptlyPublishDrop(cmd *commander.Command, args []string) error {
|
|||||||
prefix = args[1]
|
prefix = args[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
|
err = context.CollectionFactory().PublishedRepoCollection().Remove(context.PublishedStorage(), prefix, distribution,
|
||||||
|
context.CollectionFactory(), context.Progress())
|
||||||
err = publishedCollecton.Remove(context.publishedStorage, prefix, distribution)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to remove: %s", err)
|
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
|
return err
|
||||||
}
|
}
|
||||||
@@ -46,7 +43,6 @@ Example:
|
|||||||
|
|
||||||
$ aptly publish drop wheezy
|
$ aptly publish drop wheezy
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-publish-drop", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|||||||
+27
-18
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,23 +14,21 @@ func aptlyPublishList(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
|
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
|
||||||
|
|
||||||
if publishedCollecton.Len() == 0 {
|
published := make([]string, 0, context.CollectionFactory().PublishedRepoCollection().Len())
|
||||||
fmt.Printf("No snapshots have been published. Publish a snapshot by running `aptly publish snapshot ...`.\n")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
published := make([]string, 0, publishedCollecton.Len())
|
err = context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error {
|
||||||
|
err := context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
|
||||||
err = publishedCollecton.ForEach(func(repo *debian.PublishedRepo) error {
|
|
||||||
err := publishedCollecton.LoadComplete(repo, snapshotCollection)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -41,10 +38,21 @@ func aptlyPublishList(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
sort.Strings(published)
|
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("Published repositories:\n")
|
||||||
fmt.Printf(" * %s\n", description)
|
|
||||||
|
for _, description := range published {
|
||||||
|
fmt.Printf(" * %s\n", description)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
@@ -62,8 +70,9 @@ Example:
|
|||||||
|
|
||||||
$ aptly publish list
|
$ aptly publish list
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-publish-list", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flag.Bool("raw", false, "display list in machine-readable format")
|
||||||
|
|
||||||
return cmd
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
|
"github.com/smira/commander"
|
||||||
|
"github.com/smira/flag"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
|
func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
|
||||||
var err error
|
var err error
|
||||||
if len(args) < 1 || len(args) > 2 {
|
if len(args) < 1 || len(args) > 2 {
|
||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
@@ -25,98 +25,101 @@ func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
|
|||||||
prefix = ""
|
prefix = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
|
var (
|
||||||
|
source interface{}
|
||||||
|
message string
|
||||||
|
)
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
if cmd.Name() == "snapshot" {
|
||||||
snapshot, err := snapshotCollection.ByName(name)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to publish: %s", err)
|
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)
|
duplicate := context.CollectionFactory().PublishedRepoCollection().CheckDuplicate(published)
|
||||||
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)
|
|
||||||
if duplicate != nil {
|
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)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to initialize GPG signer: %s", err)
|
return fmt.Errorf("unable to initialize GPG signer: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
packageCollection := debian.NewPackageCollection(context.database)
|
err = published.Publish(context.PackagePool(), context.PublishedStorage(), context.CollectionFactory(), signer, context.Progress())
|
||||||
err = published.Publish(context.packagePool, context.publishedStorage, packageCollection, signer, context.progress)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to publish: %s", err)
|
return fmt.Errorf("unable to publish: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = publishedCollecton.Add(published)
|
err = context.CollectionFactory().PublishedRepoCollection().Add(published)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to save to DB: %s", err)
|
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 += "/"
|
prefix += "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
context.progress.Printf("\nSnapshot %s has been successfully published.\nPlease setup your webserver to serve directory '%s' with autoindexing.\n",
|
context.Progress().Printf("\n%s has been successfully published.\nPlease setup your webserver to serve directory '%s' with autoindexing.\n",
|
||||||
snapshot.Name, context.publishedStorage.PublicPath())
|
message, context.PublishedStorage().PublicPath())
|
||||||
context.progress.Printf("Now you can add following line to apt sources:\n")
|
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(" deb http://your-server/%s %s %s\n", prefix, distribution, component)
|
||||||
if utils.StrSliceHasItem(published.Architectures, "source") {
|
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("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("\nYou can also use `aptly serve` to publish your repositories over HTTP quickly.\n")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeCmdPublishSnapshot() *commander.Command {
|
func makeCmdPublishSnapshot() *commander.Command {
|
||||||
cmd := &commander.Command{
|
cmd := &commander.Command{
|
||||||
Run: aptlyPublishSnapshot,
|
Run: aptlyPublishSnapshotOrRepo,
|
||||||
UsageLine: "snapshot <name> [<prefix>]",
|
UsageLine: "snapshot <name> [<prefix>]",
|
||||||
Short: "publish snapshot",
|
Short: "publish snapshot",
|
||||||
Long: `
|
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.
|
by apt tools. Published repostiories appear under rootDir/public directory.
|
||||||
Valid GPG key is required for publishing.
|
Valid GPG key is required for publishing.
|
||||||
|
|
||||||
@@ -129,9 +132,11 @@ Example:
|
|||||||
cmd.Flag.String("distribution", "", "distribution name to publish")
|
cmd.Flag.String("distribution", "", "distribution name to publish")
|
||||||
cmd.Flag.String("component", "", "component 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("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.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.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
|
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
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeCmdRepo() *commander.Command {
|
func makeCmdRepo() *commander.Command {
|
||||||
@@ -14,12 +13,12 @@ func makeCmdRepo() *commander.Command {
|
|||||||
makeCmdRepoCopy(),
|
makeCmdRepoCopy(),
|
||||||
makeCmdRepoCreate(),
|
makeCmdRepoCreate(),
|
||||||
makeCmdRepoDrop(),
|
makeCmdRepoDrop(),
|
||||||
|
makeCmdRepoEdit(),
|
||||||
makeCmdRepoImport(),
|
makeCmdRepoImport(),
|
||||||
makeCmdRepoList(),
|
makeCmdRepoList(),
|
||||||
makeCmdRepoMove(),
|
makeCmdRepoMove(),
|
||||||
makeCmdRepoRemove(),
|
makeCmdRepoRemove(),
|
||||||
makeCmdRepoShow(),
|
makeCmdRepoShow(),
|
||||||
},
|
},
|
||||||
Flag: *flag.NewFlagSet("aptly-repo", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-41
@@ -2,10 +2,10 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
|
"github.com/smira/commander"
|
||||||
|
"github.com/smira/flag"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -23,21 +23,19 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
verifier := &utils.GpgVerifier{}
|
verifier := &utils.GpgVerifier{}
|
||||||
|
|
||||||
localRepoCollection := debian.NewLocalRepoCollection(context.database)
|
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
|
||||||
repo, err := localRepoCollection.ByName(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to add: %s", err)
|
return fmt.Errorf("unable to add: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = localRepoCollection.LoadComplete(repo)
|
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to add: %s", err)
|
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 := deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
|
||||||
list, err := debian.NewPackageListFromRefList(repo.RefList(), packageCollection, context.progress)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load packages: %s", err)
|
return fmt.Errorf("unable to load packages: %s", err)
|
||||||
}
|
}
|
||||||
@@ -45,15 +43,15 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
|
|||||||
packageFiles := []string{}
|
packageFiles := []string{}
|
||||||
|
|
||||||
for _, location := range args[1:] {
|
for _, location := range args[1:] {
|
||||||
info, err := os.Stat(location)
|
info, err2 := os.Stat(location)
|
||||||
if err != nil {
|
if err2 != nil {
|
||||||
context.progress.ColoredPrintf("@y[!]@| @!Unable to process %s: %s@|", location, err)
|
context.Progress().ColoredPrintf("@y[!]@| @!Unable to process %s: %s@|", location, err2)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
err = filepath.Walk(location, func(path string, info os.FileInfo, err error) error {
|
err2 = filepath.Walk(location, func(path string, info os.FileInfo, err3 error) error {
|
||||||
if err != nil {
|
if err3 != nil {
|
||||||
return err
|
return err3
|
||||||
}
|
}
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
return nil
|
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") {
|
if strings.HasSuffix(info.Name(), ".deb") || strings.HasSuffix(info.Name(), ".dsc") {
|
||||||
packageFiles = append(packageFiles, location)
|
packageFiles = append(packageFiles, location)
|
||||||
} else {
|
} else {
|
||||||
context.progress.ColoredPrintf("@y[!]@| @!Unknwon file extenstion: %s@|", location)
|
context.Progress().ColoredPrintf("@y[!]@| @!Unknwon file extenstion: %s@|", location)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,46 +78,46 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
for _, file := range packageFiles {
|
for _, file := range packageFiles {
|
||||||
var (
|
var (
|
||||||
stanza debian.Stanza
|
stanza deb.Stanza
|
||||||
err error
|
p *deb.Package
|
||||||
p *debian.Package
|
|
||||||
)
|
)
|
||||||
|
|
||||||
candidateProcessedFiles := []string{}
|
candidateProcessedFiles := []string{}
|
||||||
isSourcePackage := strings.HasSuffix(file, ".dsc")
|
isSourcePackage := strings.HasSuffix(file, ".dsc")
|
||||||
|
|
||||||
if isSourcePackage {
|
if isSourcePackage {
|
||||||
stanza, err = debian.GetControlFileFromDsc(file, verifier)
|
stanza, err = deb.GetControlFileFromDsc(file, verifier)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
stanza["Package"] = stanza["Source"]
|
stanza["Package"] = stanza["Source"]
|
||||||
delete(stanza, "Source")
|
delete(stanza, "Source")
|
||||||
|
|
||||||
p, err = debian.NewSourcePackageFromControlFile(stanza)
|
p, err = deb.NewSourcePackageFromControlFile(stanza)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
stanza, err = debian.GetControlFileFromDeb(file)
|
stanza, err = deb.GetControlFileFromDeb(file)
|
||||||
p = debian.NewPackageFromControlFile(stanza)
|
p = deb.NewPackageFromControlFile(stanza)
|
||||||
}
|
}
|
||||||
if err != nil {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
checksums, err := utils.ChecksumsForFile(file)
|
var checksums utils.ChecksumInfo
|
||||||
|
checksums, err = utils.ChecksumsForFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSourcePackage {
|
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 {
|
} 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 {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,9 +129,9 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sourceFile := filepath.Join(filepath.Dir(file), filepath.Base(f.Filename))
|
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 {
|
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
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,30 +142,30 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = packageCollection.Update(p)
|
err = context.CollectionFactory().PackageCollection().Update(p)
|
||||||
if err != nil {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = list.Add(p)
|
err = list.Add(p)
|
||||||
if err != nil {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
context.progress.ColoredPrintf("@g[+]@| %s added@|", p)
|
context.Progress().ColoredPrintf("@g[+]@| %s added@|", p)
|
||||||
processedFiles = append(processedFiles, candidateProcessedFiles...)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to save: %s", err)
|
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)
|
processedFiles = utils.StrSliceDeduplicate(processedFiles)
|
||||||
|
|
||||||
for _, file := range processedFiles {
|
for _, file := range processedFiles {
|
||||||
@@ -189,9 +187,9 @@ func makeCmdRepoAdd() *commander.Command {
|
|||||||
Long: `
|
Long: `
|
||||||
Command adds packages to local repository from .deb (binary packages) and .dsc (source packages) files.
|
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
|
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
|
patterns. Every file discovered would be analyzed to extract metadata, package would then be created and added
|
||||||
to database. Files would be imported to internal package pool. For source packages, all required files are
|
to the 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.
|
added automatically as well. Extra files for source package should be in the same directory as *.dsc file.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeCmdRepoCopy() *commander.Command {
|
func makeCmdRepoCopy() *commander.Command {
|
||||||
|
|||||||
+9
-7
@@ -2,9 +2,9 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
"github.com/smira/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlyRepoCreate(cmd *commander.Command, args []string) error {
|
func aptlyRepoCreate(cmd *commander.Command, args []string) error {
|
||||||
@@ -14,11 +14,11 @@ func aptlyRepoCreate(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
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 = context.CollectionFactory().LocalRepoCollection().Add(repo)
|
||||||
|
|
||||||
err = localRepoCollection.Add(repo)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to add local repo: %s", err)
|
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("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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-11
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/flag"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlyRepoDrop(cmd *commander.Command, args []string) error {
|
func aptlyRepoDrop(cmd *commander.Command, args []string) error {
|
||||||
@@ -16,16 +15,28 @@ func aptlyRepoDrop(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
localRepoCollection := debian.NewLocalRepoCollection(context.database)
|
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
|
||||||
repo, err := localRepoCollection.ByName(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to drop: %s", err)
|
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 {
|
if !force {
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
snapshots := context.CollectionFactory().SnapshotCollection().ByLocalRepoSource(repo)
|
||||||
snapshots := snapshotCollection.ByLocalRepoSource(repo)
|
|
||||||
|
|
||||||
if len(snapshots) > 0 {
|
if len(snapshots) > 0 {
|
||||||
fmt.Printf("Local repo `%s` was used to create following snapshots:\n", repo.Name)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to drop: %s", err)
|
return fmt.Errorf("unable to drop: %s", err)
|
||||||
}
|
}
|
||||||
@@ -53,8 +64,8 @@ func makeCmdRepoDrop() *commander.Command {
|
|||||||
UsageLine: "drop <name>",
|
UsageLine: "drop <name>",
|
||||||
Short: "delete local repository",
|
Short: "delete local repository",
|
||||||
Long: `
|
Long: `
|
||||||
Drop deletes information about local repo. Package data is not deleted
|
Drop information about deletions from local repo. Package data is not deleted
|
||||||
(it could be still used by other mirrors or snapshots).
|
(since it could be still used by other mirrors or snapshots).
|
||||||
|
|
||||||
Example:
|
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
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeCmdRepoImport() *commander.Command {
|
func makeCmdRepoImport() *commander.Command {
|
||||||
|
|||||||
+33
-21
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,32 +14,44 @@ func aptlyRepoList(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
localRepoCollection := debian.NewLocalRepoCollection(context.database)
|
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
|
||||||
|
|
||||||
if localRepoCollection.Len() > 0 {
|
repos := make([]string, context.CollectionFactory().LocalRepoCollection().Len())
|
||||||
fmt.Printf("List of mirrors:\n")
|
i := 0
|
||||||
repos := make([]string, localRepoCollection.Len())
|
context.CollectionFactory().LocalRepoCollection().ForEach(func(repo *deb.LocalRepo) error {
|
||||||
i := 0
|
if raw {
|
||||||
localRepoCollection.ForEach(func(repo *debian.LocalRepo) error {
|
repos[i] = repo.Name
|
||||||
err := localRepoCollection.LoadComplete(repo)
|
} else {
|
||||||
|
err := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repos[i] = fmt.Sprintf(" * %s (packages: %d)", repo.String(), repo.NumPackages())
|
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 {
|
} 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,14 +61,15 @@ func makeCmdRepoList() *commander.Command {
|
|||||||
UsageLine: "list",
|
UsageLine: "list",
|
||||||
Short: "list local repositories",
|
Short: "list local repositories",
|
||||||
Long: `
|
Long: `
|
||||||
List shows full list of local package repositories.
|
List command shows full list of local package repositories.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
$ aptly repo list
|
$ aptly repo list
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-repo-list", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flag.Bool("raw", false, "display list in machine-readable format")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-32
@@ -2,9 +2,9 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
"github.com/smira/flag"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,25 +17,23 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
command := cmd.Name()
|
command := cmd.Name()
|
||||||
|
|
||||||
localRepoCollection := debian.NewLocalRepoCollection(context.database)
|
dstRepo, err := context.CollectionFactory().LocalRepoCollection().ByName(args[1])
|
||||||
|
|
||||||
dstRepo, err := localRepoCollection.ByName(args[1])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to %s: %s", command, err)
|
return fmt.Errorf("unable to %s: %s", command, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = localRepoCollection.LoadComplete(dstRepo)
|
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(dstRepo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to %s: %s", command, err)
|
return fmt.Errorf("unable to %s: %s", command, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
srcRefList *debian.PackageRefList
|
srcRefList *deb.PackageRefList
|
||||||
srcRepo *debian.LocalRepo
|
srcRepo *deb.LocalRepo
|
||||||
)
|
)
|
||||||
|
|
||||||
if command == "copy" || command == "move" {
|
if command == "copy" || command == "move" {
|
||||||
srcRepo, err = localRepoCollection.ByName(args[0])
|
srcRepo, err = context.CollectionFactory().LocalRepoCollection().ByName(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to %s: %s", command, err)
|
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)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to %s: %s", command, err)
|
return fmt.Errorf("unable to %s: %s", command, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
srcRefList = srcRepo.RefList()
|
srcRefList = srcRepo.RefList()
|
||||||
} else if command == "import" {
|
} 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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to %s: %s", command, err)
|
return fmt.Errorf("unable to %s: %s", command, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = repoCollection.LoadComplete(srcRepo)
|
err = context.CollectionFactory().RemoteRepoCollection().LoadComplete(srcRemoteRepo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to %s: %s", command, err)
|
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)
|
return fmt.Errorf("unable to %s: mirror not updated", command)
|
||||||
}
|
}
|
||||||
|
|
||||||
srcRefList = srcRepo.RefList()
|
srcRefList = srcRemoteRepo.RefList()
|
||||||
} else {
|
} else {
|
||||||
panic("unexpected command")
|
panic("unexpected command")
|
||||||
}
|
}
|
||||||
|
|
||||||
context.progress.Printf("Loading packages...\n")
|
context.Progress().Printf("Loading packages...\n")
|
||||||
|
|
||||||
packageCollection := debian.NewPackageCollection(context.database)
|
dstList, err := deb.NewPackageListFromRefList(dstRepo.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
|
||||||
dstList, err := debian.NewPackageListFromRefList(dstRepo.RefList(), packageCollection, context.progress)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load packages: %s", err)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load packages: %s", err)
|
return fmt.Errorf("unable to load packages: %s", err)
|
||||||
}
|
}
|
||||||
@@ -89,14 +86,14 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
var architecturesList []string
|
var architecturesList []string
|
||||||
|
|
||||||
withDeps := cmd.Flag.Lookup("with-deps").Value.Get().(bool)
|
withDeps := context.flags.Lookup("with-deps").Value.Get().(bool)
|
||||||
|
|
||||||
if withDeps {
|
if withDeps {
|
||||||
dstList.PrepareIndex()
|
dstList.PrepareIndex()
|
||||||
|
|
||||||
// Calculate architectures
|
// Calculate architectures
|
||||||
if len(context.architecturesList) > 0 {
|
if len(context.ArchitecturesList()) > 0 {
|
||||||
architecturesList = context.architecturesList
|
architecturesList = context.ArchitecturesList()
|
||||||
} else {
|
} else {
|
||||||
architecturesList = dstList.Architectures(false)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to %s: %s", command, err)
|
return fmt.Errorf("unable to %s: %s", command, err)
|
||||||
}
|
}
|
||||||
@@ -123,7 +120,7 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
|
|||||||
verb = "imported"
|
verb = "imported"
|
||||||
}
|
}
|
||||||
|
|
||||||
err = toProcess.ForEach(func(p *debian.Package) error {
|
err = toProcess.ForEach(func(p *deb.Package) error {
|
||||||
err = dstList.Add(p)
|
err = dstList.Add(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -132,27 +129,27 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
|
|||||||
if command == "move" {
|
if command == "move" {
|
||||||
srcList.Remove(p)
|
srcList.Remove(p)
|
||||||
}
|
}
|
||||||
context.progress.ColoredPrintf("@g[o]@| %s %s", p, verb)
|
context.Progress().ColoredPrintf("@g[o]@| %s %s", p, verb)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to %s: %s", command, err)
|
return fmt.Errorf("unable to %s: %s", command, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Flag.Lookup("dry-run").Value.Get().(bool) {
|
if context.flags.Lookup("dry-run").Value.Get().(bool) {
|
||||||
context.progress.Printf("\nChanges not saved, as dry run has been requested.\n")
|
context.Progress().Printf("\nChanges not saved, as dry run has been requested.\n")
|
||||||
} else {
|
} else {
|
||||||
dstRepo.UpdateRefList(debian.NewPackageRefListFromPackageList(dstList))
|
dstRepo.UpdateRefList(deb.NewPackageRefListFromPackageList(dstList))
|
||||||
|
|
||||||
err = localRepoCollection.Update(dstRepo)
|
err = context.CollectionFactory().LocalRepoCollection().Update(dstRepo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to save: %s", err)
|
return fmt.Errorf("unable to save: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if command == "move" {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to save: %s", err)
|
return fmt.Errorf("unable to save: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-15
@@ -2,9 +2,9 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
"github.com/smira/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlyRepoRemove(cmd *commander.Command, args []string) error {
|
func aptlyRepoRemove(cmd *commander.Command, args []string) error {
|
||||||
@@ -16,21 +16,19 @@ func aptlyRepoRemove(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
localRepoCollection := debian.NewLocalRepoCollection(context.database)
|
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
|
||||||
repo, err := localRepoCollection.ByName(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to remove: %s", err)
|
return fmt.Errorf("unable to remove: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = localRepoCollection.LoadComplete(repo)
|
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to remove: %s", err)
|
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 := deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
|
||||||
list, err := debian.NewPackageListFromRefList(repo.RefList(), packageCollection, context.progress)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load packages: %s", err)
|
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)
|
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)
|
list.Remove(p)
|
||||||
context.progress.ColoredPrintf("@r[-]@| %s removed", p)
|
context.Progress().ColoredPrintf("@r[-]@| %s removed", p)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if cmd.Flag.Lookup("dry-run").Value.Get().(bool) {
|
if context.flags.Lookup("dry-run").Value.Get().(bool) {
|
||||||
context.progress.Printf("\nChanges not saved, as dry run has been requested.\n")
|
context.Progress().Printf("\nChanges not saved, as dry run has been requested.\n")
|
||||||
} else {
|
} else {
|
||||||
repo.UpdateRefList(debian.NewPackageRefListFromPackageList(list))
|
repo.UpdateRefList(deb.NewPackageRefListFromPackageList(list))
|
||||||
|
|
||||||
err = localRepoCollection.Update(repo)
|
err = context.CollectionFactory().LocalRepoCollection().Update(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to save: %s", err)
|
return fmt.Errorf("unable to save: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/flag"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlyRepoShow(cmd *commander.Command, args []string) error {
|
func aptlyRepoShow(cmd *commander.Command, args []string) error {
|
||||||
@@ -16,22 +15,23 @@ func aptlyRepoShow(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
localRepoCollection := debian.NewLocalRepoCollection(context.database)
|
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
|
||||||
repo, err := localRepoCollection.ByName(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to show: %s", err)
|
return fmt.Errorf("unable to show: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = localRepoCollection.LoadComplete(repo)
|
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to show: %s", err)
|
return fmt.Errorf("unable to show: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Name: %s\n", repo.Name)
|
fmt.Printf("Name: %s\n", repo.Name)
|
||||||
fmt.Printf("Comment: %s\n", repo.Comment)
|
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())
|
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 {
|
if withPackages {
|
||||||
ListPackagesRefList(repo.RefList())
|
ListPackagesRefList(repo.RefList())
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ func makeCmdRepoShow() *commander.Command {
|
|||||||
UsageLine: "show <name>",
|
UsageLine: "show <name>",
|
||||||
Short: "show details about local repository",
|
Short: "show details about local repository",
|
||||||
Long: `
|
Long: `
|
||||||
Show shows full information about local package repository.
|
Show command shows full information about local package repository.
|
||||||
|
|
||||||
ex:
|
ex:
|
||||||
$ aptly repo show testing
|
$ aptly repo show testing
|
||||||
|
|||||||
+12
-14
@@ -2,10 +2,10 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
|
"github.com/smira/commander"
|
||||||
|
"github.com/smira/flag"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -15,15 +15,12 @@ import (
|
|||||||
func aptlyServe(cmd *commander.Command, args []string) error {
|
func aptlyServe(cmd *commander.Command, args []string) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
publishedCollection := debian.NewPublishedRepoCollection(context.database)
|
if context.CollectionFactory().PublishedRepoCollection().Len() == 0 {
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
|
||||||
|
|
||||||
if publishedCollection.Len() == 0 {
|
|
||||||
fmt.Printf("No published repositories, unable to serve.\n")
|
fmt.Printf("No published repositories, unable to serve.\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
listen := cmd.Flag.Lookup("listen").Value.String()
|
listen := context.flags.Lookup("listen").Value.String()
|
||||||
|
|
||||||
listenHost, listenPort, err := net.SplitHostPort(listen)
|
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")
|
fmt.Printf("Serving published repositories, recommended apt sources list:\n\n")
|
||||||
|
|
||||||
sources := make(sort.StringSlice, 0, publishedCollection.Len())
|
sources := make(sort.StringSlice, 0, context.CollectionFactory().PublishedRepoCollection().Len())
|
||||||
published := make(map[string]*debian.PublishedRepo, publishedCollection.Len())
|
published := make(map[string]*deb.PublishedRepo, context.CollectionFactory().PublishedRepoCollection().Len())
|
||||||
|
|
||||||
err = publishedCollection.ForEach(func(repo *debian.PublishedRepo) error {
|
err = context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error {
|
||||||
err := publishedCollection.LoadComplete(repo, snapshotCollection)
|
err := context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to serve: %s", err)
|
return fmt.Errorf("unable to serve: %s", err)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -1,8 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeCmdSnapshot() *commander.Command {
|
func makeCmdSnapshot() *commander.Command {
|
||||||
@@ -19,6 +18,5 @@ func makeCmdSnapshot() *commander.Command {
|
|||||||
makeCmdSnapshotMerge(),
|
makeCmdSnapshotMerge(),
|
||||||
makeCmdSnapshotDrop(),
|
makeCmdSnapshotDrop(),
|
||||||
},
|
},
|
||||||
Flag: *flag.NewFlagSet("aptly-snapshot", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-18
@@ -2,52 +2,53 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlySnapshotCreate(cmd *commander.Command, args []string) error {
|
func aptlySnapshotCreate(cmd *commander.Command, args []string) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
snapshot *debian.Snapshot
|
snapshot *deb.Snapshot
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(args) == 4 && args[1] == "from" && args[2] == "mirror" {
|
if len(args) == 4 && args[1] == "from" && args[2] == "mirror" {
|
||||||
// aptly snapshot create snap from mirror mirror
|
// aptly snapshot create snap from mirror mirror
|
||||||
|
var repo *deb.RemoteRepo
|
||||||
|
|
||||||
repoName, snapshotName := args[3], args[0]
|
repoName, snapshotName := args[3], args[0]
|
||||||
|
|
||||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
repo, err = context.CollectionFactory().RemoteRepoCollection().ByName(repoName)
|
||||||
repo, err := repoCollection.ByName(repoName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = repoCollection.LoadComplete(repo)
|
err = context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot, err = debian.NewSnapshotFromRepository(snapshotName, repo)
|
snapshot, err = deb.NewSnapshotFromRepository(snapshotName, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||||
}
|
}
|
||||||
} else if len(args) == 4 && args[1] == "from" && args[2] == "repo" {
|
} else if len(args) == 4 && args[1] == "from" && args[2] == "repo" {
|
||||||
// aptly snapshot create snap from repo repo
|
// aptly snapshot create snap from repo repo
|
||||||
|
var repo *deb.LocalRepo
|
||||||
|
|
||||||
localRepoName, snapshotName := args[3], args[0]
|
localRepoName, snapshotName := args[3], args[0]
|
||||||
|
|
||||||
localRepoCollection := debian.NewLocalRepoCollection(context.database)
|
repo, err = context.CollectionFactory().LocalRepoCollection().ByName(localRepoName)
|
||||||
repo, err := localRepoCollection.ByName(localRepoName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = localRepoCollection.LoadComplete(repo)
|
err = context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot, err = debian.NewSnapshotFromLocalRepo(snapshotName, repo)
|
snapshot, err = deb.NewSnapshotFromLocalRepo(snapshotName, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
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
|
// aptly snapshot create snap empty
|
||||||
snapshotName := args[0]
|
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 {
|
} else {
|
||||||
cmd.Usage()
|
cmd.Usage()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
err = context.CollectionFactory().SnapshotCollection().Add(snapshot)
|
||||||
|
|
||||||
err = snapshotCollection.Add(snapshot)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to add snapshot: %s", err)
|
return fmt.Errorf("unable to add snapshot: %s", err)
|
||||||
}
|
}
|
||||||
@@ -97,7 +96,6 @@ Example:
|
|||||||
|
|
||||||
$ aptly snapshot create wheezy-main-today from mirror wheezy-main
|
$ aptly snapshot create wheezy-main-today from mirror wheezy-main
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-snapshot-create", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|||||||
+11
-15
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/flag"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlySnapshotDiff(cmd *commander.Command, args []string) error {
|
func aptlySnapshotDiff(cmd *commander.Command, args []string) error {
|
||||||
@@ -14,43 +13,40 @@ func aptlySnapshotDiff(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
onlyMatching := cmd.Flag.Lookup("only-matching").Value.Get().(bool)
|
onlyMatching := context.flags.Lookup("only-matching").Value.Get().(bool)
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
|
||||||
packageCollection := debian.NewPackageCollection(context.database)
|
|
||||||
|
|
||||||
// Load <name-a> snapshot
|
// Load <name-a> snapshot
|
||||||
snapshotA, err := snapshotCollection.ByName(args[0])
|
snapshotA, err := context.CollectionFactory().SnapshotCollection().ByName(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load snapshot A: %s", err)
|
return fmt.Errorf("unable to load snapshot A: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snapshotCollection.LoadComplete(snapshotA)
|
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshotA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load snapshot A: %s", err)
|
return fmt.Errorf("unable to load snapshot A: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load <name-b> snapshot
|
// Load <name-b> snapshot
|
||||||
snapshotB, err := snapshotCollection.ByName(args[1])
|
snapshotB, err := context.CollectionFactory().SnapshotCollection().ByName(args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load snapshot B: %s", err)
|
return fmt.Errorf("unable to load snapshot B: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snapshotCollection.LoadComplete(snapshotB)
|
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshotB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load snapshot B: %s", err)
|
return fmt.Errorf("unable to load snapshot B: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate diff
|
// Calculate diff
|
||||||
diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), packageCollection)
|
diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), context.CollectionFactory().PackageCollection())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to calculate diff: %s", err)
|
return fmt.Errorf("unable to calculate diff: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(diff) == 0 {
|
if len(diff) == 0 {
|
||||||
context.progress.Printf("Snapshots are identical.\n")
|
context.Progress().Printf("Snapshots are identical.\n")
|
||||||
} else {
|
} 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 {
|
for _, pdiff := range diff {
|
||||||
if onlyMatching && (pdiff.Left == nil || pdiff.Right == nil) {
|
if onlyMatching && (pdiff.Left == nil || pdiff.Right == nil) {
|
||||||
continue
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/flag"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlySnapshotDrop(cmd *commander.Command, args []string) error {
|
func aptlySnapshotDrop(cmd *commander.Command, args []string) error {
|
||||||
@@ -16,19 +15,17 @@ func aptlySnapshotDrop(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
snapshot, err := context.CollectionFactory().SnapshotCollection().ByName(name)
|
||||||
snapshot, err := snapshotCollection.ByName(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to drop: %s", err)
|
return fmt.Errorf("unable to drop: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
publishedRepoCollection := debian.NewPublishedRepoCollection(context.database)
|
published := context.CollectionFactory().PublishedRepoCollection().BySnapshot(snapshot)
|
||||||
published := publishedRepoCollection.BySnapshot(snapshot)
|
|
||||||
|
|
||||||
if len(published) > 0 {
|
if len(published) > 0 {
|
||||||
fmt.Printf("Snapshot `%s` is published currently:\n", snapshot.Name)
|
fmt.Printf("Snapshot `%s` is published currently:\n", snapshot.Name)
|
||||||
for _, repo := range published {
|
for _, repo := range published {
|
||||||
err = publishedRepoCollection.LoadComplete(repo, snapshotCollection)
|
err = context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load published: %s", err)
|
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")
|
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 {
|
if !force {
|
||||||
snapshots := snapshotCollection.BySnapshotSource(snapshot)
|
snapshots := context.CollectionFactory().SnapshotCollection().BySnapshotSource(snapshot)
|
||||||
if len(snapshots) > 0 {
|
if len(snapshots) > 0 {
|
||||||
fmt.Printf("Snapshot `%s` was used as a source in following snapshots:\n", snapshot.Name)
|
fmt.Printf("Snapshot `%s` was used as a source in following snapshots:\n", snapshot.Name)
|
||||||
for _, snap := range snapshots {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to drop: %s", err)
|
return fmt.Errorf("unable to drop: %s", err)
|
||||||
}
|
}
|
||||||
@@ -67,7 +64,7 @@ func makeCmdSnapshotDrop() *commander.Command {
|
|||||||
UsageLine: "drop <name>",
|
UsageLine: "drop <name>",
|
||||||
Short: "delete snapshot",
|
Short: "delete snapshot",
|
||||||
Long: `
|
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.
|
it can't be dropped.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|||||||
+31
-20
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,28 +14,39 @@ func aptlySnapshotList(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
raw := cmd.Flag.Lookup("raw").Value.Get().(bool)
|
||||||
|
|
||||||
if snapshotCollection.Len() > 0 {
|
snapshots := make([]string, context.CollectionFactory().SnapshotCollection().Len())
|
||||||
fmt.Printf("List of snapshots:\n")
|
|
||||||
|
|
||||||
snapshots := make([]string, snapshotCollection.Len())
|
i := 0
|
||||||
|
context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
|
||||||
i := 0
|
if raw {
|
||||||
snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
|
snapshots[i] = snapshot.Name
|
||||||
|
} else {
|
||||||
snapshots[i] = snapshot.String()
|
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 {
|
} 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
|
return err
|
||||||
|
|
||||||
@@ -54,8 +64,9 @@ Example:
|
|||||||
|
|
||||||
$ aptly snapshot list
|
$ aptly snapshot list
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-snapshot-list", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flag.Bool("raw", false, "display list in machine-readable format")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-16
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,26 +14,31 @@ func aptlySnapshotMerge(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
sources := make([]*deb.Snapshot, len(args)-1)
|
||||||
|
|
||||||
sources := make([]*debian.Snapshot, len(args)-1)
|
|
||||||
|
|
||||||
for i := 0; i < len(args)-1; i++ {
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load snapshot: %s", err)
|
return fmt.Errorf("unable to load snapshot: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snapshotCollection.LoadComplete(sources[i])
|
err = context.CollectionFactory().SnapshotCollection().LoadComplete(sources[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load snapshot: %s", err)
|
return fmt.Errorf("unable to load snapshot: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
latest := context.flags.Lookup("latest").Value.Get().(bool)
|
||||||
|
overrideMatching := !latest
|
||||||
|
|
||||||
result := sources[0].RefList()
|
result := sources[0].RefList()
|
||||||
|
|
||||||
for i := 1; i < len(sources); i++ {
|
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))
|
sourceDescription := make([]string, len(sources))
|
||||||
@@ -43,10 +47,10 @@ func aptlySnapshotMerge(cmd *commander.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create <destination> snapshot
|
// 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, ", ")))
|
fmt.Sprintf("Merged from sources: %s", strings.Join(sourceDescription, ", ")))
|
||||||
|
|
||||||
err = snapshotCollection.Add(destination)
|
err = context.CollectionFactory().SnapshotCollection().Add(destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||||
}
|
}
|
||||||
@@ -62,18 +66,19 @@ func makeCmdSnapshotMerge() *commander.Command {
|
|||||||
UsageLine: "merge <destination> <source> [<source>...]",
|
UsageLine: "merge <destination> <source> [<source>...]",
|
||||||
Short: "merges snapshots",
|
Short: "merges snapshots",
|
||||||
Long: `
|
Long: `
|
||||||
Merge merges several <source> snapshots into one <destination> snapshot.
|
Merge command merges several <source> snapshots into one <destination> snapshot.
|
||||||
Merge happens from left to right. Packages with the same name-architecture
|
Merge happens from left to right. By default, packages with the same
|
||||||
pair are replaced during merge (package from latest snapshot on the list
|
name-architecture pair are replaced during merge (package from latest snapshot
|
||||||
wins). If run with only one source snapshot, merge copies <source> into
|
on the list wins). If run with only one source snapshot, merge copies <source> into
|
||||||
<destination>.
|
<destination>.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
$ aptly snapshot merge wheezy-w-backports wheezy-main wheezy-backports
|
$ 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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-37
@@ -2,9 +2,9 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
"github.com/smira/flag"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -16,58 +16,55 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
noDeps := cmd.Flag.Lookup("no-deps").Value.Get().(bool)
|
noDeps := context.flags.Lookup("no-deps").Value.Get().(bool)
|
||||||
noRemove := cmd.Flag.Lookup("no-remove").Value.Get().(bool)
|
noRemove := context.flags.Lookup("no-remove").Value.Get().(bool)
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
|
||||||
packageCollection := debian.NewPackageCollection(context.database)
|
|
||||||
|
|
||||||
// Load <name> snapshot
|
// Load <name> snapshot
|
||||||
snapshot, err := snapshotCollection.ByName(args[0])
|
snapshot, err := context.CollectionFactory().SnapshotCollection().ByName(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to pull: %s", err)
|
return fmt.Errorf("unable to pull: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snapshotCollection.LoadComplete(snapshot)
|
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to pull: %s", err)
|
return fmt.Errorf("unable to pull: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load <source> snapshot
|
// Load <source> snapshot
|
||||||
source, err := snapshotCollection.ByName(args[1])
|
source, err := context.CollectionFactory().SnapshotCollection().ByName(args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to pull: %s", err)
|
return fmt.Errorf("unable to pull: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snapshotCollection.LoadComplete(source)
|
err = context.CollectionFactory().SnapshotCollection().LoadComplete(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to pull: %s", err)
|
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])
|
snapshot, source, args[2])
|
||||||
|
|
||||||
// Convert snapshot to package list
|
// Convert snapshot to package list
|
||||||
context.progress.Printf("Loading packages (%d)...\n", snapshot.RefList().Len()+source.RefList().Len())
|
context.Progress().Printf("Loading packages (%d)...\n", snapshot.RefList().Len()+source.RefList().Len())
|
||||||
packageList, err := debian.NewPackageListFromRefList(snapshot.RefList(), packageCollection, context.progress)
|
packageList, err := deb.NewPackageListFromRefList(snapshot.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load packages: %s", err)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to load packages: %s", err)
|
return fmt.Errorf("unable to load packages: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
context.progress.Printf("Building indexes...\n")
|
context.Progress().Printf("Building indexes...\n")
|
||||||
packageList.PrepareIndex()
|
packageList.PrepareIndex()
|
||||||
sourcePackageList.PrepareIndex()
|
sourcePackageList.PrepareIndex()
|
||||||
|
|
||||||
// Calculate architectures
|
// Calculate architectures
|
||||||
var architecturesList []string
|
var architecturesList []string
|
||||||
|
|
||||||
if len(context.architecturesList) > 0 {
|
if len(context.ArchitecturesList()) > 0 {
|
||||||
architecturesList = context.architecturesList
|
architecturesList = context.ArchitecturesList()
|
||||||
} else {
|
} else {
|
||||||
architecturesList = packageList.Architectures(false)
|
architecturesList = packageList.Architectures(false)
|
||||||
}
|
}
|
||||||
@@ -79,9 +76,9 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initial dependencies out of arguments
|
// 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:] {
|
for i, arg := range args[3:] {
|
||||||
initialDependencies[i], err = debian.ParseDependency(arg)
|
initialDependencies[i], err = deb.ParseDependency(arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to parse argument: %s", err)
|
return fmt.Errorf("unable to parse argument: %s", err)
|
||||||
}
|
}
|
||||||
@@ -89,7 +86,7 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
// Perform pull
|
// Perform pull
|
||||||
for _, arch := range architecturesList {
|
for _, arch := range architecturesList {
|
||||||
dependencies := make([]debian.Dependency, len(initialDependencies), 128)
|
dependencies := make([]deb.Dependency, len(initialDependencies), 128)
|
||||||
for i := range dependencies {
|
for i := range dependencies {
|
||||||
dependencies[i] = initialDependencies[i]
|
dependencies[i] = initialDependencies[i]
|
||||||
dependencies[i].Architecture = arch
|
dependencies[i].Architecture = arch
|
||||||
@@ -102,34 +99,35 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
|
|||||||
// Search for package that can satisfy dependencies
|
// Search for package that can satisfy dependencies
|
||||||
pkg := sourcePackageList.Search(dep)
|
pkg := sourcePackageList.Search(dep)
|
||||||
if pkg == nil {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !noRemove {
|
if !noRemove {
|
||||||
// Remove all packages with the same name and architecture
|
// 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)
|
packageList.Remove(p)
|
||||||
context.progress.ColoredPrintf("@r[-]@| %s removed", p)
|
context.Progress().ColoredPrintf("@r[-]@| %s removed", p)
|
||||||
p = packageList.Search(debian.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name})
|
p = packageList.Search(deb.Dependency{Architecture: pkg.Architecture, Pkg: pkg.Name})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new discovered package
|
// Add new discovered package
|
||||||
packageList.Add(pkg)
|
packageList.Add(pkg)
|
||||||
context.progress.ColoredPrintf("@g[+]@| %s added", pkg)
|
context.Progress().ColoredPrintf("@g[+]@| %s added", pkg)
|
||||||
|
|
||||||
if noDeps {
|
if noDeps {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find missing dependencies for single added package
|
// Find missing dependencies for single added package
|
||||||
pL := debian.NewPackageList()
|
pL := deb.NewPackageList()
|
||||||
pL.Add(pkg)
|
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 {
|
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
|
// 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) {
|
if context.flags.Lookup("dry-run").Value.Get().(bool) {
|
||||||
context.progress.Printf("\nNot creating snapshot, as dry run was requested.\n")
|
context.Progress().Printf("\nNot creating snapshot, as dry run was requested.\n")
|
||||||
} else {
|
} else {
|
||||||
// Create <destination> snapshot
|
// 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:], " ")))
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
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
|
return err
|
||||||
}
|
}
|
||||||
@@ -172,10 +170,10 @@ func makeCmdSnapshotPull() *commander.Command {
|
|||||||
UsageLine: "pull <name> <source> <destination> <package-name> ...",
|
UsageLine: "pull <name> <source> <destination> <package-name> ...",
|
||||||
Short: "pull packages from another snapshot",
|
Short: "pull packages from another snapshot",
|
||||||
Long: `
|
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
|
from snapshot <source>. Pull can upgrade package version in <name> with
|
||||||
versions from <source> following dependencies. New snapshot <destination>
|
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)'.
|
as 'package-name' or as dependency 'package-name (>= version)'.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/commander"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/flag"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlySnapshotShow(cmd *commander.Command, args []string) error {
|
func aptlySnapshotShow(cmd *commander.Command, args []string) error {
|
||||||
@@ -16,13 +15,12 @@ func aptlySnapshotShow(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
snapshot, err := context.CollectionFactory().SnapshotCollection().ByName(name)
|
||||||
snapshot, err := snapshotCollection.ByName(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to show: %s", err)
|
return fmt.Errorf("unable to show: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snapshotCollection.LoadComplete(snapshot)
|
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to show: %s", err)
|
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("Description: %s\n", snapshot.Description)
|
||||||
fmt.Printf("Number of packages: %d\n", snapshot.NumPackages())
|
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 {
|
if withPackages {
|
||||||
ListPackagesRefList(snapshot.RefList())
|
ListPackagesRefList(snapshot.RefList())
|
||||||
}
|
}
|
||||||
@@ -46,7 +44,7 @@ func makeCmdSnapshotShow() *commander.Command {
|
|||||||
UsageLine: "show <name>",
|
UsageLine: "show <name>",
|
||||||
Short: "shows details about snapshot",
|
Short: "shows details about snapshot",
|
||||||
Long: `
|
Long: `
|
||||||
Command show displays full information about snapshot.
|
Command show displays full information about a snapshot.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|||||||
+18
-22
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
"github.com/smira/aptly/deb"
|
||||||
"github.com/gonuts/flag"
|
"github.com/smira/commander"
|
||||||
"github.com/smira/aptly/debian"
|
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,37 +14,35 @@ func aptlySnapshotVerify(cmd *commander.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
snapshots := make([]*deb.Snapshot, len(args))
|
||||||
packageCollection := debian.NewPackageCollection(context.database)
|
|
||||||
|
|
||||||
snapshots := make([]*debian.Snapshot, len(args))
|
|
||||||
for i := range snapshots {
|
for i := range snapshots {
|
||||||
snapshots[i], err = snapshotCollection.ByName(args[i])
|
snapshots[i], err = context.CollectionFactory().SnapshotCollection().ByName(args[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to verify: %s", err)
|
return fmt.Errorf("unable to verify: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snapshotCollection.LoadComplete(snapshots[i])
|
err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshots[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to verify: %s", err)
|
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 {
|
if err != nil {
|
||||||
fmt.Errorf("unable to load packages: %s", err)
|
fmt.Errorf("unable to load packages: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sourcePackageList := debian.NewPackageList()
|
sourcePackageList := deb.NewPackageList()
|
||||||
err = sourcePackageList.Append(packageList)
|
err = sourcePackageList.Append(packageList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("unable to merge sources: %s", err)
|
fmt.Errorf("unable to merge sources: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pL *deb.PackageList
|
||||||
for i := 1; i < len(snapshots); i++ {
|
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 {
|
if err != nil {
|
||||||
fmt.Errorf("unable to load packages: %s", err)
|
fmt.Errorf("unable to load packages: %s", err)
|
||||||
}
|
}
|
||||||
@@ -60,8 +57,8 @@ func aptlySnapshotVerify(cmd *commander.Command, args []string) error {
|
|||||||
|
|
||||||
var architecturesList []string
|
var architecturesList []string
|
||||||
|
|
||||||
if len(context.architecturesList) > 0 {
|
if len(context.ArchitecturesList()) > 0 {
|
||||||
architecturesList = context.architecturesList
|
architecturesList = context.ArchitecturesList()
|
||||||
} else {
|
} else {
|
||||||
architecturesList = packageList.Architectures(true)
|
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")
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to verify dependencies: %s", err)
|
return fmt.Errorf("unable to verify dependencies: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(missing) == 0 {
|
if len(missing) == 0 {
|
||||||
context.progress.Printf("All dependencies are satisfied.\n")
|
context.Progress().Printf("All dependencies are satisfied.\n")
|
||||||
} else {
|
} else {
|
||||||
context.progress.Printf("Missing dependencies (%d):\n", len(missing))
|
context.Progress().Printf("Missing dependencies (%d):\n", len(missing))
|
||||||
deps := make([]string, len(missing))
|
deps := make([]string, len(missing))
|
||||||
i := 0
|
i := 0
|
||||||
for _, dep := range missing {
|
for _, dep := range missing {
|
||||||
@@ -91,7 +88,7 @@ func aptlySnapshotVerify(cmd *commander.Command, args []string) error {
|
|||||||
sort.Strings(deps)
|
sort.Strings(deps)
|
||||||
|
|
||||||
for _, dep := range 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> ...]",
|
UsageLine: "verify <name> [<source> ...]",
|
||||||
Short: "verify dependencies in snapshot",
|
Short: "verify dependencies in snapshot",
|
||||||
Long: `
|
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
|
snapshots <source> as dependency sources. All unsatisfied dependencies are
|
||||||
printed.
|
printed.
|
||||||
|
|
||||||
@@ -112,7 +109,6 @@ Example:
|
|||||||
|
|
||||||
$ aptly snapshot verify wheezy-main wheezy-contrib wheezy-non-free
|
$ aptly snapshot verify wheezy-main wheezy-contrib wheezy-non-free
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-snapshot-verify", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|||||||
+1
-3
@@ -2,9 +2,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
|
"github.com/smira/commander"
|
||||||
)
|
)
|
||||||
|
|
||||||
func aptlyVersion(cmd *commander.Command, args []string) error {
|
func aptlyVersion(cmd *commander.Command, args []string) error {
|
||||||
@@ -23,6 +22,5 @@ Shows aptly version.
|
|||||||
ex:
|
ex:
|
||||||
$ aptly version
|
$ aptly version
|
||||||
`,
|
`,
|
||||||
Flag: *flag.NewFlagSet("aptly-version", flag.ExitOnError),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"github.com/syndtr/goleveldb/leveldb/filter"
|
"github.com/syndtr/goleveldb/leveldb/filter"
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/storage"
|
||||||
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errors for Storage
|
// Errors for Storage
|
||||||
@@ -24,6 +26,7 @@ type Storage interface {
|
|||||||
Close() error
|
Close() error
|
||||||
StartBatch()
|
StartBatch()
|
||||||
FinishBatch() error
|
FinishBatch() error
|
||||||
|
CompactDB() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type levelDB struct {
|
type levelDB struct {
|
||||||
@@ -49,6 +52,25 @@ func OpenDB(path string) (Storage, error) {
|
|||||||
return &levelDB{db: db}, nil
|
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) {
|
func (l *levelDB) Get(key []byte) ([]byte, error) {
|
||||||
value, err := l.db.Get(key, nil)
|
value, err := l.db.Get(key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -61,6 +83,7 @@ func (l *levelDB) Get(key []byte) ([]byte, error) {
|
|||||||
return value, nil
|
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 {
|
func (l *levelDB) Put(key []byte, value []byte) error {
|
||||||
if l.batch != nil {
|
if l.batch != nil {
|
||||||
l.batch.Put(key, value)
|
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)
|
return l.db.Put(key, value, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete removes key from DB
|
||||||
func (l *levelDB) Delete(key []byte) error {
|
func (l *levelDB) Delete(key []byte) error {
|
||||||
if l.batch != nil {
|
if l.batch != nil {
|
||||||
l.batch.Delete(key)
|
l.batch.Delete(key)
|
||||||
@@ -87,6 +111,7 @@ func (l *levelDB) Delete(key []byte) error {
|
|||||||
return l.db.Delete(key, nil)
|
return l.db.Delete(key, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeysByPrefix returns all keys that start with prefix
|
||||||
func (l *levelDB) KeysByPrefix(prefix []byte) [][]byte {
|
func (l *levelDB) KeysByPrefix(prefix []byte) [][]byte {
|
||||||
result := make([][]byte, 0, 20)
|
result := make([][]byte, 0, 20)
|
||||||
|
|
||||||
@@ -103,6 +128,7 @@ func (l *levelDB) KeysByPrefix(prefix []byte) [][]byte {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchByPrefix returns all values with keys that start with prefix
|
||||||
func (l *levelDB) FetchByPrefix(prefix []byte) [][]byte {
|
func (l *levelDB) FetchByPrefix(prefix []byte) [][]byte {
|
||||||
result := make([][]byte, 0, 20)
|
result := make([][]byte, 0, 20)
|
||||||
|
|
||||||
@@ -119,10 +145,14 @@ func (l *levelDB) FetchByPrefix(prefix []byte) [][]byte {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close finishes DB work
|
||||||
func (l *levelDB) Close() error {
|
func (l *levelDB) Close() error {
|
||||||
return l.db.Close()
|
return l.db.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StartBatch starts batch processing of keys
|
||||||
|
//
|
||||||
|
// All subsequent Get, Put and Delete would work on batch
|
||||||
func (l *levelDB) StartBatch() {
|
func (l *levelDB) StartBatch() {
|
||||||
if l.batch != nil {
|
if l.batch != nil {
|
||||||
panic("batch already started")
|
panic("batch already started")
|
||||||
@@ -130,6 +160,7 @@ func (l *levelDB) StartBatch() {
|
|||||||
l.batch = new(leveldb.Batch)
|
l.batch = new(leveldb.Batch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FinishBatch finalizes the batch, saving operations
|
||||||
func (l *levelDB) FinishBatch() error {
|
func (l *levelDB) FinishBatch() error {
|
||||||
if l.batch == nil {
|
if l.batch == nil {
|
||||||
panic("no batch")
|
panic("no batch")
|
||||||
@@ -138,3 +169,8 @@ func (l *levelDB) FinishBatch() error {
|
|||||||
l.batch = nil
|
l.batch = nil
|
||||||
return err
|
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 {
|
type LevelDBSuite struct {
|
||||||
db Storage
|
path string
|
||||||
|
db Storage
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = Suite(&LevelDBSuite{})
|
var _ = Suite(&LevelDBSuite{})
|
||||||
@@ -19,7 +20,8 @@ var _ = Suite(&LevelDBSuite{})
|
|||||||
func (s *LevelDBSuite) SetUpTest(c *C) {
|
func (s *LevelDBSuite) SetUpTest(c *C) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
s.db, err = OpenDB(c.MkDir())
|
s.path = c.MkDir()
|
||||||
|
s.db, err = OpenDB(s.path)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +30,29 @@ func (s *LevelDBSuite) TearDownTest(c *C) {
|
|||||||
c.Assert(err, IsNil)
|
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) {
|
func (s *LevelDBSuite) TestGetPut(c *C) {
|
||||||
var (
|
var (
|
||||||
key = []byte("key")
|
key = []byte("key")
|
||||||
@@ -122,3 +147,11 @@ func (s *LevelDBSuite) TestBatch(c *C) {
|
|||||||
s.db.StartBatch()
|
s.db.StartBatch()
|
||||||
c.Check(func() { s.db.StartBatch() }, Panics, "batch already started")
|
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 (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/smira/aptly/utils"
|
"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 (
|
import (
|
||||||
. "launchpad.net/gocheck"
|
. "launchpad.net/gocheck"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -63,9 +63,9 @@ func NewPackageListFromRefList(reflist *PackageRefList, collection *PackageColle
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := reflist.ForEach(func(key []byte) error {
|
err := reflist.ForEach(func(key []byte) error {
|
||||||
p, err := collection.ByKey(key)
|
p, err2 := collection.ByKey(key)
|
||||||
if err != nil {
|
if err2 != nil {
|
||||||
return fmt.Errorf("unable to load package with key %s: %s", key, err)
|
return fmt.Errorf("unable to load package with key %s: %s", key, err2)
|
||||||
}
|
}
|
||||||
if progress != nil {
|
if progress != nil {
|
||||||
progress.AddBar(1)
|
progress.AddBar(1)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -17,6 +17,10 @@ type LocalRepo struct {
|
|||||||
Name string
|
Name string
|
||||||
// Comment
|
// Comment
|
||||||
Comment string
|
Comment string
|
||||||
|
// DefaultDistribution
|
||||||
|
DefaultDistribution string `codec:",omitempty"`
|
||||||
|
// DefaultComponent
|
||||||
|
DefaultComponent string `codec:",omitempty"`
|
||||||
// "Snapshot" of current list of packages
|
// "Snapshot" of current list of packages
|
||||||
packageRefs *PackageRefList
|
packageRefs *PackageRefList
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -388,16 +388,18 @@ func (p *Package) LinkFromPool(publishedStorage aptly.PublishedStorage, packageP
|
|||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := filepath.Dir(relPath)
|
|
||||||
if p.IsSource {
|
if p.IsSource {
|
||||||
p.Extra()["Directory"] = dir
|
p.Extra()["Directory"] = relPath
|
||||||
} else {
|
} else {
|
||||||
p.Files()[i].downloadPath = dir
|
p.Files()[i].downloadPath = relPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,6 +411,8 @@ func (p *Package) PoolDirectory() (string, error) {
|
|||||||
source := p.Source
|
source := p.Source
|
||||||
if source == "" {
|
if source == "" {
|
||||||
source = p.Name
|
source = p.Name
|
||||||
|
} else if pos := strings.Index(source, "("); pos != -1 {
|
||||||
|
source = strings.TrimSpace(source[:pos])
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(source) < 2 {
|
if len(source) < 2 {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/smira/aptly/database"
|
"github.com/smira/aptly/database"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/smira/aptly/files"
|
"github.com/smira/aptly/files"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -230,6 +230,12 @@ func (s *PackageSuite) TestPoolDirectory(c *C) {
|
|||||||
c.Check(err, IsNil)
|
c.Check(err, IsNil)
|
||||||
c.Check(dir, Equals, "liba/libarena")
|
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 = NewPackageFromControlFile(packageStanza.Copy())
|
||||||
p.Source = "l"
|
p.Source = "l"
|
||||||
_, err = p.PoolDirectory()
|
_, err = p.PoolDirectory()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -11,14 +11,14 @@ import (
|
|||||||
var ppaRegexp = regexp.MustCompile("^ppa:([^/]+)/(.+)$")
|
var ppaRegexp = regexp.MustCompile("^ppa:([^/]+)/(.+)$")
|
||||||
|
|
||||||
// ParsePPA converts ppa URL like ppa:user/ppa-name to full HTTP url
|
// 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)
|
matches := ppaRegexp.FindStringSubmatch(ppaURL)
|
||||||
if matches == nil {
|
if matches == nil {
|
||||||
err = fmt.Errorf("unable to parse ppa URL: %v", ppaURL)
|
err = fmt.Errorf("unable to parse ppa URL: %v", ppaURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
distributorID := utils.Config.PpaDistributorID
|
distributorID := config.PpaDistributorID
|
||||||
if distributorID == "" {
|
if distributorID == "" {
|
||||||
distributorID, err = getDistributorID()
|
distributorID, err = getDistributorID()
|
||||||
if err != nil {
|
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 == "" {
|
if codename == "" {
|
||||||
codename, err = getCodename()
|
codename, err = getCodename()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
@@ -6,27 +6,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PpaSuite struct {
|
type PpaSuite struct {
|
||||||
savedConfig utils.ConfigStructure
|
config utils.ConfigStructure
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = Suite(&PpaSuite{})
|
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) {
|
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.*")
|
c.Check(err, ErrorMatches, "unable to parse ppa URL.*")
|
||||||
|
|
||||||
utils.Config.PpaDistributorID = "debian"
|
s.config.PpaDistributorID = "debian"
|
||||||
utils.Config.PpaCodename = "wheezy"
|
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(err, IsNil)
|
||||||
c.Check(url, Equals, "http://ppa.launchpad.net/user/project/debian")
|
c.Check(url, Equals, "http://ppa.launchpad.net/user/project/debian")
|
||||||
c.Check(distribution, Equals, "wheezy")
|
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 (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -45,12 +45,14 @@ func (n *NullSigner) ClearSign(source string, destination string) error {
|
|||||||
|
|
||||||
type PublishedRepoSuite struct {
|
type PublishedRepoSuite struct {
|
||||||
PackageListMixinSuite
|
PackageListMixinSuite
|
||||||
repo *PublishedRepo
|
repo, repo2 *PublishedRepo
|
||||||
root string
|
root string
|
||||||
publishedStorage aptly.PublishedStorage
|
publishedStorage aptly.PublishedStorage
|
||||||
packagePool aptly.PackagePool
|
packagePool aptly.PackagePool
|
||||||
|
localRepo *LocalRepo
|
||||||
snapshot *Snapshot
|
snapshot *Snapshot
|
||||||
db database.Storage
|
db database.Storage
|
||||||
|
factory *CollectionFactory
|
||||||
packageCollection *PackageCollection
|
packageCollection *PackageCollection
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +62,7 @@ func (s *PublishedRepoSuite) SetUpTest(c *C) {
|
|||||||
s.SetUpPackages()
|
s.SetUpPackages()
|
||||||
|
|
||||||
s.db, _ = database.OpenDB(c.MkDir())
|
s.db, _ = database.OpenDB(c.MkDir())
|
||||||
|
s.factory = NewCollectionFactory(s.db)
|
||||||
|
|
||||||
s.root = c.MkDir()
|
s.root = c.MkDir()
|
||||||
s.publishedStorage = files.NewPublishedStorage(s.root)
|
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, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{}, false)
|
||||||
repo.packageRefs = s.reflist
|
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.snapshot, _ = NewSnapshotFromRepository("snap", repo)
|
||||||
|
s.factory.SnapshotCollection().Add(s.snapshot)
|
||||||
|
|
||||||
s.repo, _ = NewPublishedRepo("ppa", "squeeze", "main", nil, s.snapshot)
|
s.packageCollection = s.factory.PackageCollection()
|
||||||
|
|
||||||
s.packageCollection = NewPackageCollection(s.db)
|
|
||||||
s.packageCollection.Update(s.p1)
|
s.packageCollection.Update(s.p1)
|
||||||
s.packageCollection.Update(s.p2)
|
s.packageCollection.Update(s.p2)
|
||||||
s.packageCollection.Update(s.p3)
|
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)
|
poolPath, _ := s.packagePool.Path(s.p1.Files()[0].Filename, s.p1.Files()[0].Checksums.MD5)
|
||||||
err := os.MkdirAll(filepath.Dir(poolPath), 0755)
|
err := os.MkdirAll(filepath.Dir(poolPath), 0755)
|
||||||
f, err := os.Create(poolPath)
|
f, err := os.Create(poolPath)
|
||||||
@@ -88,6 +99,20 @@ func (s *PublishedRepoSuite) TearDownTest(c *C) {
|
|||||||
s.db.Close()
|
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) {
|
func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) {
|
||||||
|
|
||||||
for _, t := range []struct {
|
for _, t := range []struct {
|
||||||
@@ -144,7 +169,7 @@ func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) {
|
|||||||
errorExpected: "invalid prefix .*",
|
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 != "" {
|
if t.errorExpected != "" {
|
||||||
c.Check(err, ErrorMatches, t.errorExpected)
|
c.Check(err, ErrorMatches, t.errorExpected)
|
||||||
} else {
|
} 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) {
|
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.Assert(err, IsNil)
|
||||||
|
|
||||||
c.Check(s.repo.Architectures, DeepEquals, []string{"i386"})
|
c.Check(s.repo.Architectures, DeepEquals, []string{"i386"})
|
||||||
@@ -191,27 +250,46 @@ func (s *PublishedRepoSuite) TestPublish(c *C) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *PublishedRepoSuite) TestPublishNoSigner(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.Assert(err, IsNil)
|
||||||
|
|
||||||
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/squeeze/Release"), PathExists)
|
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) {
|
func (s *PublishedRepoSuite) TestString(c *C) {
|
||||||
c.Check(s.repo.String(), Equals,
|
c.Check(s.repo.String(), Equals,
|
||||||
"ppa/squeeze (main) publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
"ppa/squeeze (main) [] publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
||||||
repo, _ := NewPublishedRepo("", "squeeze", "main", nil, s.snapshot)
|
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,
|
c.Check(repo.String(), Equals,
|
||||||
"./squeeze (main) publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
"./squeeze (main) [s390] publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
||||||
repo, _ = NewPublishedRepo("", "squeeze", "main", []string{"i386", "amd64"}, s.snapshot)
|
repo, _ = NewPublishedRepo("", "squeeze", "main", []string{"i386", "amd64"}, s.snapshot, s.factory)
|
||||||
c.Check(repo.String(), Equals,
|
c.Check(repo.String(), Equals,
|
||||||
"./squeeze (main) [i386, amd64] publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
"./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) {
|
func (s *PublishedRepoSuite) TestKey(c *C) {
|
||||||
c.Check(s.repo.Key(), DeepEquals, []byte("Uppa>>squeeze"))
|
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) {
|
func (s *PublishedRepoSuite) TestEncodeDecode(c *C) {
|
||||||
encoded := s.repo.Encode()
|
encoded := s.repo.Encode()
|
||||||
repo := &PublishedRepo{}
|
repo := &PublishedRepo{}
|
||||||
@@ -220,23 +298,35 @@ func (s *PublishedRepoSuite) TestEncodeDecode(c *C) {
|
|||||||
s.repo.snapshot = nil
|
s.repo.snapshot = nil
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
c.Assert(repo, DeepEquals, s.repo)
|
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 {
|
type PublishedRepoCollectionSuite struct {
|
||||||
PackageListMixinSuite
|
PackageListMixinSuite
|
||||||
db database.Storage
|
db database.Storage
|
||||||
snapshotCollection *SnapshotCollection
|
factory *CollectionFactory
|
||||||
collection *PublishedRepoCollection
|
snapshotCollection *SnapshotCollection
|
||||||
snap1, snap2 *Snapshot
|
collection *PublishedRepoCollection
|
||||||
repo1, repo2, repo3 *PublishedRepo
|
snap1, snap2 *Snapshot
|
||||||
|
localRepo *LocalRepo
|
||||||
|
repo1, repo2, repo3, repo4 *PublishedRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = Suite(&PublishedRepoCollectionSuite{})
|
var _ = Suite(&PublishedRepoCollectionSuite{})
|
||||||
|
|
||||||
func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) {
|
func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) {
|
||||||
s.db, _ = database.OpenDB(c.MkDir())
|
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.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1")
|
||||||
s.snap2 = NewSnapshotFromPackageList("snap2", []*Snapshot{}, NewPackageList(), "desc2")
|
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.snap1)
|
||||||
s.snapshotCollection.Add(s.snap2)
|
s.snapshotCollection.Add(s.snap2)
|
||||||
|
|
||||||
s.repo1, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap1)
|
s.localRepo = NewLocalRepo("local1", "comment1")
|
||||||
s.repo2, _ = NewPublishedRepo("", "anaconda", "main", []string{}, s.snap2)
|
s.factory.LocalRepoCollection().Add(s.localRepo)
|
||||||
s.repo3, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap2)
|
|
||||||
|
|
||||||
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) {
|
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.repo2), IsNil)
|
||||||
c.Assert(s.collection.Add(s.repo3), ErrorMatches, ".*already exists")
|
c.Assert(s.collection.Add(s.repo3), ErrorMatches, ".*already exists")
|
||||||
c.Assert(s.collection.CheckDuplicate(s.repo3), Equals, s.repo1)
|
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")
|
r, err = s.collection.ByPrefixDistribution("ppa", "anaconda")
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
err = s.collection.LoadComplete(r, s.snapshotCollection)
|
err = s.collection.LoadComplete(r, s.factory)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
c.Assert(r.String(), Equals, s.repo1.String())
|
c.Assert(r.String(), Equals, s.repo1.String())
|
||||||
|
|
||||||
@@ -277,7 +372,7 @@ func (s *PublishedRepoCollectionSuite) TestAddByPrefixDistribution(c *C) {
|
|||||||
r, err = collection.ByPrefixDistribution("ppa", "anaconda")
|
r, err = collection.ByPrefixDistribution("ppa", "anaconda")
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
err = s.collection.LoadComplete(r, s.snapshotCollection)
|
err = s.collection.LoadComplete(r, s.factory)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
c.Assert(r.String(), Equals, s.repo1.String())
|
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)
|
r, err = s.collection.ByUUID(s.repo1.UUID)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
err = s.collection.LoadComplete(r, s.snapshotCollection)
|
err = s.collection.LoadComplete(r, s.factory)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
c.Assert(r.String(), Equals, s.repo1.String())
|
c.Assert(r.String(), Equals, s.repo1.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PublishedRepoCollectionSuite) TestUpdateLoadComplete(c *C) {
|
func (s *PublishedRepoCollectionSuite) TestUpdateLoadComplete(c *C) {
|
||||||
c.Assert(s.collection.Update(s.repo1), IsNil)
|
c.Assert(s.collection.Update(s.repo1), IsNil)
|
||||||
|
c.Assert(s.collection.Update(s.repo4), IsNil)
|
||||||
|
|
||||||
collection := NewPublishedRepoCollection(s.db)
|
collection := NewPublishedRepoCollection(s.db)
|
||||||
r, err := collection.ByPrefixDistribution("ppa", "anaconda")
|
r, err := collection.ByPrefixDistribution("ppa", "anaconda")
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
c.Assert(r.snapshot, 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.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) {
|
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})
|
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 {
|
type PublishedRepoRemoveSuite struct {
|
||||||
PackageListMixinSuite
|
PackageListMixinSuite
|
||||||
db database.Storage
|
db database.Storage
|
||||||
|
factory *CollectionFactory
|
||||||
snapshotCollection *SnapshotCollection
|
snapshotCollection *SnapshotCollection
|
||||||
collection *PublishedRepoCollection
|
collection *PublishedRepoCollection
|
||||||
root string
|
root string
|
||||||
@@ -351,19 +464,20 @@ var _ = Suite(&PublishedRepoRemoveSuite{})
|
|||||||
|
|
||||||
func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) {
|
func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) {
|
||||||
s.db, _ = database.OpenDB(c.MkDir())
|
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.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1")
|
||||||
|
|
||||||
s.snapshotCollection.Add(s.snap1)
|
s.snapshotCollection.Add(s.snap1)
|
||||||
|
|
||||||
s.repo1, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap1)
|
s.repo1, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap1, s.factory)
|
||||||
s.repo2, _ = NewPublishedRepo("", "anaconda", "main", []string{}, s.snap1)
|
s.repo2, _ = NewPublishedRepo("", "anaconda", "main", []string{}, s.snap1, s.factory)
|
||||||
s.repo3, _ = NewPublishedRepo("ppa", "meduza", "main", []string{}, s.snap1)
|
s.repo3, _ = NewPublishedRepo("ppa", "meduza", "main", []string{}, s.snap1, s.factory)
|
||||||
s.repo4, _ = NewPublishedRepo("ppa", "osminog", "contrib", []string{}, s.snap1)
|
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.repo1)
|
||||||
s.collection.Add(s.repo2)
|
s.collection.Add(s.repo2)
|
||||||
s.collection.Add(s.repo3)
|
s.collection.Add(s.repo3)
|
||||||
@@ -385,7 +499,7 @@ func (s *PublishedRepoRemoveSuite) TearDownTest(c *C) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *PublishedRepoRemoveSuite) TestRemoveFilesOnlyDist(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/anaconda"), Not(PathExists))
|
||||||
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), 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) {
|
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/anaconda"), Not(PathExists))
|
||||||
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), 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) {
|
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/anaconda"), Not(PathExists))
|
||||||
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), 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) {
|
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/anaconda"), PathExists)
|
||||||
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), 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) {
|
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)
|
c.Check(err, IsNil)
|
||||||
|
|
||||||
_, err = s.collection.ByPrefixDistribution("ppa", "anaconda")
|
_, 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(), "dists/anaconda"), PathExists)
|
||||||
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), 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")
|
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(err, IsNil)
|
||||||
|
|
||||||
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
|
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) {
|
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)
|
c.Check(err, IsNil)
|
||||||
|
|
||||||
_, err = s.collection.ByPrefixDistribution(".", "anaconda")
|
_, err = s.collection.ByPrefixDistribution(".", "anaconda")
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -219,9 +219,12 @@ func (l *PackageRefList) Diff(r *PackageRefList, packageCollection *PackageColle
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge merges reflist r into current reflist. If overrideMatching, merge replaces matching packages (by architecture/name)
|
// Merge merges reflist r into current reflist. If overrideMatching, merge
|
||||||
// with reference from r, otherwise all packages are saved.
|
// 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) {
|
func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching bool) (result *PackageRefList) {
|
||||||
|
var overriddenArch, overridenName []byte
|
||||||
|
|
||||||
// pointer to left and right reflists
|
// pointer to left and right reflists
|
||||||
il, ir := 0, 0
|
il, ir := 0, 0
|
||||||
// length of reflists
|
// length of reflists
|
||||||
@@ -253,6 +256,8 @@ func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching bool) (result
|
|||||||
result.Refs = append(result.Refs, l.Refs[il])
|
result.Refs = append(result.Refs, l.Refs[il])
|
||||||
il++
|
il++
|
||||||
ir++
|
ir++
|
||||||
|
overridenName = nil
|
||||||
|
overriddenArch = nil
|
||||||
} else {
|
} else {
|
||||||
if overrideMatching {
|
if overrideMatching {
|
||||||
partsL := bytes.Split(rl, []byte(" "))
|
partsL := bytes.Split(rl, []byte(" "))
|
||||||
@@ -261,11 +266,19 @@ func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching bool) (result
|
|||||||
partsR := bytes.Split(rr, []byte(" "))
|
partsR := bytes.Split(rr, []byte(" "))
|
||||||
archR, nameR := partsR[0][1:], partsR[1]
|
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
|
// override with package from the right
|
||||||
result.Refs = append(result.Refs, r.Refs[ir])
|
result.Refs = append(result.Refs, r.Refs[ir])
|
||||||
il++
|
il++
|
||||||
ir++
|
ir++
|
||||||
|
overriddenArch = archL
|
||||||
|
overridenName = nameL
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,10 +290,50 @@ func (l *PackageRefList) Merge(r *PackageRefList, overrideMatching bool) (result
|
|||||||
} else {
|
} else {
|
||||||
result.Refs = append(result.Refs, r.Refs[ir])
|
result.Refs = append(result.Refs, r.Refs[ir])
|
||||||
ir++
|
ir++
|
||||||
|
overridenName = nil
|
||||||
|
overriddenArch = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
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 (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -14,6 +14,14 @@ type PackageRefListSuite struct {
|
|||||||
|
|
||||||
var _ = Suite(&PackageRefListSuite{})
|
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) {
|
func (s *PackageRefListSuite) SetUpTest(c *C) {
|
||||||
s.list = NewPackageList()
|
s.list = NewPackageList()
|
||||||
|
|
||||||
@@ -250,14 +258,6 @@ func (s *PackageRefListSuite) TestMerge(c *C) {
|
|||||||
reflistA := NewPackageRefListFromPackageList(listA)
|
reflistA := NewPackageRefListFromPackageList(listA)
|
||||||
reflistB := NewPackageRefListFromPackageList(listB)
|
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)
|
mergeAB := reflistA.Merge(reflistB, true)
|
||||||
mergeBA := reflistB.Merge(reflistA, true)
|
mergeBA := reflistB.Merge(reflistA, true)
|
||||||
|
|
||||||
@@ -273,3 +273,32 @@ func (s *PackageRefListSuite) TestMerge(c *C) {
|
|||||||
c.Check(toStrSlice(mergeBAall), DeepEquals,
|
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"})
|
[]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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -66,9 +67,11 @@ func NewRemoteRepo(name string, archiveRoot string, distribution string, compone
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.Distribution == "." || result.Distribution == "./" {
|
if strings.HasSuffix(result.Distribution, "/") || strings.HasPrefix(result.Distribution, ".") {
|
||||||
// flat repo
|
// flat repo
|
||||||
result.Distribution = ""
|
if !strings.HasPrefix(result.Distribution, ".") {
|
||||||
|
result.Distribution = "./" + result.Distribution
|
||||||
|
}
|
||||||
result.Architectures = nil
|
result.Architectures = nil
|
||||||
if len(result.Components) > 0 {
|
if len(result.Components) > 0 {
|
||||||
return nil, fmt.Errorf("components aren't supported for flat repos")
|
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
|
// IsFlat determines if repository is flat
|
||||||
func (repo *RemoteRepo) IsFlat() bool {
|
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
|
// NumPackages return number of packages retrived from remote repo
|
||||||
@@ -129,7 +134,7 @@ func (repo *RemoteRepo) ReleaseURL(name string) *url.URL {
|
|||||||
if !repo.IsFlat() {
|
if !repo.IsFlat() {
|
||||||
path = &url.URL{Path: fmt.Sprintf("dists/%s/%s", repo.Distribution, name)}
|
path = &url.URL{Path: fmt.Sprintf("dists/%s/%s", repo.Distribution, name)}
|
||||||
} else {
|
} else {
|
||||||
path = &url.URL{Path: name}
|
path = &url.URL{Path: filepath.Join(repo.Distribution, name)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return repo.archiveRootURL.ResolveReference(path)
|
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
|
// FlatBinaryURL returns URL to Packages files for flat repo
|
||||||
func (repo *RemoteRepo) FlatBinaryURL() *url.URL {
|
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)
|
return repo.archiveRootURL.ResolveReference(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlatSourcesURL returns URL to Sources files for flat repo
|
// FlatSourcesURL returns URL to Sources files for flat repo
|
||||||
func (repo *RemoteRepo) FlatSourcesURL() *url.URL {
|
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)
|
return repo.archiveRootURL.ResolveReference(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,8 +175,8 @@ func (repo *RemoteRepo) PackageURL(filename string) *url.URL {
|
|||||||
// Fetch updates information about repository
|
// Fetch updates information about repository
|
||||||
func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier utils.Verifier) error {
|
func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier utils.Verifier) error {
|
||||||
var (
|
var (
|
||||||
release *os.File
|
release, inrelease, releasesig *os.File
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
if verifier == nil {
|
if verifier == nil {
|
||||||
@@ -182,7 +187,7 @@ func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier utils.Verifier) error
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 1. try InRelease file
|
// 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 {
|
if err != nil {
|
||||||
goto splitsignature
|
goto splitsignature
|
||||||
}
|
}
|
||||||
@@ -209,7 +214,7 @@ func (repo *RemoteRepo) Fetch(d aptly.Downloader, verifier utils.Verifier) error
|
|||||||
return err
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -275,7 +280,8 @@ ok:
|
|||||||
return fmt.Errorf("unparseable hash sum line: %#v", line)
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to parse size: %s", err)
|
return fmt.Errorf("unable to parse size: %s", err)
|
||||||
}
|
}
|
||||||
@@ -314,7 +320,7 @@ ok:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Download downloads all repo files
|
// 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()
|
list := NewPackageList()
|
||||||
|
|
||||||
progress.Printf("Downloading & parsing package files...\n")
|
progress.Printf("Downloading & parsing package files...\n")
|
||||||
@@ -378,7 +384,7 @@ func (repo *RemoteRepo) Download(progress aptly.Progress, d aptly.Downloader, pa
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = packageCollection.Update(p)
|
err = collectionFactory.PackageCollection().Update(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -395,9 +401,9 @@ func (repo *RemoteRepo) Download(progress aptly.Progress, d aptly.Downloader, pa
|
|||||||
downloadSize := int64(0)
|
downloadSize := int64(0)
|
||||||
|
|
||||||
err := list.ForEach(func(p *Package) error {
|
err := list.ForEach(func(p *Package) error {
|
||||||
list, err := p.DownloadList(packagePool)
|
list, err2 := p.DownloadList(packagePool)
|
||||||
if err != nil {
|
if err2 != nil {
|
||||||
return err
|
return err2
|
||||||
}
|
}
|
||||||
p.files = nil
|
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
|
// free up package list, we don't need it after this point
|
||||||
list = nil
|
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)
|
progress.InitBar(downloadSize, true)
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -72,7 +72,7 @@ type RemoteRepoSuite struct {
|
|||||||
downloader *http.FakeDownloader
|
downloader *http.FakeDownloader
|
||||||
progress aptly.Progress
|
progress aptly.Progress
|
||||||
db database.Storage
|
db database.Storage
|
||||||
packageCollection *PackageCollection
|
collectionFactory *CollectionFactory
|
||||||
packagePool aptly.PackagePool
|
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.downloader = http.NewFakeDownloader().ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile)
|
||||||
s.progress = console.NewProgress()
|
s.progress = console.NewProgress()
|
||||||
s.db, _ = database.OpenDB(c.MkDir())
|
s.db, _ = database.OpenDB(c.MkDir())
|
||||||
s.packageCollection = NewPackageCollection(s.db)
|
s.collectionFactory = NewCollectionFactory(s.db)
|
||||||
s.packagePool = files.NewPackagePool(c.MkDir())
|
s.packagePool = files.NewPackagePool(c.MkDir())
|
||||||
s.SetUpPackages()
|
s.SetUpPackages()
|
||||||
s.progress.Start()
|
s.progress.Start()
|
||||||
@@ -101,10 +101,15 @@ func (s *RemoteRepoSuite) TestInvalidURL(c *C) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *RemoteRepoSuite) TestFlatCreation(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.Architectures, IsNil)
|
||||||
c.Check(s.flat.Components, 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)
|
_, err := NewRemoteRepo("fl", "http://some.repo/", "./", []string{"main"}, []string{}, false)
|
||||||
c.Check(err, ErrorMatches, "components aren't supported for flat repos")
|
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/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")
|
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(err, IsNil)
|
||||||
c.Assert(s.downloader.Empty(), Equals, true)
|
c.Assert(s.downloader.Empty(), Equals, true)
|
||||||
c.Assert(s.repo.packageRefs, NotNil)
|
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)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
result, err := pkg.VerifyFiles(s.packagePool)
|
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.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")
|
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(err, IsNil)
|
||||||
c.Assert(s.downloader.Empty(), Equals, true)
|
c.Assert(s.downloader.Empty(), Equals, true)
|
||||||
c.Assert(s.repo.packageRefs, NotNil)
|
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)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
result, err := pkg.VerifyFiles(s.packagePool)
|
result, err := pkg.VerifyFiles(s.packagePool)
|
||||||
@@ -293,7 +298,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSources(c *C) {
|
|||||||
|
|
||||||
c.Check(pkg.Name, Equals, "amanda-client")
|
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)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
result, err = pkg.VerifyFiles(s.packagePool)
|
result, err = pkg.VerifyFiles(s.packagePool)
|
||||||
@@ -314,12 +319,12 @@ func (s *RemoteRepoSuite) TestDownloadFlat(c *C) {
|
|||||||
err := s.flat.Fetch(downloader, nil)
|
err := s.flat.Fetch(downloader, nil)
|
||||||
c.Assert(err, IsNil)
|
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(err, IsNil)
|
||||||
c.Assert(downloader.Empty(), Equals, true)
|
c.Assert(downloader.Empty(), Equals, true)
|
||||||
c.Assert(s.flat.packageRefs, NotNil)
|
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)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
result, err := pkg.VerifyFiles(s.packagePool)
|
result, err := pkg.VerifyFiles(s.packagePool)
|
||||||
@@ -348,12 +353,12 @@ func (s *RemoteRepoSuite) TestDownloadWithSourcesFlat(c *C) {
|
|||||||
err := s.flat.Fetch(downloader, nil)
|
err := s.flat.Fetch(downloader, nil)
|
||||||
c.Assert(err, IsNil)
|
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(err, IsNil)
|
||||||
c.Assert(downloader.Empty(), Equals, true)
|
c.Assert(downloader.Empty(), Equals, true)
|
||||||
c.Assert(s.flat.packageRefs, NotNil)
|
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)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
result, err := pkg.VerifyFiles(s.packagePool)
|
result, err := pkg.VerifyFiles(s.packagePool)
|
||||||
@@ -362,7 +367,7 @@ func (s *RemoteRepoSuite) TestDownloadWithSourcesFlat(c *C) {
|
|||||||
|
|
||||||
c.Check(pkg.Name, Equals, "amanda-client")
|
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)
|
c.Assert(err, IsNil)
|
||||||
|
|
||||||
result, err = pkg.VerifyFiles(s.packagePool)
|
result, err = pkg.VerifyFiles(s.packagePool)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package debian
|
package deb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "launchpad.net/gocheck"
|
. "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
|
package files
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/smira/aptly/aptly"
|
"github.com/smira/aptly/aptly"
|
||||||
"github.com/smira/aptly/utils"
|
"github.com/smira/aptly/utils"
|
||||||
"os"
|
"os"
|
||||||
@@ -38,46 +37,72 @@ func (storage *PublishedStorage) CreateFile(path string) (*os.File, error) {
|
|||||||
return os.Create(filepath.Join(storage.rootPath, path))
|
return os.Create(filepath.Join(storage.rootPath, path))
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveDirs removes directory structure under public path
|
// Remove removes single file under public path
|
||||||
func (storage *PublishedStorage) RemoveDirs(path string) error {
|
func (storage *PublishedStorage) Remove(path string) error {
|
||||||
filepath := filepath.Join(storage.rootPath, path)
|
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)
|
return os.RemoveAll(filepath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinkFromPool links package file from pool to dist's pool location
|
// LinkFromPool links package file from pool to dist's pool location
|
||||||
//
|
//
|
||||||
// prefix is publishing prefix for this repo (e.g. empty or "ppa/")
|
// publishedDirectory is desired location in pool (like prefix/pool/component/liba/libav/)
|
||||||
// component is component name when publishing (e.g. main)
|
|
||||||
// poolDirectory is desired location in pool (like liba/libav/)
|
|
||||||
// sourcePool is instance of aptly.PackagePool
|
// sourcePool is instance of aptly.PackagePool
|
||||||
// sourcePath is filepath to package file in package pool
|
// sourcePath is filepath to package file in package pool
|
||||||
//
|
//
|
||||||
// LinkFromPool returns relative path for the published file to be included in package index
|
// 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
|
// verify that package pool is local pool is filesystem pool
|
||||||
_ = sourcePool.(*PackagePool)
|
_ = sourcePool.(*PackagePool)
|
||||||
|
|
||||||
baseName := filepath.Base(sourcePath)
|
baseName := filepath.Base(sourcePath)
|
||||||
|
poolPath := filepath.Join(storage.rootPath, publishedDirectory)
|
||||||
relPath := filepath.Join("pool", component, poolDirectory, baseName)
|
|
||||||
poolPath := filepath.Join(storage.rootPath, prefix, "pool", component, poolDirectory)
|
|
||||||
|
|
||||||
err := os.MkdirAll(poolPath, 0755)
|
err := os.MkdirAll(poolPath, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = os.Stat(filepath.Join(poolPath, baseName))
|
_, err = os.Stat(filepath.Join(poolPath, baseName))
|
||||||
if err == nil { // already exists, skip
|
if err == nil { // already exists, skip
|
||||||
return relPath, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.Link(sourcePath, filepath.Join(poolPath, baseName))
|
return os.Link(sourcePath, filepath.Join(poolPath, baseName))
|
||||||
return relPath, err
|
}
|
||||||
|
|
||||||
|
// 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
|
// ChecksumsForFile proxies requests to utils.ChecksumsForFile, joining public path
|
||||||
func (storage *PublishedStorage) ChecksumsForFile(path string) (utils.ChecksumInfo, error) {
|
func (storage *PublishedStorage) ChecksumsForFile(path string) (utils.ChecksumInfo, error) {
|
||||||
return utils.ChecksumsForFile(filepath.Join(storage.rootPath, path))
|
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)
|
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) {
|
func (s *PublishedStorageSuite) TestRemoveDirs(c *C) {
|
||||||
err := s.storage.MkDir("ppa/dists/squeeze/")
|
err := s.storage.MkDir("ppa/dists/squeeze/")
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
@@ -52,7 +84,22 @@ func (s *PublishedStorageSuite) TestRemoveDirs(c *C) {
|
|||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
defer file.Close()
|
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"))
|
_, err = os.Stat(filepath.Join(s.storage.rootPath, "ppa/dists/squeeze/Release"))
|
||||||
c.Assert(err, NotNil)
|
c.Assert(err, NotNil)
|
||||||
@@ -108,9 +155,8 @@ func (s *PublishedStorageSuite) TestLinkFromPool(c *C) {
|
|||||||
err = ioutil.WriteFile(t.sourcePath, []byte("Contents"), 0644)
|
err = ioutil.WriteFile(t.sourcePath, []byte("Contents"), 0644)
|
||||||
c.Assert(err, IsNil)
|
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(err, IsNil)
|
||||||
c.Assert(path, Equals, t.expectedFilename)
|
|
||||||
|
|
||||||
st, err := os.Stat(filepath.Join(s.storage.rootPath, t.prefix, t.expectedFilename))
|
st, err := os.Stat(filepath.Join(s.storage.rootPath, t.prefix, t.expectedFilename))
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
|||||||
+8
-1
@@ -28,6 +28,7 @@ type downloaderImpl struct {
|
|||||||
unpause chan bool
|
unpause chan bool
|
||||||
progress aptly.Progress
|
progress aptly.Progress
|
||||||
threads int
|
threads int
|
||||||
|
client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadTask represents single item in queue
|
// downloadTask represents single item in queue
|
||||||
@@ -50,6 +51,12 @@ func NewDownloader(threads int, progress aptly.Progress) aptly.Downloader {
|
|||||||
unpause: make(chan bool),
|
unpause: make(chan bool),
|
||||||
threads: threads,
|
threads: threads,
|
||||||
progress: progress,
|
progress: progress,
|
||||||
|
client: &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
DisableCompression: true,
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < downloader.threads; i++ {
|
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) {
|
func (downloader *downloaderImpl) handleTask(task *downloadTask) {
|
||||||
downloader.progress.Printf("Downloading %s...\n", task.url)
|
downloader.progress.Printf("Downloading %s...\n", task.url)
|
||||||
|
|
||||||
resp, err := http.Get(task.url)
|
resp, err := downloader.client.Get(task.url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
task.result <- err
|
task.result <- err
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -2,96 +2,37 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
|
||||||
"github.com/smira/aptly/cmd"
|
"github.com/smira/aptly/cmd"
|
||||||
"github.com/smira/aptly/utils"
|
|
||||||
"os"
|
"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() {
|
func main() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if errorMessage != "" {
|
if r := recover(); r != nil {
|
||||||
fmt.Print(errorMessage)
|
fatal, ok := r.(*cmd.FatalError)
|
||||||
}
|
if !ok {
|
||||||
if returnCode != 0 {
|
panic(r)
|
||||||
os.Exit(returnCode)
|
}
|
||||||
|
fmt.Println("ERROR:", fatal.Message)
|
||||||
|
os.Exit(fatal.ReturnCode)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
command := cmd.RootCommand()
|
command := cmd.RootCommand()
|
||||||
|
|
||||||
err := command.Flag.Parse(os.Args[1:])
|
flags, args, err := command.ParseFlags(os.Args[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatal(err)
|
cmd.Fatal(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = loadConfig(command)
|
err = cmd.InitContext(flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatal(err)
|
cmd.Fatal(err)
|
||||||
return
|
|
||||||
}
|
|
||||||
if returnCode != 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.InitContext(command)
|
|
||||||
if err != nil {
|
|
||||||
fatal(err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
defer cmd.ShutdownContext()
|
defer cmd.ShutdownContext()
|
||||||
|
|
||||||
err = command.Dispatch(command.Flag.Args())
|
err = command.Dispatch(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatal(err)
|
cmd.Fatal(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+276
-69
@@ -1,7 +1,7 @@
|
|||||||
.\" generated with Ronn/v0.7.3
|
.\" generated with Ronn/v0.7.3
|
||||||
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
||||||
.
|
.
|
||||||
.TH "APTLY" "1" "March 2014" "" ""
|
.TH "APTLY" "1" "May 2014" "" ""
|
||||||
.
|
.
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
\fBaptly\fR \- Debian repository management tool
|
\fBaptly\fR \- Debian repository management tool
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
Common command format:
|
Common command format:
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
aptly has integrated help that matches contents of this manual page, to get help, prepend \fBhelp\fR to command name:
|
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\.
|
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
|
.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"
|
.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\.
|
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
|
.TP
|
||||||
\fBgpgDisableSign\fR
|
\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
|
.TP
|
||||||
\fBgpgDisableVerify\fR
|
\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
|
.TP
|
||||||
\fBdownloadSourcePackages\fR
|
\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:
|
When specified on command line, condition may have to be quoted according to shell rules, so that it stays single argument:
|
||||||
.
|
.
|
||||||
.P
|
.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"
|
.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)
|
location of configuration file (default locations are /etc/aptly\.conf, ~/\.aptly\.conf)
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBcpuprofile\fR=
|
|
||||||
write cpu profile to file
|
|
||||||
.
|
|
||||||
.TP
|
|
||||||
\-\fBdep\-follow\-all\-variants\fR=false
|
\-\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
|
.TP
|
||||||
\-\fBdep\-follow\-recommends\fR=false
|
\-\fBdep\-follow\-recommends\fR=false
|
||||||
@@ -166,23 +162,11 @@ when processing dependencies, follow from binary to Source packages
|
|||||||
\-\fBdep\-follow\-suggests\fR=false
|
\-\fBdep\-follow\-suggests\fR=false
|
||||||
when processing dependencies, follow Suggests
|
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"
|
.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
|
.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
|
.P
|
||||||
PPA urls could specified in short format:
|
PPA urls could specified in short format:
|
||||||
@@ -223,11 +207,18 @@ Example:
|
|||||||
.P
|
.P
|
||||||
$ aptly mirror list
|
$ aptly mirror list
|
||||||
.
|
.
|
||||||
|
.P
|
||||||
|
Options:
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
\-\fBraw\fR=false
|
||||||
|
display list in machine\-readable format
|
||||||
|
.
|
||||||
.SH "SHOW DETAILS ABOUT MIRROR"
|
.SH "SHOW DETAILS ABOUT MIRROR"
|
||||||
\fBaptly\fR \fBmirror\fR \fBshow\fR \fIname\fR
|
\fBaptly\fR \fBmirror\fR \fBshow\fR \fIname\fR
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Shows detailed information about mirror\.
|
Shows detailed information about the mirror\.
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -246,7 +237,7 @@ show detailed list of packages and versions stored in the mirror
|
|||||||
\fBaptly\fR \fBmirror\fR \fBdrop\fR \fIname\fR
|
\fBaptly\fR \fBmirror\fR \fBdrop\fR \fIname\fR
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -265,7 +256,7 @@ force mirror deletion even if used by snapshots
|
|||||||
\fBaptly\fR \fBmirror\fR \fBupdate\fR \fIname\fR
|
\fBaptly\fR \fBmirror\fR \fBupdate\fR \fIname\fR
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
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
|
\fBaptly\fR \fBrepo\fR \fBadd\fR \fIname\fR
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -308,7 +299,7 @@ Options:
|
|||||||
remove files that have been imported successfully into repository
|
remove files that have been imported successfully into repository
|
||||||
.
|
.
|
||||||
.SH "COPY PACKAGES BETWEEN LOCAL REPOSITORIES"
|
.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
|
.P
|
||||||
Command copy copies packages matching \fIpackage\-spec\fR from local repo \fIsrc\-name\fR to local repo \fIdst\-name\fR\.
|
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:
|
Example:
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
$ aptly repo copy testing stable \'myapp (=0\.1\.12)\'
|
$ aptly repo copy testing stable \(cqmyapp (=0\.1\.12)\(cq
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Options:
|
Options:
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBdry\-run\fR=false
|
\-\fBdry\-run\fR=false
|
||||||
don\'t copy, just show what would be copied
|
don\(cqt copy, just show what would be copied
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBwith\-deps\fR=false
|
\-\fBwith\-deps\fR=false
|
||||||
@@ -349,11 +340,19 @@ Options:
|
|||||||
\-\fBcomment\fR=
|
\-\fBcomment\fR=
|
||||||
any text that would be used to described local repository
|
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"
|
.SH "DELETE LOCAL REPOSITORY"
|
||||||
\fBaptly\fR \fBrepo\fR \fBdrop\fR \fIname\fR
|
\fBaptly\fR \fBrepo\fR \fBdrop\fR \fIname\fR
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -368,8 +367,35 @@ Options:
|
|||||||
\-\fBforce\fR=false
|
\-\fBforce\fR=false
|
||||||
force local repo deletion even if used by snapshots
|
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"
|
.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
|
.P
|
||||||
Command import looks up packages matching \fIpackage\-spec\fR in mirror \fIsrc\-mirror\fR and copies them to local repo \fIdst\-repo\fR\.
|
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
|
.TP
|
||||||
\-\fBdry\-run\fR=false
|
\-\fBdry\-run\fR=false
|
||||||
don\'t import, just show what would be imported
|
don\(cqt import, just show what would be imported
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBwith\-deps\fR=false
|
\-\fBwith\-deps\fR=false
|
||||||
@@ -395,7 +421,7 @@ follow dependencies when processing package\-spec
|
|||||||
\fBaptly\fR \fBrepo\fR \fBlist\fR
|
\fBaptly\fR \fBrepo\fR \fBlist\fR
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
List shows full list of local package repositories\.
|
List command shows full list of local package repositories\.
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -403,8 +429,15 @@ Example:
|
|||||||
.P
|
.P
|
||||||
$ aptly repo list
|
$ aptly repo list
|
||||||
.
|
.
|
||||||
|
.P
|
||||||
|
Options:
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
\-\fBraw\fR=false
|
||||||
|
display list in machine\-readable format
|
||||||
|
.
|
||||||
.SH "MOVE PACKAGES BETWEEN LOCAL REPOSITORIES"
|
.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
|
.P
|
||||||
Command move moves packages matching \fIpackage\-spec\fR from local repo \fIsrc\-name\fR to local repo \fIdst\-name\fR\.
|
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:
|
Example:
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
$ aptly repo move testing stable \'myapp (=0\.1\.12)\'
|
$ aptly repo move testing stable \(cqmyapp (=0\.1\.12)\(cq
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Options:
|
Options:
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBdry\-run\fR=false
|
\-\fBdry\-run\fR=false
|
||||||
don\'t move, just show what would be moved
|
don\(cqt move, just show what would be moved
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBwith\-deps\fR=false
|
\-\fBwith\-deps\fR=false
|
||||||
follow dependencies when processing package\-spec
|
follow dependencies when processing package\-spec
|
||||||
.
|
.
|
||||||
.SH "REMOVE PACKAGES FROM LOCAL REPOSITORY"
|
.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
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
$ aptly repo remove testing \'myapp (=0\.1\.12)\'
|
$ aptly repo remove testing \(cqmyapp (=0\.1\.12)\(cq
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Options:
|
Options:
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBdry\-run\fR=false
|
\-\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"
|
.SH "SHOW DETAILS ABOUT LOCAL REPOSITORY"
|
||||||
\fBaptly\fR \fBrepo\fR \fBshow\fR \fIname\fR
|
\fBaptly\fR \fBrepo\fR \fBshow\fR \fIname\fR
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Show shows full information about local package repository\.
|
Show command shows full information about local package repository\.
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
ex: $ aptly repo show testing
|
ex: $ aptly repo show testing
|
||||||
@@ -491,11 +524,18 @@ Example:
|
|||||||
.P
|
.P
|
||||||
$ aptly snapshot list
|
$ aptly snapshot list
|
||||||
.
|
.
|
||||||
|
.P
|
||||||
|
Options:
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
\-\fBraw\fR=false
|
||||||
|
display list in machine\-readable format
|
||||||
|
.
|
||||||
.SH "SHOWS DETAILS ABOUT SNAPSHOT"
|
.SH "SHOWS DETAILS ABOUT SNAPSHOT"
|
||||||
\fBaptly\fR \fBsnapshot\fR \fBshow\fR \fIname\fR
|
\fBaptly\fR \fBsnapshot\fR \fBshow\fR \fIname\fR
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Command show displays full information about snapshot\.
|
Command show displays full information about a snapshot\.
|
||||||
.
|
.
|
||||||
.P
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -518,10 +558,10 @@ Options:
|
|||||||
show list of packages
|
show list of packages
|
||||||
.
|
.
|
||||||
.SH "VERIFY DEPENDENCIES IN SNAPSHOT"
|
.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
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -537,10 +577,10 @@ $ aptly snapshot verify wheezy\-main wheezy\-contrib wheezy\-non\-free
|
|||||||
.IP "" 0
|
.IP "" 0
|
||||||
.
|
.
|
||||||
.SH "PULL PACKAGES FROM ANOTHER SNAPSHOT"
|
.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
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -560,15 +600,15 @@ Options:
|
|||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBdry\-run\fR=false
|
\-\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
|
.TP
|
||||||
\-\fBno\-deps\fR=false
|
\-\fBno\-deps\fR=false
|
||||||
don\'t process dependencies, just pull listed packages
|
don\(cqt process dependencies, just pull listed packages
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBno\-remove\fR=false
|
\-\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"
|
.SH "DIFFERENCE BETWEEN TWO SNAPSHOTS"
|
||||||
\fBaptly\fR \fBsnapshot\fR \fBdiff\fR \fIname\-a\fR \fIname\-b\fR
|
\fBaptly\fR \fBsnapshot\fR \fBdiff\fR \fIname\-a\fR \fIname\-b\fR
|
||||||
@@ -594,13 +634,13 @@ Options:
|
|||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBonly\-matching\fR=false
|
\-\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"
|
.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
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -615,11 +655,18 @@ $ aptly snapshot merge wheezy\-w\-backports wheezy\-main wheezy\-backports
|
|||||||
.
|
.
|
||||||
.IP "" 0
|
.IP "" 0
|
||||||
.
|
.
|
||||||
|
.P
|
||||||
|
Options:
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
\-\fBlatest\fR=false
|
||||||
|
use only the latest version of each package
|
||||||
|
.
|
||||||
.SH "DELETE SNAPSHOT"
|
.SH "DELETE SNAPSHOT"
|
||||||
\fBaptly\fR \fBsnapshot\fR \fBdrop\fR \fIname\fR
|
\fBaptly\fR \fBsnapshot\fR \fBdrop\fR \fIname\fR
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -641,11 +688,113 @@ Options:
|
|||||||
\-\fBforce\fR=false
|
\-\fBforce\fR=false
|
||||||
remove snapshot even if it was used as source for other snapshots
|
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"
|
.SH "PUBLISH SNAPSHOT"
|
||||||
\fBaptly\fR \fBpublish\fR \fBsnapshot\fR \fIname\fR [\fIprefix\fR]
|
\fBaptly\fR \fBpublish\fR \fBsnapshot\fR \fIname\fR [\fIprefix\fR]
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -680,18 +829,26 @@ GPG key ID to use when signing the release
|
|||||||
GPG keyring to use (instead of default)
|
GPG keyring to use (instead of default)
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
|
\-\fBlabel\fR=
|
||||||
|
label to publish
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
\-\fBorigin\fR=
|
||||||
|
origin name to publish
|
||||||
|
.
|
||||||
|
.TP
|
||||||
\-\fBsecret\-keyring\fR=
|
\-\fBsecret\-keyring\fR=
|
||||||
GPG secret keyring to use (instead of default)
|
GPG secret keyring to use (instead of default)
|
||||||
.
|
.
|
||||||
.TP
|
.TP
|
||||||
\-\fBskip\-signing\fR=false
|
\-\fBskip\-signing\fR=false
|
||||||
don\'t sign Release files with GPG
|
don\(cqt sign Release files with GPG
|
||||||
.
|
.
|
||||||
.SH "LIST OF PUBLISHED REPOSITORIES"
|
.SH "UPDATE PUBLISHED REPOSITORY BY SWITCHING TO NEW SNAPSHOT"
|
||||||
\fBaptly\fR \fBpublish\fR \fBlist\fR
|
\fBaptly\fR \fBpublish\fR \fBswitch\fR \fIdistribution\fR [\fIprefix\fR] \fInew\-snapshot\fR
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -700,17 +857,36 @@ Example:
|
|||||||
.
|
.
|
||||||
.nf
|
.nf
|
||||||
|
|
||||||
$ aptly publish list
|
$ aptly publish update wheezy ppa wheezy\-7\.5
|
||||||
.
|
.
|
||||||
.fi
|
.fi
|
||||||
.
|
.
|
||||||
.IP "" 0
|
.IP "" 0
|
||||||
.
|
.
|
||||||
.SH "REMOVE PUBLISHED REPOSITORY"
|
.P
|
||||||
\fBaptly\fR \fBpublish\fR \fBdrop\fR \fIdistribution\fR [\fIprefix\fR]
|
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
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -719,17 +895,36 @@ Example:
|
|||||||
.
|
.
|
||||||
.nf
|
.nf
|
||||||
|
|
||||||
$ aptly publish drop wheezy
|
$ aptly publish update wheezy ppa
|
||||||
.
|
.
|
||||||
.fi
|
.fi
|
||||||
.
|
.
|
||||||
.IP "" 0
|
.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"
|
.SH "CLEANUP DB AND PACKAGE POOL"
|
||||||
\fBaptly\fR \fBdb\fR \fBcleanup\fR
|
\fBaptly\fR \fBdb\fR \fBcleanup\fR
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -737,11 +932,23 @@ Example:
|
|||||||
.P
|
.P
|
||||||
$ aptly db cleanup
|
$ 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"
|
.SH "HTTP SERVE PUBLISHED REPOSITORIES"
|
||||||
\fBaptly\fR \fBserve\fR
|
\fBaptly\fR \fBserve\fR
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
@@ -760,7 +967,7 @@ host:port for HTTP listening
|
|||||||
\fBaptly\fR \fBgraph\fR
|
\fBaptly\fR \fBgraph\fR
|
||||||
.
|
.
|
||||||
.P
|
.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
|
.P
|
||||||
Example:
|
Example:
|
||||||
|
|||||||
+2
-2
@@ -2,9 +2,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gonuts/commander"
|
|
||||||
"github.com/gonuts/flag"
|
|
||||||
"github.com/smira/aptly/cmd"
|
"github.com/smira/aptly/cmd"
|
||||||
|
"github.com/smira/commander"
|
||||||
|
"github.com/smira/flag"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"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": "",
|
"ppaCodename": "",
|
||||||
}
|
}
|
||||||
configOverride = {}
|
configOverride = {}
|
||||||
|
environmentOverride = {}
|
||||||
|
|
||||||
fixtureDBDir = os.path.join(os.environ["HOME"], "aptly-fixture-db")
|
fixtureDBDir = os.path.join(os.environ["HOME"], "aptly-fixture-db")
|
||||||
fixturePoolDir = os.path.join(os.environ["HOME"], "aptly-fixture-pool")
|
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",
|
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", "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", "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"):
|
if hasattr(self, "fixtureCmds"):
|
||||||
for cmd in self.fixtureCmds:
|
for cmd in self.fixtureCmds:
|
||||||
@@ -160,6 +162,7 @@ class BaseTest(object):
|
|||||||
command = shlex.split(command)
|
command = shlex.split(command)
|
||||||
environ = os.environ.copy()
|
environ = os.environ.copy()
|
||||||
environ["LC_ALL"] = "C"
|
environ["LC_ALL"] = "C"
|
||||||
|
environ.update(self.environmentOverride)
|
||||||
proc = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=environ)
|
proc = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=environ)
|
||||||
output, _ = proc.communicate()
|
output, _ = proc.communicate()
|
||||||
#print "CMD %s: %.2f" % (" ".join(command), time.time()-start)
|
#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:
|
with open(os.path.join(os.environ["HOME"], ".aptly", path), "r") as f:
|
||||||
return f.read()
|
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):
|
def check_file_contents(self, path, gold_name, match_prepare=None):
|
||||||
contents = self.read_file(path)
|
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
|
No mirrors found, create one with `aptly mirror create ...`.
|
||||||
|
|
||||||
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
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class CreateConfigTest(BaseTest):
|
|||||||
"""
|
"""
|
||||||
new file is generated if missing
|
new file is generated if missing
|
||||||
"""
|
"""
|
||||||
runCmd = "aptly"
|
runCmd = "aptly mirror list"
|
||||||
checkedFile = os.path.join(os.environ["HOME"], ".aptly.conf")
|
checkedFile = os.path.join(os.environ["HOME"], ".aptly.conf")
|
||||||
|
|
||||||
check = BaseTest.check_file
|
check = BaseTest.check_file
|
||||||
@@ -24,7 +24,7 @@ class BadConfigTest(BaseTest):
|
|||||||
"""
|
"""
|
||||||
broken config file
|
broken config file
|
||||||
"""
|
"""
|
||||||
runCmd = "aptly"
|
runCmd = "aptly mirror list"
|
||||||
expectedCode = 1
|
expectedCode = 1
|
||||||
|
|
||||||
gold_processor = BaseTest.expand_environ
|
gold_processor = BaseTest.expand_environ
|
||||||
@@ -41,7 +41,8 @@ class ConfigInFileTest(BaseTest):
|
|||||||
"""
|
"""
|
||||||
config in other file test
|
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
|
prepare = BaseTest.prepare_remove_all
|
||||||
|
|
||||||
outputMatchPrepare = lambda _, s: re.sub(r' -(cpuprofile|memprofile|memstats|meminterval)=.*\n', '', s, flags=re.MULTILINE)
|
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
|
config in other file test
|
||||||
"""
|
"""
|
||||||
runCmd = ["aptly", "-config=nosuchfile.conf"]
|
runCmd = ["aptly", "mirror", "list", "-config=nosuchfile.conf"]
|
||||||
expectedCode = 1
|
expectedCode = 1
|
||||||
prepare = BaseTest.prepare_remove_all
|
prepare = BaseTest.prepare_remove_all
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ repositories, manage local repositories, filter them, merge,
|
|||||||
upgrade individual packages, take snapshots and publish them
|
upgrade individual packages, take snapshots and publish them
|
||||||
back as Debian repositories.
|
back as Debian repositories.
|
||||||
|
|
||||||
aptly goal is to establish repeatiblity and controlled changes
|
aptly's goal is to establish repeatability and controlled changes
|
||||||
in package environment. aptly allows to fix set of packages in
|
in a package-centric environment. aptly allows to fix a set of packages
|
||||||
repository, so that package installation and upgrade becomes
|
in a repository, so that package installation and upgrade becomes
|
||||||
deterministic. At the same time aptly allows to perform controlled,
|
deterministic. At the same time aptly allows to perform controlled,
|
||||||
fine-grained changes in repository contents to transition your
|
fine-grained changes in repository contents to transition your
|
||||||
package environment to new version.
|
package environment to new version.
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
Usage: aptly mirror create <name> <archive url> <distribution> [<component1> ...]
|
Usage: aptly mirror create <name> <archive url> <distribution> [<component1> ...]
|
||||||
|
|
||||||
Creates mirror <name> of remote repository, aptly supports both regular and flat Debian repositories exported
|
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:
|
PPA urls could specified in short format:
|
||||||
|
|
||||||
@@ -12,6 +13,12 @@ Example:
|
|||||||
$ aptly mirror create wheezy-main http://mirror.yandex.ru/debian/ wheezy main
|
$ aptly mirror create wheezy-main http://mirror.yandex.ru/debian/ wheezy main
|
||||||
|
|
||||||
Options:
|
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
|
-ignore-signatures=false: disable verification of Release file signatures
|
||||||
-keyring=: gpg keyring to use when verifying Release file (could be specified multiple times)
|
-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
|
-with-sources=false: download source packages in addition to binary packages
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ aptly mirror create - create new mirror
|
|||||||
|
|
||||||
|
|
||||||
Options:
|
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
|
-ignore-signatures=false: disable verification of Release file signatures
|
||||||
-keyring=: gpg keyring to use when verifying Release file (could be specified multiple times)
|
-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
|
-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.
|
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.
|
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
|
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
|
||||||
Codename: wheezy
|
Codename: wheezy
|
||||||
Components: main contrib non-free
|
Components: main contrib non-free
|
||||||
Date: Sat, 08 Feb 2014 10:36:03 UTC
|
Date: Sat, 26 Apr 2014 09:27:11 UTC
|
||||||
Description: Debian 7.4 Released 08 February 2014
|
Description: Debian 7.5 Released 26 April 2014
|
||||||
|
|
||||||
Label: Debian
|
Label: Debian
|
||||||
Origin: Debian
|
Origin: Debian
|
||||||
Suite: stable
|
Suite: stable
|
||||||
Version: 7.4
|
Version: 7.5
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Name: mirror14
|
Name: mirror14
|
||||||
Archive Root URL: http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/
|
Archive Root URL: http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/
|
||||||
Distribution:
|
Distribution: ./
|
||||||
Components:
|
Components:
|
||||||
Architectures:
|
Architectures:
|
||||||
Download Sources: no
|
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
|
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
|
||||||
Codename: wheezy
|
Codename: wheezy
|
||||||
Components: main contrib non-free
|
Components: main contrib non-free
|
||||||
Date: Sat, 08 Feb 2014 10:36:03 UTC
|
Date: Sat, 26 Apr 2014 09:27:11 UTC
|
||||||
Description: Debian 7.4 Released 08 February 2014
|
Description: Debian 7.5 Released 26 April 2014
|
||||||
|
|
||||||
Label: Debian
|
Label: Debian
|
||||||
Origin: Debian
|
Origin: Debian
|
||||||
Suite: stable
|
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