mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-04 05:10:40 +00:00
Compare commits
179 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3008147b3a | |||
| 421283d161 | |||
| 4020e30f07 | |||
| 766d634fbb | |||
| 1bba0319cb | |||
| 651f6e934c | |||
| f2a7018335 | |||
| 7a3063963c | |||
| 0c85e5252f | |||
| d0e73a3e00 | |||
| 955b09a41c | |||
| 3075addd46 | |||
| ecbd146cd3 | |||
| 80100a2eda | |||
| fc51eb8414 | |||
| 8c83706684 | |||
| 3e5d54f3ef | |||
| 9b4e858734 | |||
| 14e66c03a6 | |||
| 803570bf26 | |||
| 66d1f40a49 | |||
| 610940ae5d | |||
| cddce9a5f7 | |||
| 36892a2797 | |||
| f3bad4ee2c | |||
| bb13462f7b | |||
| a3dbc8444b | |||
| 9dccf2a4ee | |||
| 919dc53814 | |||
| 87c0430628 | |||
| ca4736674e | |||
| cf3dc6be27 | |||
| d4307ad03c | |||
| 47225a0e2d | |||
| f4bf144145 | |||
| ad623f7d74 | |||
| 3a51116881 | |||
| 39d2dd2483 | |||
| b532cb19ee | |||
| f5ee710098 | |||
| 7cbba33fe7 | |||
| a9c812a1b3 | |||
| 09648044db | |||
| a97365377f | |||
| 0e9ccb4481 | |||
| c4a30ce0ce | |||
| d350e9edba | |||
| ab468bcac4 | |||
| 679fc3e5fd | |||
| e99fee3908 | |||
| c3bcc9f7cb | |||
| 62d3c625ed | |||
| 3a9ce36662 | |||
| b4d7f8ec55 | |||
| 79eaf5d460 | |||
| 502ed4366a | |||
| d65de9bd30 | |||
| c1feb4210c | |||
| 360e09cc7d | |||
| 182a4bd39c | |||
| 35976f5ff1 | |||
| 982a25992e | |||
| 08123ef5e3 | |||
| 0dd44f98b8 | |||
| 996fc445be | |||
| df0a678863 | |||
| 89ac907ca3 | |||
| 7ce8b0ff7b | |||
| a1258f2125 | |||
| 59d72c8112 | |||
| 5bd0546fb7 | |||
| 67422642ef | |||
| de5e39818e | |||
| cfdcf84fa5 | |||
| 043ed13c18 | |||
| 0271456ca4 | |||
| 08bf46e486 | |||
| 93eef2cc80 | |||
| c4f1179b65 | |||
| 2487d5da37 | |||
| 772035ad44 | |||
| e49afbcd2d | |||
| 1803252f33 | |||
| 555256c1fe | |||
| 26267802e9 | |||
| 69eb6a85b0 | |||
| 78c7bf6af1 | |||
| d5bc13751b | |||
| b04027edad | |||
| 5c6e4fffc4 | |||
| 0da53a2d87 | |||
| db4ccce9e4 | |||
| c538ca8cc6 | |||
| 00bb27fcea | |||
| b571e4d79b | |||
| 29cb5d9c9e | |||
| 899a28cc27 | |||
| 898f726659 | |||
| 5a9e13265f | |||
| 17f5afb494 | |||
| d87fc1be21 | |||
| c3b3e580bd | |||
| abc117531d | |||
| 03b800882c | |||
| 6ffc6056c4 | |||
| 2fe8f5cc1a | |||
| a738d4843d | |||
| 86f3a0b463 | |||
| 121f93957d | |||
| be3cd88a31 | |||
| 81d75ccba4 | |||
| a3df28ec4b | |||
| 06ed37225a | |||
| a9cb70dc08 | |||
| 845ef28a79 | |||
| c9e8d98e37 | |||
| 1728691462 | |||
| 4197af902e | |||
| 656dddda53 | |||
| e1ca459329 | |||
| 7ec27ad88c | |||
| e21506d373 | |||
| e183ddb981 | |||
| c61a6b6dd8 | |||
| 211cce1a8e | |||
| 362cdbcd57 | |||
| 0f902ee74b | |||
| f1d892c759 | |||
| ce5f277f36 | |||
| 9b4ea531d2 | |||
| 69b48de0af | |||
| 99621119e8 | |||
| aa803efd28 | |||
| b48ebbae81 | |||
| 4fea570f5e | |||
| cf12c0b751 | |||
| bbec7ef948 | |||
| 311c8ca6ad | |||
| 33a8dcdacd | |||
| a8e6251a80 | |||
| 326d589f56 | |||
| 7adc065bb8 | |||
| 640c9fe8bd | |||
| 81d6325730 | |||
| 8ece5368b1 | |||
| 7afcc93507 | |||
| e63bbe839b | |||
| 49c8c8bdc0 | |||
| e70517b9ca | |||
| d66fe47def | |||
| 667703a9ac | |||
| 1268f744ab | |||
| d684c87fd1 | |||
| f9853de144 | |||
| b144227fdf | |||
| 7e11e5c652 | |||
| 9ca005147c | |||
| c0b41a7e96 | |||
| 335298d074 | |||
| c903633363 | |||
| 5bf015b2b7 | |||
| 01338d6037 | |||
| 356187f3ae | |||
| 645bba1924 | |||
| 10da8330b0 | |||
| ba30a42d6d | |||
| 6412bee952 | |||
| f168feb9b8 | |||
| 4e2fce7251 | |||
| e37fe33203 | |||
| 5dbb771ba8 | |||
| 4969c31e38 | |||
| b1e9b82ce3 | |||
| 275db14b9f | |||
| 5ccbd232f4 | |||
| 82c06f78f7 | |||
| 4aa24048d5 | |||
| 06f1c62ef0 | |||
| 2c5dcde29d |
+3
-1
@@ -23,4 +23,6 @@ _testmain.go
|
||||
*.test
|
||||
|
||||
coverage.html
|
||||
coverage*.out
|
||||
coverage*.out
|
||||
|
||||
*.pyc
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2013 Andrey Smirnov. All rights reserved.
|
||||
Copyright 2013-2014 Andrey Smirnov. All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
@@ -14,8 +14,8 @@ all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
@@ -3,9 +3,11 @@ GOVERSION=$(shell go version | awk '{print $$3;}')
|
||||
ifeq ($(TRAVIS), true)
|
||||
GOVERALLS?=$(HOME)/gopath/bin/goveralls
|
||||
SRCPATH?=$(HOME)/gopath/src
|
||||
BINPATH=$(HOME)/gopath/bin
|
||||
else
|
||||
GOVERALLS?=goveralls
|
||||
SRCPATH?=$(GOPATH)/src
|
||||
BINPATH?=$(GOPATH)/bin
|
||||
endif
|
||||
|
||||
ifeq ($(GOVERSION), go1.2)
|
||||
@@ -16,13 +18,11 @@ TRAVIS_TARGET=test
|
||||
PREPARE_LIST=
|
||||
endif
|
||||
|
||||
all: test check
|
||||
all: test check system-test
|
||||
|
||||
prepare: $(PREPARE_LIST)
|
||||
go get -d -v ./...
|
||||
go get launchpad.net/gocheck
|
||||
# temporary fix: use commander develop version for now (https://github.com/smira/aptly/pull/1)
|
||||
cd $(SRCPATH)/github.com/gonuts/commander && git fetch && git checkout develop
|
||||
|
||||
cover-prepare:
|
||||
go get github.com/golang/lint/golint
|
||||
@@ -45,7 +45,14 @@ check:
|
||||
go tool vet -all=true .
|
||||
golint .
|
||||
|
||||
travis: $(TRAVIS_TARGET)
|
||||
system-test:
|
||||
ifeq ($(GOVERSION), go1.2)
|
||||
if [ ! -e ~/aptly-fixture-db ]; then git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; fi
|
||||
endif
|
||||
go install
|
||||
PATH=$(BINPATH):$(PATH) python system/run.py --long
|
||||
|
||||
travis: $(TRAVIS_TARGET) system-test
|
||||
|
||||
test:
|
||||
go test -v ./... -gocheck.v=true
|
||||
|
||||
+10
-342
@@ -10,366 +10,34 @@ aptly
|
||||
|
||||
Aptly is a swiss army knife for Debian repository management.
|
||||
|
||||
It allows to: ("+" means planned features)
|
||||
Documentation is available at `http://www.aptly.info/ <http://www.aptly.info/>`_. For support use
|
||||
mailing list `aptly-discuss <https://groups.google.com/forum/#!forum/aptly-discuss>`_.
|
||||
|
||||
Aptly features: ("+" means planned features)
|
||||
|
||||
* make mirrors of remote Debian/Ubuntu repositories, limiting by components/architectures
|
||||
* take snapshots of mirrors at any point in time, fixing state of repository at some moment of time
|
||||
* publish snapshot as Debian repository, ready to be consumed by apt
|
||||
* controlled update of one or more packages in snapshot from upstream mirror, tracking dependencies
|
||||
* merge two or more snapshots into one (+)
|
||||
* filter repository by search query, pulling dependencies when required (+)
|
||||
* controlled update of one or more packages in snapshot from upstream mirror, tracking dependencies (+)
|
||||
* publish self-made packages as Debian repositories (+)
|
||||
|
||||
Current limitations:
|
||||
|
||||
* source packages, debian-installer and translations not supported yet
|
||||
* checksums and signature are not verified while downloading
|
||||
* deleting created items is not implemented
|
||||
* signature is not verified while downloading
|
||||
* cleaning up stale files is not implemented
|
||||
|
||||
Currently aptly is under heavy development, so please use it with care.
|
||||
|
||||
.. contents::
|
||||
|
||||
Download
|
||||
--------
|
||||
|
||||
TBD
|
||||
Binary executables (depends almost only on libc) are available for download from `Bintray <http://dl.bintray.com/smira/aptly/>`_.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
If you have Go environment set up, you can build aptly from source by running (go 1.1+ required)::
|
||||
|
||||
aptly looks for configuration file in ``/etc/aptly.conf`` and ``~/.aptly.conf``, if no config file found,
|
||||
new one is created. Also aptly needs root directory for database, package and published repository storage.
|
||||
If not specified, directory defaults to ``~/.aptly``, it will be created if missing.
|
||||
go get github.com/smira/aptly
|
||||
|
||||
Configuration file is stored in JSON format::
|
||||
|
||||
{
|
||||
"rootDir": "/var/aptly",
|
||||
"downloadConcurrency": 4
|
||||
}
|
||||
|
||||
Options:
|
||||
|
||||
* ``rootDir`` is root of directory storage to store datbase (``rootDir/db``), downloaded packages (``rootDir/pool``) and
|
||||
published repositories (``rootDir/public``)
|
||||
* ``downloadConcurrency`` is a number of parallel download threads to use when downloading packages
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
Create mirror::
|
||||
|
||||
$ aptly mirror create --architecture="amd64" debian-main http://ftp.ru.debian.org/debian/ squeeze main
|
||||
2013/12/28 19:44:45 Downloading http://ftp.ru.debian.org/debian/dists/squeeze/Release...
|
||||
...
|
||||
|
||||
Mirror [debian-main]: http://ftp.ru.debian.org/debian/ squeeze successfully added.
|
||||
You can run 'aptly mirror update debian-main' to download repository contents.
|
||||
|
||||
Take snapshot::
|
||||
|
||||
$ aptly snapshot create debian-3112 from mirror debian-main
|
||||
|
||||
Snapshot debian-3112 successfully created.
|
||||
You can run 'aptly publish snapshot debian-3112' to publish snapshot as Debian repository.
|
||||
|
||||
Publish snapshot (requires generated GPG key)::
|
||||
|
||||
$ aptly publish snapshot debian-3112
|
||||
|
||||
...
|
||||
|
||||
Snapshot back has been successfully published.
|
||||
Please setup your webserver to serve directory '/var/aptly/public' with autoindexing.
|
||||
Now you can add following line to apt sources:
|
||||
deb http://your-server/ squeeze main
|
||||
Don't forget to add your GPG key to apt with apt-key.
|
||||
|
||||
Set up webserver (e.g. nginx)::
|
||||
|
||||
server {
|
||||
root /home/example/.aptly/public;
|
||||
server_name mirror.local;
|
||||
|
||||
location / {
|
||||
autoindex on;
|
||||
}
|
||||
|
||||
Add new repository to apt's sources::
|
||||
|
||||
deb http://mirror.local/ squeeze main
|
||||
|
||||
Run apt-get to fetch repository metadata::
|
||||
|
||||
apt-get update
|
||||
|
||||
Enjoy!
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Aptly supports commands in three basic categories:
|
||||
|
||||
* ``mirror``
|
||||
* ``snapshot``
|
||||
* ``publish``
|
||||
|
||||
Command ``mirror``
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Mirror subcommands manage mirrors of remote Debian repositories.
|
||||
|
||||
``aptly mirror create``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Creates mirror of remote repository. It supports only HTTP repositories.
|
||||
|
||||
Usage::
|
||||
|
||||
$ aptly mirror create <name> <archive url> <distribution> [<component1> ...]
|
||||
|
||||
Params are:
|
||||
|
||||
* ``name`` is a name that would be used in aptly to reference this mirror
|
||||
* ``archive url`` is a root of archive, e.g. http://ftp.ru.debian.org/debian/
|
||||
* ``distribution`` is a distribution name, e.g. ``squeeze``
|
||||
* ``component1`` is an optional list of components to download, if not
|
||||
specified aptly would fetch all components, e.g. ``main``
|
||||
|
||||
Options:
|
||||
|
||||
* ``--architecture="i386,amd64"`` list of architectures to fetch, if not specified,
|
||||
aptly would fetch packages for all architectures
|
||||
|
||||
Example::
|
||||
|
||||
$ aptly mirror create --architecture="amd64" debian-main http://ftp.ru.debian.org/debian/ squeeze main
|
||||
2013/12/28 19:44:45 Downloading http://ftp.ru.debian.org/debian/dists/squeeze/Release...
|
||||
...
|
||||
|
||||
Mirror [debian-main]: http://ftp.ru.debian.org/debian/ squeeze successfully added.
|
||||
You can run 'aptly mirror update debian-main' to download repository contents.
|
||||
|
||||
``aptly mirror update``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Updates (fetches packages and meta) remote mirror. When mirror is created, it should be run for the
|
||||
first time to fetch mirror contents. This command could be run many times. If interrupted, it could
|
||||
be restarted in a safe way.
|
||||
|
||||
Usage::
|
||||
|
||||
$ aptly mirror update <name>
|
||||
|
||||
Params are:
|
||||
|
||||
* ``name`` is a mirror name (given when mirror was created)
|
||||
|
||||
All packages would be stored under aptly's root dir (see section on Configuration).
|
||||
|
||||
Example::
|
||||
|
||||
$ aptly mirror update debian-main
|
||||
|
||||
2013/12/29 18:32:34 Downloading http://ftp.ru.debian.org/debian/dists/squeeze/Release...
|
||||
2013/12/29 18:32:37 Downloading http://ftp.ru.debian.org/debian/dists/squeeze/main/binary-amd64/Packages.bz2...
|
||||
2013/12/29 18:37:19 Downloading http://ftp.ru.debian.org/debian/pool/main/libg/libgwenhywfar/libgwenhywfar47-dev_3.11.3-1_amd64.deb...
|
||||
....
|
||||
|
||||
``aptly mirror list``
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Shows list of registered mirrors of repositories.
|
||||
|
||||
Usage::
|
||||
|
||||
$ aptly mirror list
|
||||
|
||||
Example::
|
||||
|
||||
$ aptly mirror list
|
||||
List of mirrors:
|
||||
* [backports]: http://mirror.yandex.ru/backports.org/ squeeze-backports
|
||||
* [debian-main]: http://ftp.ru.debian.org/debian/ squeeze
|
||||
|
||||
To get more information about repository, run `aptly mirror show <name>`.
|
||||
|
||||
``aptly mirror show``
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Shows detailed information about mirror.
|
||||
|
||||
Usage::
|
||||
|
||||
$ aptly mirror show <name>
|
||||
|
||||
Params are:
|
||||
|
||||
* ``name`` is a mirror name (given when mirror was created)
|
||||
|
||||
Example::
|
||||
|
||||
$ aptly mirror show backports2
|
||||
Name: backports2
|
||||
Archive Root URL: http://mirror.yandex.ru/backports.org/
|
||||
Distribution: squeeze-backports
|
||||
Components: main, contrib, non-free
|
||||
Architectures: i386, amd64
|
||||
Last update: 2013-12-27 19:30:19 MSK
|
||||
Number of packages: 3898
|
||||
|
||||
Information from release file:
|
||||
...
|
||||
|
||||
In detailed information, one can see basiс parameters of the mirror, filters by component & architecture, timestamp
|
||||
of last successful repository fetch and number of packages.
|
||||
|
||||
Command ``snapshot``
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Snapshot is a fixed state of remote repository. Internally snapshot is list of packages with explicit version.
|
||||
Snapshot is immutable, i.e. it can't change since it has been created.
|
||||
|
||||
``aptly snapshot create .. from mirror``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Creates snapshot from current state of remote mirror. Mirros should be updated at least once before using this command.
|
||||
|
||||
Usage::
|
||||
|
||||
$ aptly snapshot create <name> from mirror <mirror-name>
|
||||
|
||||
Params are:
|
||||
|
||||
* ``name`` is a name for the snapshot to be created
|
||||
* ``mirror-name`` is a mirror name (given when mirror was created)
|
||||
|
||||
Example::
|
||||
|
||||
$ aptly snapshot create monday-updates from mirror backports2
|
||||
|
||||
Snapshot monday-updates successfully created.
|
||||
You can run 'aptly publish snapshot monday-updates' to publish snapshot as Debian repository.
|
||||
|
||||
``aptly snapshot list``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Displays list of all created snapshots.
|
||||
|
||||
Usage::
|
||||
|
||||
$ aptly snapshot list
|
||||
|
||||
Example::
|
||||
|
||||
$ aptly snapshot list
|
||||
List of snapshots:
|
||||
* [monday-updates]: Snapshot from mirror [backports2]: http://mirror.yandex.ru/backports.org/ squeeze-backports
|
||||
* [back]: Snapshot from mirror [backports2]: http://mirror.yandex.ru/backports.org/ squeeze-backports
|
||||
|
||||
To get more information about snapshot, run `aptly snapshot show <name>`.
|
||||
|
||||
With snapshot information, basic information about snapshot origin is displayed: which mirror it has been created from.
|
||||
|
||||
``aptly snapshot show``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Shows detailed information about snapshot. Full list of packages in the snapshot is displayed as well.
|
||||
|
||||
Usage::
|
||||
|
||||
$ aptly snapshot show <name>
|
||||
|
||||
Params:
|
||||
|
||||
* ``name`` is snapshot name which has been given during snapshot creation
|
||||
|
||||
Example::
|
||||
|
||||
Name: back
|
||||
Created At: 2013-12-24 15:39:29 MSK
|
||||
Description: Snapshot from mirror [backports2]: http://mirror.yandex.ru/backports.org/ squeeze-backports
|
||||
Number of packages: 3898
|
||||
Packages:
|
||||
altos-1.0.3~bpo60+1_i386
|
||||
amanda-client-1:3.3.1-3~bpo60+1_amd64
|
||||
...
|
||||
|
||||
Command ``publish``
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Publishing snapshot as Debian repository which could be served by HTTP/FTP/rsync server. Repository is signed by
|
||||
user's key with GnuPG. Key should be created beforehand (see section GPG Keys). Published repository could
|
||||
be consumed directly by apt.
|
||||
|
||||
``aptly publish snapshot``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Published repositories appear under ``rootDir/public`` directory.
|
||||
|
||||
Usage::
|
||||
|
||||
$ aptly publish snapshot <name> [<prefix>]
|
||||
|
||||
Params:
|
||||
|
||||
* ``name`` is a snapshot name that snould be published
|
||||
* ``prefix`` is an optional prefix for publishing, if not specified, repository would be published to the root of
|
||||
publiс directory
|
||||
|
||||
Options:
|
||||
|
||||
* ``-architectures=""``: list of architectures to publish (comma-separated); derived automatically from
|
||||
snapshot contents
|
||||
* ``-component=""``: component name to publish; guessed from original repository (if any), or defaults to
|
||||
main
|
||||
* ``-distribution=""``: distribution name to publish; guessed from original repository distribution
|
||||
* ``-gpg-key=""``: GPG key ID to use when signing the release, if not specified default key is used
|
||||
|
||||
Example::
|
||||
|
||||
$ aptly publish snapshot back
|
||||
Signing file '/var/aptly/public/dists/squeeze-backports/Release' with gpg, please enter your passphrase when prompted:
|
||||
|
||||
<<gpg asks for passphrase>>
|
||||
|
||||
Clearsigning file '/var/aptly/public/dists/squeeze-backports/Release' with gpg, please enter your passphrase when prompted:
|
||||
|
||||
<<gpg asks for passphrase>>
|
||||
|
||||
Snapshot back has been successfully published.
|
||||
Please setup your webserver to serve directory '/var/aptly/public' with autoindexing.
|
||||
Now you can add following line to apt sources:
|
||||
deb http://your-server/ squeeze-backports main
|
||||
Don't forget to add your GPG key to apt with apt-key.
|
||||
|
||||
Directory structure for published repositories::
|
||||
|
||||
public/ - root of published tree (root for webserver)
|
||||
dists/
|
||||
squeeze/ - distribution name
|
||||
Release - raw file
|
||||
InRelease - clearsigned file
|
||||
Release.gpg - signature for Release file
|
||||
binary-i386/
|
||||
Packages - list of metadata for packages
|
||||
Packages.gz
|
||||
Packages.bz2
|
||||
pool/
|
||||
main/ - component name
|
||||
m/
|
||||
mars-invaders/
|
||||
mars-invaders_1.0.3_i386.deb - package (hard link to package from main pool)
|
||||
|
||||
GPG Keys
|
||||
--------
|
||||
|
||||
GPG key is required to sign any published repository. Key should be generated before publishing first repository.
|
||||
|
||||
Key generation, storage, backup and revocation is out of scope of this document, there are many tutorials available,
|
||||
e.g. `this one <http://fedoraproject.org/wiki/Creating_GPG_Keys>`_.
|
||||
|
||||
Publiс part of the key should be exported (``gpg --export --armor``) and imported into apt keyring on all machines that would be using
|
||||
published repositories using ``apt-key``.
|
||||
If you don't have Go installed (or older version), you can easily install Go using `gvm <https://github.com/moovweb/gvm/>`_.
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.google.com/p/gographviz"
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func graphvizEscape(s string) string {
|
||||
return fmt.Sprintf("\"%s\"", strings.Replace(s, "\"", "\\\"", 0))
|
||||
}
|
||||
|
||||
func aptlyGraph(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
graph := gographviz.NewGraph()
|
||||
graph.SetDir(true)
|
||||
graph.SetName("aptly")
|
||||
|
||||
fmt.Printf("Loading mirrors...\n")
|
||||
|
||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
||||
|
||||
err = repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
|
||||
err := repoCollection.LoadComplete(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
graph.AddNode("aptly", graphvizEscape(repo.UUID), map[string]string{
|
||||
"shape": "Mrecord",
|
||||
"style": "filled",
|
||||
"fillcolor": "darkgoldenrod1",
|
||||
"label": graphvizEscape(fmt.Sprintf("{Mirror %s|url: %s|dist: %s|comp: %s|arch: %s|pkgs: %d}",
|
||||
repo.Name, repo.ArchiveRoot, repo.Distribution, strings.Join(repo.Components, ", "),
|
||||
strings.Join(repo.Architectures, ", "), repo.NumPackages())),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Loading snapshots...\n")
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
err = snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
|
||||
err := snapshotCollection.LoadComplete(snapshot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
description := snapshot.Description
|
||||
if snapshot.SourceKind == "repo" {
|
||||
description = "Snapshot from repo"
|
||||
}
|
||||
|
||||
graph.AddNode("aptly", graphvizEscape(snapshot.UUID), map[string]string{
|
||||
"shape": "Mrecord",
|
||||
"style": "filled",
|
||||
"fillcolor": "cadetblue1",
|
||||
"label": graphvizEscape(fmt.Sprintf("{Snapshot %s|%s|pkgs: %d}", snapshot.Name, description, snapshot.NumPackages())),
|
||||
})
|
||||
|
||||
if snapshot.SourceKind == "repo" {
|
||||
for _, uuid := range snapshot.SourceIDs {
|
||||
graph.AddEdge(graphvizEscape(uuid), "", graphvizEscape(snapshot.UUID), "", true, nil)
|
||||
}
|
||||
} else if snapshot.SourceKind == "snapshot" {
|
||||
for _, uuid := range snapshot.SourceIDs {
|
||||
graph.AddEdge(graphvizEscape(uuid), "", graphvizEscape(snapshot.UUID), "", true, nil)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Loading published repos...\n")
|
||||
|
||||
publishedCollection := debian.NewPublishedRepoCollection(context.database)
|
||||
|
||||
publishedCollection.ForEach(func(repo *debian.PublishedRepo) error {
|
||||
graph.AddNode("aptly", graphvizEscape(repo.UUID), map[string]string{
|
||||
"shape": "Mrecord",
|
||||
"style": "filled",
|
||||
"fillcolor": "darkolivegreen1",
|
||||
"label": graphvizEscape(fmt.Sprintf("{Published %s/%s|comp: %s|arch: %s}", repo.Prefix, repo.Distribution, repo.Component, strings.Join(repo.Architectures, ", "))),
|
||||
})
|
||||
|
||||
graph.AddEdge(graphvizEscape(repo.SnapshotUUID), "", graphvizEscape(repo.UUID), "", true, nil)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
fmt.Printf("Generating graph...\n")
|
||||
|
||||
buf := bytes.NewBufferString(graph.String())
|
||||
|
||||
tempfile, err := ioutil.TempFile("", "aptly-graph")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tempfile.Close()
|
||||
os.Remove(tempfile.Name())
|
||||
|
||||
tempfilename := tempfile.Name() + ".png"
|
||||
|
||||
command := exec.Command("dot", "-Tpng", "-o"+tempfilename)
|
||||
command.Stderr = os.Stderr
|
||||
|
||||
stdin, err := command.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = command.Start()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to execute dot: %s (is graphviz package installed?)", err)
|
||||
}
|
||||
|
||||
_, err = io.Copy(stdin, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = stdin.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = command.Wait()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = exec.Command("open", tempfilename).Run()
|
||||
if err != nil {
|
||||
fmt.Printf("Rendered to PNG file: %s\n", tempfilename)
|
||||
err = nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func makeCmdGraph() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyGraph,
|
||||
UsageLine: "graph",
|
||||
Short: "display graph of dependencies between aptly objects (requires graphviz)",
|
||||
Long: `
|
||||
Command graph displays relationship between mirrors, snapshots and published repositories using
|
||||
graphviz package to render graph as image.
|
||||
|
||||
ex:
|
||||
$ aptly graph
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-graph", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
+166
-32
@@ -5,9 +5,48 @@ import (
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/smira/aptly/utils"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getVerifier(cmd *commander.Command) (utils.Verifier, error) {
|
||||
if utils.Config.GpgDisableVerify || cmd.Flag.Lookup("ignore-signatures").Value.Get().(bool) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
verifier := &utils.GpgVerifier{}
|
||||
for _, keyRing := range keyRings.keyRings {
|
||||
verifier.AddKeyring(keyRing)
|
||||
}
|
||||
|
||||
err := verifier.InitKeyring()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return verifier, nil
|
||||
}
|
||||
|
||||
type keyRingsFlag struct {
|
||||
keyRings []string
|
||||
}
|
||||
|
||||
func (k *keyRingsFlag) Set(value string) error {
|
||||
k.keyRings = append(k.keyRings, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *keyRingsFlag) Get() interface{} {
|
||||
return k.keyRings
|
||||
}
|
||||
|
||||
func (k *keyRingsFlag) String() string {
|
||||
return strings.Join(k.keyRings, ",")
|
||||
}
|
||||
|
||||
var keyRings = keyRingsFlag{}
|
||||
|
||||
func aptlyMirrorList(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 0 {
|
||||
@@ -15,15 +54,27 @@ func aptlyMirrorList(cmd *commander.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("List of mirrors:\n")
|
||||
|
||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
||||
repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
|
||||
fmt.Printf(" * %s\n", repo)
|
||||
return nil
|
||||
})
|
||||
|
||||
fmt.Printf("\nTo get more information about repository, run `aptly mirror show <name>`.\n")
|
||||
if repoCollection.Len() > 0 {
|
||||
fmt.Printf("List of mirrors:\n")
|
||||
repos := make(sort.StringSlice, repoCollection.Len())
|
||||
i := 0
|
||||
repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
|
||||
repos[i] = repo.String()
|
||||
i++
|
||||
return nil
|
||||
})
|
||||
|
||||
sort.Strings(repos)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -34,18 +85,17 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
var architectures []string
|
||||
archs := cmd.Flag.Lookup("architecture").Value.String()
|
||||
if len(archs) > 0 {
|
||||
architectures = strings.Split(archs, ",")
|
||||
}
|
||||
|
||||
repo, err := debian.NewRemoteRepo(args[0], args[1], args[2], args[3:], architectures)
|
||||
repo, err := debian.NewRemoteRepo(args[0], args[1], args[2], args[3:], context.architecturesList)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create mirror: %s", err)
|
||||
}
|
||||
|
||||
err = repo.Fetch(context.downloader)
|
||||
verifier, err := getVerifier(cmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initialize GPG verifier: %s", err)
|
||||
}
|
||||
|
||||
err = repo.Fetch(context.downloader, verifier)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to fetch mirror: %s", err)
|
||||
}
|
||||
@@ -94,9 +144,19 @@ func aptlyMirrorShow(cmd *commander.Command, args []string) error {
|
||||
}
|
||||
|
||||
fmt.Printf("\nInformation from release file:\n")
|
||||
for name, value := range repo.Meta {
|
||||
fmt.Printf("%s: %s\n", name, value)
|
||||
for _, k := range utils.StrMapSortedKeys(repo.Meta) {
|
||||
fmt.Printf("%s: %s\n", k, repo.Meta[k])
|
||||
}
|
||||
|
||||
withPackages := cmd.Flag.Lookup("with-packages").Value.Get().(bool)
|
||||
if withPackages {
|
||||
if repo.LastDownloadDate.IsZero() {
|
||||
fmt.Printf("Unable to show package list, mirror hasn't been downloaded yet.\n")
|
||||
} else {
|
||||
ListPackagesRefList(repo.RefList())
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -120,14 +180,21 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
|
||||
return fmt.Errorf("unable to update: %s", err)
|
||||
}
|
||||
|
||||
err = repo.Fetch(context.downloader)
|
||||
ignoreMismatch := cmd.Flag.Lookup("ignore-checksums").Value.Get().(bool)
|
||||
|
||||
verifier, err := getVerifier(cmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initialize GPG verifier: %s", err)
|
||||
}
|
||||
|
||||
err = repo.Fetch(context.downloader, verifier)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to update: %s", err)
|
||||
}
|
||||
|
||||
packageCollection := debian.NewPackageCollection(context.database)
|
||||
|
||||
err = repo.Download(context.downloader, packageCollection, context.packageRepository)
|
||||
err = repo.Download(context.downloader, packageCollection, context.packageRepository, ignoreMismatch)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to update: %s", err)
|
||||
}
|
||||
@@ -141,23 +208,64 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func aptlyMirrorDrop(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 1 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
name := args[0]
|
||||
|
||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
||||
repo, err := repoCollection.ByName(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to drop: %s", err)
|
||||
}
|
||||
|
||||
force := cmd.Flag.Lookup("force").Value.Get().(bool)
|
||||
if !force {
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
snapshots := snapshotCollection.ByRemoteRepoSource(repo)
|
||||
|
||||
if len(snapshots) > 0 {
|
||||
fmt.Printf("Mirror `%s` was used to create following snapshots:\n", repo.Name)
|
||||
for _, snapshot := range snapshots {
|
||||
fmt.Printf(" * %s\n", snapshot)
|
||||
}
|
||||
|
||||
return fmt.Errorf("won't delete mirror with snapshots, use -force to override")
|
||||
}
|
||||
}
|
||||
|
||||
err = repoCollection.Drop(repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to drop: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Mirror `%s` has been removed.\n", repo.Name)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func makeCmdMirrorCreate() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyMirrorCreate,
|
||||
UsageLine: "create",
|
||||
UsageLine: "create <name> <archive url> <distribution> [<component1> ...]",
|
||||
Short: "create new mirror of Debian repository",
|
||||
Long: `
|
||||
create only stores metadata about new mirror, and fetches Release files (it doesn't download packages)
|
||||
Create records information about new mirror and fetches Release file (it doesn't download packages).
|
||||
|
||||
ex:
|
||||
$ aptly mirror create <name> <archive url> <distribution> [<component1> ...]
|
||||
$ aptly mirror create wheezy-main http://mirror.yandex.ru/debian/ wheezy main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-mirror-create", flag.ExitOnError),
|
||||
}
|
||||
cmd.Flag.String("architecture", "", "limit architectures to download, comma-delimited list")
|
||||
|
||||
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)")
|
||||
|
||||
return cmd
|
||||
|
||||
}
|
||||
|
||||
func makeCmdMirrorList() *commander.Command {
|
||||
@@ -166,7 +274,7 @@ func makeCmdMirrorList() *commander.Command {
|
||||
UsageLine: "list",
|
||||
Short: "list mirrors of remote repositories",
|
||||
Long: `
|
||||
list shows full list of remote repositories.
|
||||
List shows full list of remote repositories.
|
||||
|
||||
ex:
|
||||
$ aptly mirror list
|
||||
@@ -181,34 +289,60 @@ ex:
|
||||
func makeCmdMirrorShow() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyMirrorShow,
|
||||
UsageLine: "show",
|
||||
UsageLine: "show <name>",
|
||||
Short: "show details about remote repository mirror",
|
||||
Long: `
|
||||
show shows full information about mirror.
|
||||
Show shows full information about mirror.
|
||||
|
||||
ex:
|
||||
$ aptly mirror show <name>
|
||||
$ aptly mirror show wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-mirror-show", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("with-packages", false, "show list of packages")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdMirrorUpdate() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyMirrorUpdate,
|
||||
UsageLine: "update",
|
||||
UsageLine: "update <name>",
|
||||
Short: "update packages from remote mirror",
|
||||
Long: `
|
||||
Update downloads list of packages and packages themselves.
|
||||
Update downloads list of packages and package files.
|
||||
|
||||
ex:
|
||||
$ aptly mirror update <name>
|
||||
$ aptly mirror update wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-mirror-update", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("ignore-checksums", false, "ignore checksum mismatches while downloading package files and metadata")
|
||||
cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures")
|
||||
cmd.Flag.Var(&keyRings, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdMirrorDrop() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyMirrorDrop,
|
||||
UsageLine: "drop <name>",
|
||||
Short: "delete remote repository mirror",
|
||||
Long: `
|
||||
Drop deletes information about remote repository mirror. Package data is not deleted
|
||||
(it could be still used by other mirrors or snapshots).
|
||||
|
||||
ex:
|
||||
$ aptly mirror drop wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-mirror-drop", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("force", false, "force mirror deletion even if used by snapshots")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -220,7 +354,7 @@ func makeCmdMirror() *commander.Command {
|
||||
makeCmdMirrorCreate(),
|
||||
makeCmdMirrorList(),
|
||||
makeCmdMirrorShow(),
|
||||
//makeCmdMirrorDestroy(),
|
||||
makeCmdMirrorDrop(),
|
||||
makeCmdMirrorUpdate(),
|
||||
},
|
||||
Flag: *flag.NewFlagSet("aptly-mirror", flag.ExitOnError),
|
||||
|
||||
+155
-14
@@ -6,9 +6,31 @@ import (
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/smira/aptly/utils"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getSigner(cmd *commander.Command) (utils.Signer, error) {
|
||||
if cmd.Flag.Lookup("skip-signing").Value.Get().(bool) || utils.Config.GpgDisableSign {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
signer := &utils.GpgSigner{}
|
||||
|
||||
key := cmd.Flag.Lookup("gpg-key").Value.String()
|
||||
if key != "" {
|
||||
signer.SetKey(key)
|
||||
}
|
||||
|
||||
err := signer.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return signer, nil
|
||||
|
||||
}
|
||||
|
||||
func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) < 1 || len(args) > 2 {
|
||||
@@ -25,6 +47,8 @@ func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
|
||||
prefix = ""
|
||||
}
|
||||
|
||||
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
snapshot, err := snapshotCollection.ByName(name)
|
||||
if err != nil {
|
||||
@@ -57,26 +81,38 @@ func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
|
||||
if distribution == "" {
|
||||
if sourceRepo != nil {
|
||||
distribution = sourceRepo.Distribution
|
||||
} else {
|
||||
}
|
||||
|
||||
if distribution == "" {
|
||||
return fmt.Errorf("unable to guess distribution name, please specify explicitly")
|
||||
}
|
||||
}
|
||||
|
||||
var architecturesList []string
|
||||
architectures := cmd.Flag.Lookup("architectures").Value.String()
|
||||
if architectures != "" {
|
||||
architecturesList = strings.Split(architectures, ",")
|
||||
published, err := debian.NewPublishedRepo(prefix, distribution, component, context.architecturesList, snapshot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to publish: %s", err)
|
||||
}
|
||||
|
||||
signer := &utils.GpgSigner{}
|
||||
signer.SetKey(cmd.Flag.Lookup("gpg-key").Value.String())
|
||||
duplicate := publishedCollecton.CheckDuplicate(published)
|
||||
if duplicate != nil {
|
||||
publishedCollecton.LoadComplete(duplicate, snapshotCollection)
|
||||
return fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
|
||||
}
|
||||
|
||||
published := debian.NewPublishedRepo(prefix, distribution, component, architecturesList, snapshot)
|
||||
signer, err := getSigner(cmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initialize GPG signer: %s", err)
|
||||
}
|
||||
|
||||
packageCollection := debian.NewPackageCollection(context.database)
|
||||
err = published.Publish(context.packageRepository, packageCollection, signer)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("unable to publish: %s", err)
|
||||
}
|
||||
|
||||
err = publishedCollecton.Add(published)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to save to DB: %s", err)
|
||||
}
|
||||
|
||||
if prefix != "" && !strings.HasSuffix(prefix, "/") {
|
||||
@@ -88,6 +124,75 @@ func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
|
||||
fmt.Printf("Now you can add following line to apt sources:\n")
|
||||
fmt.Printf(" deb http://your-server/%s %s %s\n", prefix, distribution, component)
|
||||
fmt.Printf("Don't forget to add your GPG key to apt with apt-key.\n")
|
||||
fmt.Printf("\nYou can also use `aptly serve` to publish your repositories over HTTP quickly.\n")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func aptlyPublishList(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 0 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
if publishedCollecton.Len() == 0 {
|
||||
fmt.Printf("No snapshots have been published. Publish a snapshot by running `aptly publish snapshot ...`.\n")
|
||||
return err
|
||||
}
|
||||
|
||||
published := make(sort.StringSlice, 0, publishedCollecton.Len())
|
||||
|
||||
err = publishedCollecton.ForEach(func(repo *debian.PublishedRepo) error {
|
||||
err := publishedCollecton.LoadComplete(repo, snapshotCollection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
published = append(published, repo.String())
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load list of repos: %s", err)
|
||||
}
|
||||
|
||||
sort.Strings(published)
|
||||
|
||||
fmt.Printf("Published repositories:\n")
|
||||
|
||||
for _, description := range published {
|
||||
fmt.Printf(" * %s\n", description)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func aptlyPublishDrop(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]
|
||||
}
|
||||
|
||||
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
|
||||
|
||||
err = publishedCollecton.Remove(context.packageRepository, prefix, distribution)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to remove: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("\nPublished repositroy has been removed successfully.\n")
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -95,20 +200,54 @@ func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
|
||||
func makeCmdPublishSnapshot() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyPublishSnapshot,
|
||||
UsageLine: "snapshot",
|
||||
UsageLine: "snapshot <name> [<prefix>]",
|
||||
Short: "makes Debian repository out of snapshot",
|
||||
Long: `
|
||||
Publishes snapshot as Debian repository ready to be used by apt tools.
|
||||
Command publish oublishes snapshot as Debian repository ready to be used by apt tools.
|
||||
|
||||
ex:
|
||||
$ aptly publish snapshot <name> [<prefix>]
|
||||
ex.
|
||||
$ aptly publish snapshot wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-publish-snapshot", flag.ExitOnError),
|
||||
}
|
||||
cmd.Flag.String("distribution", "", "distribution name to publish")
|
||||
cmd.Flag.String("component", "", "component name to publish")
|
||||
cmd.Flag.String("architectures", "", "list of architectures to publish (comma-separated)")
|
||||
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
|
||||
cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdPublishDrop() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyPublishDrop,
|
||||
UsageLine: "drop <distribution> [<prefix>]",
|
||||
Short: "removes files of published repository",
|
||||
Long: `
|
||||
Command removes whatever has been published under specified prefix and distribution name.
|
||||
|
||||
ex.
|
||||
$ aptly publish drop wheezy
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-publish-drop", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdPublishList() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyPublishList,
|
||||
UsageLine: "list",
|
||||
Short: "displays list of published repositories",
|
||||
Long: `
|
||||
Display command displays list of currently published snapshots with information about published root.
|
||||
|
||||
ex.
|
||||
$ aptly publish list
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-publish-list", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
@@ -119,6 +258,8 @@ func makeCmdPublish() *commander.Command {
|
||||
Short: "manage published repositories",
|
||||
Subcommands: []*commander.Command{
|
||||
makeCmdPublishSnapshot(),
|
||||
makeCmdPublishList(),
|
||||
makeCmdPublishDrop(),
|
||||
},
|
||||
Flag: *flag.NewFlagSet("aptly-publish", flag.ExitOnError),
|
||||
}
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func aptlyServe(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
publishedCollection := debian.NewPublishedRepoCollection(context.database)
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
if publishedCollection.Len() == 0 {
|
||||
fmt.Printf("No published repositories, unable to serve.\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
listen := cmd.Flag.Lookup("listen").Value.String()
|
||||
|
||||
listenHost, listenPort, err := net.SplitHostPort(listen)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("wrong -listen specification: %s", err)
|
||||
}
|
||||
|
||||
if listenHost == "" {
|
||||
listenHost, err = os.Hostname()
|
||||
if err != nil {
|
||||
listenHost = "localhost"
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Serving published repositories, recommended apt sources list:\n\n")
|
||||
|
||||
sources := make(sort.StringSlice, 0, publishedCollection.Len())
|
||||
published := make(map[string]*debian.PublishedRepo, publishedCollection.Len())
|
||||
|
||||
err = publishedCollection.ForEach(func(repo *debian.PublishedRepo) error {
|
||||
err := publishedCollection.LoadComplete(repo, snapshotCollection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sources = append(sources, repo.String())
|
||||
published[repo.String()] = repo
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to serve: %s", err)
|
||||
}
|
||||
|
||||
sort.Strings(sources)
|
||||
|
||||
for _, source := range sources {
|
||||
repo := published[source]
|
||||
|
||||
prefix := repo.Prefix
|
||||
if prefix == "." {
|
||||
prefix = ""
|
||||
} else {
|
||||
prefix += "/"
|
||||
}
|
||||
|
||||
fmt.Printf("# %s\ndeb http://%s:%s/%s %s %s\n",
|
||||
repo, listenHost, listenPort, prefix, repo.Distribution, repo.Component)
|
||||
}
|
||||
|
||||
context.database.Close()
|
||||
|
||||
fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen)
|
||||
|
||||
err = http.ListenAndServe(listen, http.FileServer(http.Dir(context.packageRepository.PublicPath())))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to serve: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeCmdServe() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyServe,
|
||||
UsageLine: "serve",
|
||||
Short: "start embedded HTTP server to serve published repositories",
|
||||
Long: `
|
||||
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.
|
||||
|
||||
ex:
|
||||
$ aptly serve -listen=:8080
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-serve", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.String("listen", ":8080", "host:port for HTTP listening")
|
||||
|
||||
return cmd
|
||||
}
|
||||
+601
-45
@@ -5,34 +5,48 @@ import (
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/wsxiaoys/terminal/color"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func aptlySnapshotCreate(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
var (
|
||||
err error
|
||||
snapshot *debian.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
|
||||
repoName, snapshotName := args[3], args[0]
|
||||
|
||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
||||
repo, err := repoCollection.ByName(repoName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||
}
|
||||
|
||||
err = repoCollection.LoadComplete(repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||
}
|
||||
|
||||
snapshot, err = debian.NewSnapshotFromRepository(snapshotName, repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||
}
|
||||
} else if len(args) == 2 && args[1] == "empty" {
|
||||
// aptly snapshot create snap empty
|
||||
snapshotName := args[0]
|
||||
|
||||
packageList := debian.NewPackageList()
|
||||
|
||||
snapshot = debian.NewSnapshotFromPackageList(snapshotName, nil, packageList, "Created as empty")
|
||||
} else {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
repoName, mirrorName := args[3], args[0]
|
||||
|
||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
||||
repo, err := repoCollection.ByName(repoName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||
}
|
||||
|
||||
err = repoCollection.LoadComplete(repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||
}
|
||||
|
||||
snapshot, err := debian.NewSnapshotFromRepository(mirrorName, repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||
}
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
err = snapshotCollection.Add(snapshot)
|
||||
@@ -52,16 +66,31 @@ func aptlySnapshotList(cmd *commander.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("List of snapshots:\n")
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
|
||||
fmt.Printf(" * %s\n", snapshot)
|
||||
return nil
|
||||
})
|
||||
|
||||
fmt.Printf("\nTo get more information about snapshot, run `aptly snapshot show <name>`.\n")
|
||||
if snapshotCollection.Len() > 0 {
|
||||
fmt.Printf("List of snapshots:\n")
|
||||
|
||||
snapshots := make(sort.StringSlice, snapshotCollection.Len())
|
||||
|
||||
i := 0
|
||||
snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
|
||||
snapshots[i] = snapshot.String()
|
||||
i++
|
||||
return nil
|
||||
})
|
||||
|
||||
sort.Strings(snapshots)
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
func aptlySnapshotShow(cmd *commander.Command, args []string) error {
|
||||
@@ -88,35 +117,457 @@ func aptlySnapshotShow(cmd *commander.Command, args []string) error {
|
||||
fmt.Printf("Created At: %s\n", snapshot.CreatedAt.Format("2006-01-02 15:04:05 MST"))
|
||||
fmt.Printf("Description: %s\n", snapshot.Description)
|
||||
fmt.Printf("Number of packages: %d\n", snapshot.NumPackages())
|
||||
fmt.Printf("Packages:\n")
|
||||
|
||||
withPackages := cmd.Flag.Lookup("with-packages").Value.Get().(bool)
|
||||
if withPackages {
|
||||
ListPackagesRefList(snapshot.RefList())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func aptlySnapshotVerify(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) < 1 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
packageCollection := debian.NewPackageCollection(context.database)
|
||||
|
||||
err = snapshot.RefList().ForEach(func(key []byte) error {
|
||||
p, err := packageCollection.ByKey(key)
|
||||
snapshots := make([]*debian.Snapshot, len(args))
|
||||
for i := range snapshots {
|
||||
snapshots[i], err = snapshotCollection.ByName(args[i])
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("unable to verify: %s", err)
|
||||
}
|
||||
fmt.Printf(" %s\n", p)
|
||||
return nil
|
||||
})
|
||||
|
||||
err = snapshotCollection.LoadComplete(snapshots[i])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to verify: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
packageList, err := debian.NewPackageListFromRefList(snapshots[0].RefList(), packageCollection)
|
||||
if err != nil {
|
||||
fmt.Errorf("unable to load packages: %s", err)
|
||||
}
|
||||
|
||||
sourcePackageList := debian.NewPackageList()
|
||||
err = sourcePackageList.Append(packageList)
|
||||
if err != nil {
|
||||
fmt.Errorf("unable to merge sources: %s", err)
|
||||
}
|
||||
|
||||
for i := 1; i < len(snapshots); i++ {
|
||||
pL, err := debian.NewPackageListFromRefList(snapshots[i].RefList(), packageCollection)
|
||||
if err != nil {
|
||||
fmt.Errorf("unable to load packages: %s", err)
|
||||
}
|
||||
|
||||
err = sourcePackageList.Append(pL)
|
||||
if err != nil {
|
||||
fmt.Errorf("unable to merge sources: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
sourcePackageList.PrepareIndex()
|
||||
|
||||
var architecturesList []string
|
||||
|
||||
if len(context.architecturesList) > 0 {
|
||||
architecturesList = context.architecturesList
|
||||
} else {
|
||||
architecturesList = packageList.Architectures()
|
||||
}
|
||||
|
||||
if len(architecturesList) == 0 {
|
||||
return fmt.Errorf("unable to determine list of architectures, please specify explicitly")
|
||||
}
|
||||
|
||||
missing, err := packageList.VerifyDependencies(context.dependencyOptions, architecturesList, sourcePackageList)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to verify dependencies: %s", err)
|
||||
}
|
||||
|
||||
if len(missing) == 0 {
|
||||
fmt.Printf("All dependencies are satisfied.\n")
|
||||
} else {
|
||||
fmt.Printf("Missing dependencies (%d):\n", len(missing))
|
||||
deps := make(sort.StringSlice, len(missing))
|
||||
i := 0
|
||||
for _, dep := range missing {
|
||||
deps[i] = dep.String()
|
||||
i++
|
||||
}
|
||||
|
||||
sort.Strings(deps)
|
||||
|
||||
for _, dep := range deps {
|
||||
fmt.Printf(" %s\n", dep)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func aptlySnapshotPull(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) < 4 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
noDeps := cmd.Flag.Lookup("no-deps").Value.Get().(bool)
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
packageCollection := debian.NewPackageCollection(context.database)
|
||||
|
||||
// Load <name> snapshot
|
||||
snapshot, err := snapshotCollection.ByName(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to pull: %s", err)
|
||||
}
|
||||
|
||||
err = snapshotCollection.LoadComplete(snapshot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to pull: %s", err)
|
||||
}
|
||||
|
||||
// Load <source> snapshot
|
||||
source, err := snapshotCollection.ByName(args[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to pull: %s", err)
|
||||
}
|
||||
|
||||
err = snapshotCollection.LoadComplete(source)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to pull: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Dependencies would be pulled into snapshot:\n %s\nfrom snapshot:\n %s\nand result would be saved as new snapshot %s.\n",
|
||||
snapshot, source, args[2])
|
||||
|
||||
// Convert snapshot to package list
|
||||
fmt.Printf("Loading packages (%d)...\n", snapshot.RefList().Len()+source.RefList().Len())
|
||||
packageList, err := debian.NewPackageListFromRefList(snapshot.RefList(), packageCollection)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load packages: %s", err)
|
||||
}
|
||||
|
||||
sourcePackageList, err := debian.NewPackageListFromRefList(source.RefList(), packageCollection)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load packages: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Building indexes...\n")
|
||||
packageList.PrepareIndex()
|
||||
sourcePackageList.PrepareIndex()
|
||||
|
||||
// Calculate architectures
|
||||
var architecturesList []string
|
||||
|
||||
if len(context.architecturesList) > 0 {
|
||||
architecturesList = context.architecturesList
|
||||
} else {
|
||||
architecturesList = packageList.Architectures()
|
||||
}
|
||||
|
||||
if len(architecturesList) == 0 {
|
||||
return fmt.Errorf("unable to determine list of architectures, please specify explicitly")
|
||||
}
|
||||
|
||||
// Initial dependencies out of arguments
|
||||
initialDependencies := make([]debian.Dependency, len(args)-3)
|
||||
for i, arg := range args[3:] {
|
||||
initialDependencies[i], err = debian.ParseDependency(arg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to parse argument: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Perform pull
|
||||
for _, arch := range architecturesList {
|
||||
dependencies := make([]debian.Dependency, len(initialDependencies), 128)
|
||||
for i := range dependencies {
|
||||
dependencies[i] = initialDependencies[i]
|
||||
dependencies[i].Architecture = arch
|
||||
}
|
||||
|
||||
// Go over list of initial dependencies + list of dependencies found
|
||||
for i := 0; i < len(dependencies); i++ {
|
||||
dep := dependencies[i]
|
||||
|
||||
// Search for package that can satisfy dependencies
|
||||
pkg := sourcePackageList.Search(dep)
|
||||
if pkg == nil {
|
||||
color.Printf("@y[!]@| @!Dependency %s can't be satisfied with source %s@|", &dep, source)
|
||||
fmt.Printf("\n")
|
||||
continue
|
||||
}
|
||||
|
||||
// Remove all packages with the same name and architecture
|
||||
for p := packageList.Search(debian.Dependency{Architecture: arch, Pkg: pkg.Name}); p != nil; {
|
||||
packageList.Remove(p)
|
||||
color.Printf("@r[-]@| %s removed", p)
|
||||
fmt.Printf("\n")
|
||||
p = packageList.Search(debian.Dependency{Architecture: arch, Pkg: pkg.Name})
|
||||
}
|
||||
|
||||
// Add new discovered package
|
||||
packageList.Add(pkg)
|
||||
color.Printf("@g[+]@| %s added", pkg)
|
||||
fmt.Printf("\n")
|
||||
|
||||
if noDeps {
|
||||
continue
|
||||
}
|
||||
|
||||
// Find missing dependencies for single added package
|
||||
pL := debian.NewPackageList()
|
||||
pL.Add(pkg)
|
||||
|
||||
missing, err := pL.VerifyDependencies(context.dependencyOptions, []string{arch}, packageList)
|
||||
if err != nil {
|
||||
color.Printf("@y[!]@| @!Error while verifying dependencies for pkg %s: %s@|", pkg, err)
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
// Append missing dependencies to the list of dependencies to satisfy
|
||||
for _, misDep := range missing {
|
||||
found := false
|
||||
for _, d := range dependencies {
|
||||
if d == misDep {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
dependencies = append(dependencies, misDep)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cmd.Flag.Lookup("dry-run").Value.Get().(bool) {
|
||||
fmt.Printf("\nNot creating snapshot, as dry run was requested.\n")
|
||||
} else {
|
||||
// Create <destination> snapshot
|
||||
destination := debian.NewSnapshotFromPackageList(args[2], []*debian.Snapshot{snapshot, source}, packageList,
|
||||
fmt.Sprintf("Pulled into '%s' with '%s' as source, pull request was: '%s'", snapshot.Name, source.Name, strings.Join(args[3:], " ")))
|
||||
|
||||
err = snapshotCollection.Add(destination)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||
}
|
||||
|
||||
fmt.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
|
||||
}
|
||||
|
||||
func aptlySnapshotDiff(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 2 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
onlyMatching := cmd.Flag.Lookup("only-matching").Value.Get().(bool)
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
packageCollection := debian.NewPackageCollection(context.database)
|
||||
|
||||
// Load <name-a> snapshot
|
||||
snapshotA, err := snapshotCollection.ByName(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load snapshot A: %s", err)
|
||||
}
|
||||
|
||||
err = snapshotCollection.LoadComplete(snapshotA)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load snapshot A: %s", err)
|
||||
}
|
||||
|
||||
// Load <name-b> snapshot
|
||||
snapshotB, err := snapshotCollection.ByName(args[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load snapshot B: %s", err)
|
||||
}
|
||||
|
||||
err = snapshotCollection.LoadComplete(snapshotB)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load snapshot B: %s", err)
|
||||
}
|
||||
|
||||
// Calculate diff
|
||||
diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), packageCollection)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to calculate diff: %s", err)
|
||||
}
|
||||
|
||||
if len(diff) == 0 {
|
||||
fmt.Printf("Snapshots are identical.\n")
|
||||
} else {
|
||||
fmt.Printf(" Arch | Package | Version in A | Version in B\n")
|
||||
for _, pdiff := range diff {
|
||||
if onlyMatching && (pdiff.Left == nil || pdiff.Right == nil) {
|
||||
continue
|
||||
}
|
||||
|
||||
var verA, verB, pkg, arch, code string
|
||||
|
||||
if pdiff.Left == nil {
|
||||
verA = "-"
|
||||
verB = pdiff.Right.Version
|
||||
pkg = pdiff.Right.Name
|
||||
arch = pdiff.Right.Architecture
|
||||
} else {
|
||||
pkg = pdiff.Left.Name
|
||||
arch = pdiff.Left.Architecture
|
||||
verA = pdiff.Left.Version
|
||||
if pdiff.Right == nil {
|
||||
verB = "-"
|
||||
} else {
|
||||
verB = pdiff.Right.Version
|
||||
}
|
||||
}
|
||||
|
||||
if pdiff.Left == nil {
|
||||
code = "@g+@|"
|
||||
} else {
|
||||
if pdiff.Right == nil {
|
||||
code = "@r-@|"
|
||||
} else {
|
||||
code = "@y!@|"
|
||||
}
|
||||
}
|
||||
|
||||
color.Printf(code+" %-6s | %-40s | %-40s | %-40s\n", arch, pkg, verA, verB)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func aptlySnapshotMerge(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) < 2 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
sources := make([]*debian.Snapshot, len(args)-1)
|
||||
|
||||
for i := 0; i < len(args)-1; i++ {
|
||||
sources[i], err = snapshotCollection.ByName(args[i+1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load snapshot: %s", err)
|
||||
}
|
||||
|
||||
err = snapshotCollection.LoadComplete(sources[i])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load snapshot: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
result := sources[0].RefList()
|
||||
|
||||
for i := 1; i < len(sources); i++ {
|
||||
result = result.Merge(sources[i].RefList())
|
||||
}
|
||||
|
||||
sourceDescription := make([]string, len(sources))
|
||||
for i, s := range sources {
|
||||
sourceDescription[i] = fmt.Sprintf("'%s'", s.Name)
|
||||
}
|
||||
|
||||
// Create <destination> snapshot
|
||||
destination := debian.NewSnapshotFromRefList(args[0], sources, result,
|
||||
fmt.Sprintf("Merged from sources: %s", strings.Join(sourceDescription, ", ")))
|
||||
|
||||
err = snapshotCollection.Add(destination)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create snapshot: %s", err)
|
||||
}
|
||||
|
||||
fmt.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
|
||||
}
|
||||
|
||||
func aptlySnapshotDrop(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 1 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
name := args[0]
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
snapshot, err := snapshotCollection.ByName(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to drop: %s", err)
|
||||
}
|
||||
|
||||
publishedRepoCollection := debian.NewPublishedRepoCollection(context.database)
|
||||
published := publishedRepoCollection.BySnapshot(snapshot)
|
||||
|
||||
if len(published) > 0 {
|
||||
fmt.Printf("Snapshot `%s` is published currently:\n", snapshot.Name)
|
||||
for _, repo := range published {
|
||||
err = publishedRepoCollection.LoadComplete(repo, snapshotCollection)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load published: %s", err)
|
||||
}
|
||||
fmt.Printf(" * %s\n", repo)
|
||||
}
|
||||
|
||||
return fmt.Errorf("unable to drop: snapshot is published")
|
||||
}
|
||||
|
||||
force := cmd.Flag.Lookup("force").Value.Get().(bool)
|
||||
if !force {
|
||||
snapshots := snapshotCollection.BySnapshotSource(snapshot)
|
||||
if len(snapshots) > 0 {
|
||||
fmt.Printf("Snapshot `%s` was used as a source in following snapshots:\n", snapshot.Name)
|
||||
for _, snap := range snapshots {
|
||||
fmt.Printf(" * %s\n", snap)
|
||||
}
|
||||
|
||||
return fmt.Errorf("won't delete snapshot that was used as source for other snapshots, use -force to override")
|
||||
}
|
||||
}
|
||||
|
||||
err = snapshotCollection.Drop(snapshot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to drop: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Snapshot `%s` has been dropped.\n", snapshot.Name)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func makeCmdSnapshotCreate() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotCreate,
|
||||
UsageLine: "create",
|
||||
Short: "creates snapshot out of any mirror",
|
||||
UsageLine: "create <name> from mirror <mirror-name> | create <name> empty",
|
||||
Short: "creates immutable snapshot of mirror contents",
|
||||
Long: `
|
||||
Create makes persistent immutable snapshot of repository mirror state in givent moment of time.
|
||||
Command create .. from mirror makes persistent immutable snapshot of remote repository mirror. Snapshot could be
|
||||
published or further modified using merge, pull and other aptly features.
|
||||
|
||||
ex:
|
||||
$ aptly snapshot create <name> from mirror <mirror-name>
|
||||
Command create .. empty creates empty snapshot that could be used as a basis for snapshot pull operations, for example.
|
||||
As snapshots are immutable, creating one empty snapshot should be enough.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot create wheezy-main-today from mirror wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-create", flag.ExitOnError),
|
||||
}
|
||||
@@ -131,7 +582,7 @@ func makeCmdSnapshotList() *commander.Command {
|
||||
UsageLine: "list",
|
||||
Short: "lists snapshots",
|
||||
Long: `
|
||||
list shows full list of snapshots created.
|
||||
Command list shows full list of snapshots created.
|
||||
|
||||
ex:
|
||||
$ aptly snapshot list
|
||||
@@ -145,17 +596,118 @@ ex:
|
||||
func makeCmdSnapshotShow() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotShow,
|
||||
UsageLine: "show",
|
||||
UsageLine: "show <name>",
|
||||
Short: "shows details about snapshot",
|
||||
Long: `
|
||||
shows shows full information about snapshot.
|
||||
Command show displays full information about snapshot.
|
||||
|
||||
ex:
|
||||
$ aptly snapshot show <name>
|
||||
ex.
|
||||
$ aptly snapshot show wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-show", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("with-packages", false, "show list of packages")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotVerify() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotVerify,
|
||||
UsageLine: "verify <name> [<source> ...]",
|
||||
Short: "verifies that dependencies are satisfied in snapshot",
|
||||
Long: `
|
||||
Verify does depenency resolution in snapshot, possibly using additional snapshots as dependency sources.
|
||||
All unsatisfied dependencies are returned.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot verify wheezy-main wheezy-contrib wheezy-non-free
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-verify", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotPull() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotPull,
|
||||
UsageLine: "pull <name> <source> <destination> <package-name> ...",
|
||||
Short: "performs partial upgrades (pulls new packages) from another snapshot",
|
||||
Long: `
|
||||
Command pull pulls new packages along with its dependencies in <name> snapshot
|
||||
from <source> snapshot. Also can upgrade package version from one snapshot into
|
||||
another, once again along with dependencies. New snapshot <destination> is created as result of this
|
||||
process. Packages could be specified simply as 'package-name' or as dependency 'package-name (>= version)'.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot pull wheezy-main wheezy-backports wheezy-new-xorg xorg-server-server
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-pull", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("dry-run", false, "don't create destination snapshot, just show what would be pulled")
|
||||
cmd.Flag.Bool("no-deps", false, "don't process dependencies, just pull listed packages")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotDiff() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotDiff,
|
||||
UsageLine: "diff <name-a> <name-b>",
|
||||
Short: "calculates difference in packages between two snapshots",
|
||||
Long: `
|
||||
Command diff shows list of missing and new packages, difference in package versions between two snapshots.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot diff -only-matching wheezy-main wheezy-backports
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-diff", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("only-matching", false, "display diff only for matching packages (don't display missing packages)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotMerge() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotMerge,
|
||||
UsageLine: "merge <destination> <source> [<source>...]",
|
||||
Short: "merges snapshots into one, replacing matching packages",
|
||||
Long: `
|
||||
Merge merges several snapshots into one. Merge happens from left to right. Packages with the same
|
||||
name-architecture pair are replaced during merge (package from latest snapshot on the list wins).
|
||||
If run with only one source snapshot, merge copies source into destination.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot merge wheezy-w-backports wheezy-main wheezy-backports
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-merge", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotDrop() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotDrop,
|
||||
UsageLine: "drop <name>",
|
||||
Short: "delete snapshot",
|
||||
Long: `
|
||||
Drop removes information about snapshot. If snapshot is published,
|
||||
it can't be dropped.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot drop wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-drop", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("force", false, "remove snapshot even if it was used as source for other snapshots")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -167,7 +719,11 @@ func makeCmdSnapshot() *commander.Command {
|
||||
makeCmdSnapshotCreate(),
|
||||
makeCmdSnapshotList(),
|
||||
makeCmdSnapshotShow(),
|
||||
//makeCmdSnapshotDestroy(),
|
||||
makeCmdSnapshotVerify(),
|
||||
makeCmdSnapshotPull(),
|
||||
makeCmdSnapshotDiff(),
|
||||
makeCmdSnapshotMerge(),
|
||||
makeCmdSnapshotDrop(),
|
||||
},
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot", flag.ExitOnError),
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/smira/aptly/debian"
|
||||
)
|
||||
|
||||
//ListPackagesRefList shows list of packages in PackageRefList
|
||||
func ListPackagesRefList(reflist *debian.PackageRefList) (err error) {
|
||||
fmt.Printf("Packages:\n")
|
||||
|
||||
packageCollection := debian.NewPackageCollection(context.database)
|
||||
|
||||
err = reflist.ForEach(func(key []byte) error {
|
||||
p, err := packageCollection.ByKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf(" %s\n", p)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load packages: %s", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -18,6 +18,7 @@ var (
|
||||
type Storage interface {
|
||||
Get(key []byte) ([]byte, error)
|
||||
Put(key []byte, value []byte) error
|
||||
Delete(key []byte) error
|
||||
FetchByPrefix(prefix []byte) [][]byte
|
||||
Close() error
|
||||
}
|
||||
@@ -60,6 +61,10 @@ func (l *levelDB) Put(key []byte, value []byte) error {
|
||||
return l.db.Put(key, value, nil)
|
||||
}
|
||||
|
||||
func (l *levelDB) Delete(key []byte) error {
|
||||
return l.db.Delete(key, nil)
|
||||
}
|
||||
|
||||
func (l *levelDB) FetchByPrefix(prefix []byte) [][]byte {
|
||||
result := make([][]byte, 0, 20)
|
||||
|
||||
|
||||
@@ -45,6 +45,25 @@ func (s *LevelDBSuite) TestGetPut(c *C) {
|
||||
c.Assert(result, DeepEquals, value)
|
||||
}
|
||||
|
||||
func (s *LevelDBSuite) TestDelete(c *C) {
|
||||
var (
|
||||
key = []byte("key")
|
||||
value = []byte("value")
|
||||
)
|
||||
|
||||
err := s.db.Put(key, value)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.db.Delete(key)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
_, err = s.db.Get(key)
|
||||
c.Assert(err, ErrorMatches, "key not found")
|
||||
|
||||
err = s.db.Delete(key)
|
||||
c.Assert(err, IsNil)
|
||||
}
|
||||
|
||||
func (s *LevelDBSuite) TestFetchByPrefix(c *C) {
|
||||
c.Check(s.db.FetchByPrefix([]byte{0x80}), DeepEquals, [][]byte{})
|
||||
|
||||
|
||||
Vendored
+2
-1
@@ -11,7 +11,8 @@ import (
|
||||
type Stanza map[string]string
|
||||
|
||||
// Canonical order of fields in stanza
|
||||
var canocialOrder = []string{"Package", "Version", "Installed-Size", "Priority", "Section", "Maintainer", "Architecture"}
|
||||
var canocialOrder = []string{"Origin", "Label", "Suite", "Package", "Version", "Installed-Size", "Priority", "Section", "Maintainer",
|
||||
"Architecture", "Codename", "Date", "Architectures", "Components", "Description", "MD5sum", "MD5Sum", "SHA1", "SHA256"}
|
||||
|
||||
// Copy returns copy of Stanza
|
||||
func (s Stanza) Copy() (result Stanza) {
|
||||
|
||||
Vendored
+458
-1
@@ -3,23 +3,69 @@ package debian
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/smira/aptly/utils"
|
||||
"github.com/ugorji/go/codec"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Dependency options
|
||||
const (
|
||||
// DepFollowSource pulls source packages when required
|
||||
DepFollowSource = 1 << iota
|
||||
// DepFollowSuggests pulls from suggests
|
||||
DepFollowSuggests
|
||||
// DepFollowRecommends pulls from recommends
|
||||
DepFollowRecommends
|
||||
// DepFollowAllVariants follows all variants if depends on "a | b"
|
||||
DepFollowAllVariants
|
||||
)
|
||||
|
||||
// PackageList is list of unique (by key) packages
|
||||
//
|
||||
// It could be seen as repo snapshot, repo contents, result of filtering,
|
||||
// merge, etc.
|
||||
//
|
||||
// If indexed, PackageList starts supporting searching
|
||||
type PackageList struct {
|
||||
// Straight list of packages as map
|
||||
packages map[string]*Package
|
||||
// Has index been prepared?
|
||||
indexed bool
|
||||
// Indexed list of packages, sorted by name internally
|
||||
packagesIndex []*Package
|
||||
// Map of packages for each virtual package (provides)
|
||||
providesIndex map[string][]*Package
|
||||
}
|
||||
|
||||
// Verify interface
|
||||
var (
|
||||
_ sort.Interface = &PackageList{}
|
||||
)
|
||||
|
||||
// NewPackageList creates empty package list
|
||||
func NewPackageList() *PackageList {
|
||||
return &PackageList{packages: make(map[string]*Package, 1000)}
|
||||
}
|
||||
|
||||
// NewPackageListFromRefList loads packages list from PackageRefList
|
||||
func NewPackageListFromRefList(reflist *PackageRefList, collection *PackageCollection) (*PackageList, error) {
|
||||
result := &PackageList{packages: make(map[string]*Package, reflist.Len())}
|
||||
|
||||
err := reflist.ForEach(func(key []byte) error {
|
||||
p, err := collection.ByKey(key)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load package with key %s: %s", key, err)
|
||||
}
|
||||
return result.Add(p)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Add appends package to package list, additionally checking for uniqueness
|
||||
func (l *PackageList) Add(p *Package) error {
|
||||
key := string(p.Key())
|
||||
@@ -31,6 +77,19 @@ func (l *PackageList) Add(p *Package) error {
|
||||
return nil
|
||||
}
|
||||
l.packages[key] = p
|
||||
|
||||
if l.indexed {
|
||||
for _, provides := range p.Provides {
|
||||
l.providesIndex[provides] = append(l.providesIndex[provides], p)
|
||||
}
|
||||
|
||||
i := sort.Search(len(l.packagesIndex), func(j int) bool { return l.packagesIndex[j].Name >= p.Name })
|
||||
|
||||
// insert p into l.packagesIndex in position i
|
||||
l.packagesIndex = append(l.packagesIndex, nil)
|
||||
copy(l.packagesIndex[i+1:], l.packagesIndex[i:])
|
||||
l.packagesIndex[i] = p
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -51,15 +110,253 @@ func (l *PackageList) Len() int {
|
||||
return len(l.packages)
|
||||
}
|
||||
|
||||
// Append adds content from one package list to another
|
||||
func (l *PackageList) Append(pl *PackageList) error {
|
||||
if l.indexed {
|
||||
panic("Append not supported when indexed")
|
||||
}
|
||||
for k, p := range pl.packages {
|
||||
existing, ok := l.packages[k]
|
||||
if ok {
|
||||
if !existing.Equals(p) {
|
||||
return fmt.Errorf("conflict in package %s: %#v != %#v", p, existing, p)
|
||||
}
|
||||
} else {
|
||||
l.packages[k] = p
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes package from the list, and updates index when required
|
||||
func (l *PackageList) Remove(p *Package) {
|
||||
delete(l.packages, string(p.Key()))
|
||||
if l.indexed {
|
||||
for _, provides := range p.Provides {
|
||||
for i, pkg := range l.providesIndex[provides] {
|
||||
if pkg.Equals(p) {
|
||||
// remove l.ProvidesIndex[provides][i] w/o preserving order
|
||||
l.providesIndex[provides][len(l.providesIndex[provides])-1], l.providesIndex[provides][i], l.providesIndex[provides] =
|
||||
nil, l.providesIndex[provides][len(l.providesIndex[provides])-1], l.providesIndex[provides][:len(l.providesIndex[provides])-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i := sort.Search(len(l.packagesIndex), func(j int) bool { return l.packagesIndex[j].Name >= p.Name })
|
||||
for i < len(l.packagesIndex) && l.packagesIndex[i].Name == p.Name {
|
||||
if l.packagesIndex[i].Equals(p) {
|
||||
// remove l.packagesIndex[i] preserving order
|
||||
copy(l.packagesIndex[i:], l.packagesIndex[i+1:])
|
||||
l.packagesIndex[len(l.packagesIndex)-1] = nil
|
||||
l.packagesIndex = l.packagesIndex[:len(l.packagesIndex)-1]
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Architectures returns list of architectures present in packages
|
||||
func (l *PackageList) Architectures() (result []string) {
|
||||
result = make([]string, 0, 10)
|
||||
for _, pkg := range l.packages {
|
||||
if pkg.Architecture != "all" && !utils.StrSliceHasItem(result, pkg.Architecture) {
|
||||
result = append(result, pkg.Architecture)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// depSliceDeduplicate removes dups in slice of Dependencies
|
||||
func depSliceDeduplicate(s []Dependency) []Dependency {
|
||||
l := len(s)
|
||||
if l < 2 {
|
||||
return s
|
||||
}
|
||||
if l == 2 {
|
||||
if s[0] == s[1] {
|
||||
return s[0:1]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
found := make(map[string]bool, l)
|
||||
j := 0
|
||||
for i, x := range s {
|
||||
h := x.Hash()
|
||||
if !found[h] {
|
||||
found[h] = true
|
||||
s[j] = s[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
|
||||
return s[:j]
|
||||
}
|
||||
|
||||
// VerifyDependencies looks for missing dependencies in package list.
|
||||
//
|
||||
// Analysis would be peformed for each architecture, in specified sources
|
||||
func (l *PackageList) VerifyDependencies(options int, architectures []string, sources *PackageList) ([]Dependency, error) {
|
||||
missing := make([]Dependency, 0, 128)
|
||||
|
||||
for _, arch := range architectures {
|
||||
cache := make(map[string]bool, 2048)
|
||||
|
||||
for _, p := range l.packages {
|
||||
if !p.MatchesArchitecture(arch) {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, dep := range p.GetDependencies(options) {
|
||||
variants, err := ParseDependencyVariants(dep)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to process package %s: %s", p, err)
|
||||
}
|
||||
|
||||
variants = depSliceDeduplicate(variants)
|
||||
|
||||
variantsMissing := make([]Dependency, 0, len(variants))
|
||||
missingCount := 0
|
||||
|
||||
for _, dep := range variants {
|
||||
dep.Architecture = arch
|
||||
|
||||
hash := dep.Hash()
|
||||
r, ok := cache[hash]
|
||||
if ok {
|
||||
if !r {
|
||||
missingCount++
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if sources.Search(dep) == nil {
|
||||
variantsMissing = append(variantsMissing, dep)
|
||||
missingCount++
|
||||
} else {
|
||||
cache[hash] = true
|
||||
}
|
||||
}
|
||||
|
||||
if options&DepFollowAllVariants == DepFollowAllVariants {
|
||||
missing = append(missing, variantsMissing...)
|
||||
for _, dep := range variantsMissing {
|
||||
cache[dep.Hash()] = false
|
||||
}
|
||||
} else {
|
||||
if missingCount == len(variants) {
|
||||
missing = append(missing, variantsMissing...)
|
||||
for _, dep := range variantsMissing {
|
||||
cache[dep.Hash()] = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return missing, nil
|
||||
}
|
||||
|
||||
// Swap swaps two packages in index
|
||||
func (l *PackageList) Swap(i, j int) {
|
||||
l.packagesIndex[i], l.packagesIndex[j] = l.packagesIndex[j], l.packagesIndex[i]
|
||||
}
|
||||
|
||||
// Compare compares two names in lexographical order
|
||||
func (l *PackageList) Less(i, j int) bool {
|
||||
return l.packagesIndex[i].Name < l.packagesIndex[j].Name
|
||||
}
|
||||
|
||||
// PrepareIndex prepares list for indexing
|
||||
func (l *PackageList) PrepareIndex() {
|
||||
l.packagesIndex = make([]*Package, l.Len())
|
||||
l.providesIndex = make(map[string][]*Package, 128)
|
||||
|
||||
i := 0
|
||||
for _, p := range l.packages {
|
||||
l.packagesIndex[i] = p
|
||||
i++
|
||||
|
||||
for _, provides := range p.Provides {
|
||||
l.providesIndex[provides] = append(l.providesIndex[provides], p)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(l)
|
||||
|
||||
l.indexed = true
|
||||
}
|
||||
|
||||
// Search searches package index for specified package
|
||||
func (l *PackageList) Search(dep Dependency) *Package {
|
||||
if !l.indexed {
|
||||
panic("list not indexed, can't search")
|
||||
}
|
||||
|
||||
if dep.Relation == VersionDontCare {
|
||||
for _, p := range l.providesIndex[dep.Pkg] {
|
||||
if p.MatchesArchitecture(dep.Architecture) {
|
||||
return p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i := sort.Search(len(l.packagesIndex), func(j int) bool { return l.packagesIndex[j].Name >= dep.Pkg })
|
||||
|
||||
for i < len(l.packagesIndex) && l.packagesIndex[i].Name == dep.Pkg {
|
||||
p := l.packagesIndex[i]
|
||||
if p.MatchesArchitecture(dep.Architecture) {
|
||||
if dep.Relation == VersionDontCare {
|
||||
return p
|
||||
}
|
||||
|
||||
r := CompareVersions(p.Version, dep.Version)
|
||||
switch dep.Relation {
|
||||
case VersionEqual:
|
||||
if r == 0 {
|
||||
return p
|
||||
}
|
||||
case VersionLess:
|
||||
if r < 0 {
|
||||
return p
|
||||
}
|
||||
case VersionGreater:
|
||||
if r > 0 {
|
||||
return p
|
||||
}
|
||||
case VersionLessOrEqual:
|
||||
if r <= 0 {
|
||||
return p
|
||||
}
|
||||
case VersionGreaterOrEqual:
|
||||
if r >= 0 {
|
||||
return p
|
||||
}
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PackageRefList is a list of keys of packages, this is basis for snapshot
|
||||
// and similar stuff
|
||||
//
|
||||
// Refs are sorted in lexographical order
|
||||
// Refs are sorted in lexicographical order
|
||||
type PackageRefList struct {
|
||||
// List of package keys
|
||||
Refs [][]byte
|
||||
}
|
||||
|
||||
// Verify interface
|
||||
var (
|
||||
_ sort.Interface = &PackageRefList{}
|
||||
)
|
||||
|
||||
// NewPackageRefListFromPackageList creates PackageRefList from PackageList
|
||||
func NewPackageRefListFromPackageList(list *PackageList) *PackageRefList {
|
||||
reflist := &PackageRefList{}
|
||||
@@ -118,3 +415,163 @@ func (l *PackageRefList) ForEach(handler func([]byte) error) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// PackageDiff is a difference between two packages in a list.
|
||||
//
|
||||
// If left & right are present, difference is in package version
|
||||
// If left is nil, package is present only in right
|
||||
// If right is nil, package is present only in left
|
||||
type PackageDiff struct {
|
||||
Left, Right *Package
|
||||
}
|
||||
|
||||
// PackageDiffs is a list of PackageDiff records
|
||||
type PackageDiffs []PackageDiff
|
||||
|
||||
// Diff calculates difference between two reflists
|
||||
func (l *PackageRefList) Diff(r *PackageRefList, packageCollection *PackageCollection) (result PackageDiffs, err error) {
|
||||
result = make(PackageDiffs, 0, 128)
|
||||
|
||||
// pointer to left and right reflists
|
||||
il, ir := 0, 0
|
||||
// length of reflists
|
||||
ll, lr := l.Len(), r.Len()
|
||||
// cached loaded packages on the left & right
|
||||
pl, pr := (*Package)(nil), (*Package)(nil)
|
||||
|
||||
// until we reached end of both lists
|
||||
for il < ll || ir < lr {
|
||||
// if we've exhausted left list, pull the rest from the right
|
||||
if il == ll {
|
||||
pr, err = packageCollection.ByKey(r.Refs[ir])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, PackageDiff{Left: nil, Right: pr})
|
||||
ir++
|
||||
continue
|
||||
}
|
||||
// if we've exhausted right list, pull the rest from the left
|
||||
if ir == lr {
|
||||
pl, err = packageCollection.ByKey(l.Refs[il])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, PackageDiff{Left: pl, Right: nil})
|
||||
il++
|
||||
continue
|
||||
}
|
||||
|
||||
// refs on both sides are present, load them
|
||||
rl, rr := l.Refs[il], r.Refs[ir]
|
||||
// compare refs
|
||||
rel := bytes.Compare(rl, rr)
|
||||
|
||||
if rel == 0 {
|
||||
// refs are identical, so are packages, advance pointer
|
||||
il++
|
||||
ir++
|
||||
pl, pr = nil, nil
|
||||
} else {
|
||||
// load pl & pr if they haven't been loaded before
|
||||
if pl == nil {
|
||||
pl, err = packageCollection.ByKey(rl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if pr == nil {
|
||||
pr, err = packageCollection.ByKey(rr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// is pl & pr the same package, but different version?
|
||||
if pl.Name == pr.Name && pl.Architecture == pr.Architecture {
|
||||
result = append(result, PackageDiff{Left: pl, Right: pr})
|
||||
il++
|
||||
ir++
|
||||
pl, pr = nil, nil
|
||||
} else {
|
||||
// otherwise pl or pr is missing on one of the sides
|
||||
if rel < 0 {
|
||||
result = append(result, PackageDiff{Left: pl, Right: nil})
|
||||
il++
|
||||
pl = nil
|
||||
} else {
|
||||
result = append(result, PackageDiff{Left: nil, Right: pr})
|
||||
ir++
|
||||
pr = nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Merge merges reflist r into current reflist. Merge replaces matching packages (by architecture/name)
|
||||
// with reference from r.
|
||||
func (l *PackageRefList) Merge(r *PackageRefList) (result *PackageRefList) {
|
||||
// pointer to left and right reflists
|
||||
il, ir := 0, 0
|
||||
// length of reflists
|
||||
ll, lr := l.Len(), r.Len()
|
||||
|
||||
result = &PackageRefList{}
|
||||
result.Refs = make([][]byte, 0, ll+lr)
|
||||
|
||||
// until we reached end of both lists
|
||||
for il < ll || ir < lr {
|
||||
// if we've exhausted left list, pull the rest from the right
|
||||
if il == ll {
|
||||
result.Refs = append(result.Refs, r.Refs[ir:]...)
|
||||
break
|
||||
}
|
||||
// if we've exhausted right list, pull the rest from the left
|
||||
if ir == lr {
|
||||
result.Refs = append(result.Refs, l.Refs[il:]...)
|
||||
break
|
||||
}
|
||||
|
||||
// refs on both sides are present, load them
|
||||
rl, rr := l.Refs[il], r.Refs[ir]
|
||||
// compare refs
|
||||
rel := bytes.Compare(rl, rr)
|
||||
|
||||
if rel == 0 {
|
||||
// refs are identical, so are packages, advance pointer
|
||||
result.Refs = append(result.Refs, l.Refs[il])
|
||||
il++
|
||||
ir++
|
||||
} else {
|
||||
partsL := bytes.Split(rl, []byte(" "))
|
||||
archL, nameL := partsL[0][1:], partsL[1]
|
||||
|
||||
partsR := bytes.Split(rr, []byte(" "))
|
||||
archR, nameR := partsR[0][1:], partsR[1]
|
||||
|
||||
if bytes.Compare(archL, archR) == 0 && bytes.Compare(nameL, nameR) == 0 {
|
||||
// override with package from the right
|
||||
result.Refs = append(result.Refs, r.Refs[ir])
|
||||
il++
|
||||
ir++
|
||||
} else {
|
||||
// otherwise append smallest of two
|
||||
if rel < 0 {
|
||||
result.Refs = append(result.Refs, l.Refs[il])
|
||||
il++
|
||||
} else {
|
||||
result.Refs = append(result.Refs, r.Refs[ir])
|
||||
ir++
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
Vendored
+328
@@ -2,12 +2,19 @@ package debian
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/smira/aptly/database"
|
||||
. "launchpad.net/gocheck"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type PackageListSuite struct {
|
||||
// Simple list with "real" packages from stanzas
|
||||
list *PackageList
|
||||
p1, p2, p3, p4, p5, p6 *Package
|
||||
|
||||
// Mocked packages in list
|
||||
packages []*Package
|
||||
il *PackageList
|
||||
}
|
||||
|
||||
var _ = Suite(&PackageListSuite{})
|
||||
@@ -29,6 +36,27 @@ func (s *PackageListSuite) SetUpTest(c *C) {
|
||||
stanza = packageStanza.Copy()
|
||||
stanza["Version"] = "99.1"
|
||||
s.p6 = NewPackageFromControlFile(stanza)
|
||||
|
||||
s.il = NewPackageList()
|
||||
s.packages = []*Package{
|
||||
&Package{Name: "lib", Version: "1.0", Architecture: "i386", PreDepends: []string{"dpkg (>= 1.6)"}, Depends: []string{"mail-agent"}},
|
||||
&Package{Name: "dpkg", Version: "1.7", Architecture: "i386", Provides: []string{"package-installer"}},
|
||||
&Package{Name: "data", Version: "1.1~bp1", Architecture: "all", PreDepends: []string{"dpkg (>= 1.6)"}},
|
||||
&Package{Name: "app", Version: "1.1~bp1", Architecture: "i386", PreDepends: []string{"dpkg (>= 1.6)"}, Depends: []string{"lib (>> 0.9)", "data (>= 1.0)"}},
|
||||
&Package{Name: "mailer", Version: "3.5.8", Architecture: "i386", Provides: []string{"mail-agent"}},
|
||||
&Package{Name: "app", Version: "1.1~bp1", Architecture: "amd64", PreDepends: []string{"dpkg (>= 1.6)"}, Depends: []string{"lib (>> 0.9)", "data (>= 1.0)"}},
|
||||
&Package{Name: "app", Version: "1.1~bp1", Architecture: "arm", PreDepends: []string{"dpkg (>= 1.6)"}, Depends: []string{"lib (>> 0.9) | libx (>= 1.5)", "data (>= 1.0) | mail-agent"}},
|
||||
&Package{Name: "app", Version: "1.0", Architecture: "s390", PreDepends: []string{"dpkg >= 1.6)"}, Depends: []string{"lib (>> 0.9)", "data (>= 1.0)"}},
|
||||
&Package{Name: "aa", Version: "2.0-1", Architecture: "i386", PreDepends: []string{"dpkg (>= 1.6)"}},
|
||||
&Package{Name: "dpkg", Version: "1.6.1-3", Architecture: "amd64", Provides: []string{"package-installer"}},
|
||||
&Package{Name: "libx", Version: "1.5", Architecture: "arm", PreDepends: []string{"dpkg (>= 1.6)"}},
|
||||
&Package{Name: "dpkg", Version: "1.6.1-3", Architecture: "arm", Provides: []string{"package-installer"}},
|
||||
}
|
||||
for _, p := range s.packages {
|
||||
s.il.Add(p)
|
||||
}
|
||||
s.il.PrepareIndex()
|
||||
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestAddLen(c *C) {
|
||||
@@ -42,6 +70,73 @@ func (s *PackageListSuite) TestAddLen(c *C) {
|
||||
c.Check(s.list.Add(s.p4), ErrorMatches, "conflict in package.*")
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestRemove(c *C) {
|
||||
c.Check(s.list.Add(s.p1), IsNil)
|
||||
c.Check(s.list.Add(s.p3), IsNil)
|
||||
c.Check(s.list.Len(), Equals, 2)
|
||||
|
||||
s.list.Remove(s.p1)
|
||||
c.Check(s.list.Len(), Equals, 1)
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestAddWhenIndexed(c *C) {
|
||||
c.Check(s.list.Len(), Equals, 0)
|
||||
s.list.PrepareIndex()
|
||||
|
||||
c.Check(s.list.Add(&Package{Name: "a1st", Version: "1.0", Architecture: "i386", Provides: []string{"fa", "fb"}}), IsNil)
|
||||
c.Check(s.list.packagesIndex[0].Name, Equals, "a1st")
|
||||
c.Check(s.list.providesIndex["fa"][0].Name, Equals, "a1st")
|
||||
c.Check(s.list.providesIndex["fb"][0].Name, Equals, "a1st")
|
||||
|
||||
c.Check(s.list.Add(&Package{Name: "c3rd", Version: "1.0", Architecture: "i386", Provides: []string{"fa"}}), IsNil)
|
||||
c.Check(s.list.packagesIndex[0].Name, Equals, "a1st")
|
||||
c.Check(s.list.packagesIndex[1].Name, Equals, "c3rd")
|
||||
c.Check(s.list.providesIndex["fa"][0].Name, Equals, "a1st")
|
||||
c.Check(s.list.providesIndex["fa"][1].Name, Equals, "c3rd")
|
||||
c.Check(s.list.providesIndex["fb"][0].Name, Equals, "a1st")
|
||||
|
||||
c.Check(s.list.Add(&Package{Name: "b2nd", Version: "1.0", Architecture: "i386"}), IsNil)
|
||||
c.Check(s.list.packagesIndex[0].Name, Equals, "a1st")
|
||||
c.Check(s.list.packagesIndex[1].Name, Equals, "b2nd")
|
||||
c.Check(s.list.packagesIndex[2].Name, Equals, "c3rd")
|
||||
c.Check(s.list.providesIndex["fa"][0].Name, Equals, "a1st")
|
||||
c.Check(s.list.providesIndex["fa"][1].Name, Equals, "c3rd")
|
||||
c.Check(s.list.providesIndex["fb"][0].Name, Equals, "a1st")
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestRemoveWhenIndexed(c *C) {
|
||||
s.il.Remove(s.packages[0])
|
||||
names := make([]string, s.il.Len())
|
||||
for i, p := range s.il.packagesIndex {
|
||||
names[i] = p.Name
|
||||
}
|
||||
c.Check(names, DeepEquals, []string{"aa", "app", "app", "app", "app", "data", "dpkg", "dpkg", "dpkg", "libx", "mailer"})
|
||||
|
||||
s.il.Remove(s.packages[4])
|
||||
names = make([]string, s.il.Len())
|
||||
for i, p := range s.il.packagesIndex {
|
||||
names[i] = p.Name
|
||||
}
|
||||
c.Check(names, DeepEquals, []string{"aa", "app", "app", "app", "app", "data", "dpkg", "dpkg", "dpkg", "libx"})
|
||||
c.Check(s.il.providesIndex["mail-agent"], DeepEquals, []*Package{})
|
||||
|
||||
s.il.Remove(s.packages[9])
|
||||
names = make([]string, s.il.Len())
|
||||
for i, p := range s.il.packagesIndex {
|
||||
names[i] = p.Name
|
||||
}
|
||||
c.Check(names, DeepEquals, []string{"aa", "app", "app", "app", "app", "data", "dpkg", "dpkg", "libx"})
|
||||
c.Check(s.il.providesIndex["package-installer"], HasLen, 2)
|
||||
|
||||
s.il.Remove(s.packages[1])
|
||||
names = make([]string, s.il.Len())
|
||||
for i, p := range s.il.packagesIndex {
|
||||
names[i] = p.Name
|
||||
}
|
||||
c.Check(names, DeepEquals, []string{"aa", "app", "app", "app", "app", "data", "dpkg", "libx"})
|
||||
c.Check(s.il.providesIndex["package-installer"], DeepEquals, []*Package{s.packages[11]})
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestForeach(c *C) {
|
||||
s.list.Add(s.p1)
|
||||
s.list.Add(s.p3)
|
||||
@@ -65,6 +160,114 @@ func (s *PackageListSuite) TestForeach(c *C) {
|
||||
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestIndex(c *C) {
|
||||
c.Check(len(s.il.providesIndex), Equals, 2)
|
||||
c.Check(len(s.il.providesIndex["mail-agent"]), Equals, 1)
|
||||
c.Check(len(s.il.providesIndex["package-installer"]), Equals, 3)
|
||||
c.Check(s.il.packagesIndex[0], Equals, s.packages[8])
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestAppend(c *C) {
|
||||
s.list.Add(s.p1)
|
||||
s.list.Add(s.p3)
|
||||
|
||||
err := s.list.Append(s.il)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(s.list.Len(), Equals, 14)
|
||||
|
||||
list := NewPackageList()
|
||||
list.Add(s.p4)
|
||||
|
||||
err = s.list.Append(list)
|
||||
c.Check(err, ErrorMatches, "conflict.*")
|
||||
|
||||
s.list.PrepareIndex()
|
||||
c.Check(func() { s.list.Append(s.il) }, Panics, "Append not supported when indexed")
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestSearch(c *C) {
|
||||
c.Check(func() { s.list.Search(Dependency{Architecture: "i386", Pkg: "app"}) }, Panics, "list not indexed, can't search")
|
||||
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app"}), Equals, s.packages[3])
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "mail-agent"}), Equals, s.packages[4])
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "puppy"}), IsNil)
|
||||
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionEqual, Version: "1.1~bp1"}), Equals, s.packages[3])
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionEqual, Version: "1.1~bp2"}), IsNil)
|
||||
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLess, Version: "1.1"}), Equals, s.packages[3])
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLess, Version: "1.1~~"}), IsNil)
|
||||
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1"}), Equals, s.packages[3])
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1~bp1"}), Equals, s.packages[3])
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionLessOrEqual, Version: "1.1~~"}), IsNil)
|
||||
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreater, Version: "1.0"}), Equals, s.packages[3])
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreater, Version: "1.2"}), IsNil)
|
||||
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.0"}), Equals, s.packages[3])
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.1~bp1"}), Equals, s.packages[3])
|
||||
c.Check(s.il.Search(Dependency{Architecture: "i386", Pkg: "app", Relation: VersionGreaterOrEqual, Version: "1.2"}), IsNil)
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestVerifyDependencies(c *C) {
|
||||
missing, err := s.il.VerifyDependencies(0, []string{"i386"}, s.il)
|
||||
|
||||
c.Check(err, IsNil)
|
||||
c.Check(missing, DeepEquals, []Dependency{})
|
||||
|
||||
missing, err = s.il.VerifyDependencies(0, []string{"i386", "amd64"}, s.il)
|
||||
|
||||
c.Check(err, IsNil)
|
||||
c.Check(missing, DeepEquals, []Dependency{Dependency{Pkg: "lib", Relation: VersionGreater, Version: "0.9", Architecture: "amd64"}})
|
||||
|
||||
missing, err = s.il.VerifyDependencies(0, []string{"arm"}, s.il)
|
||||
|
||||
c.Check(err, IsNil)
|
||||
c.Check(missing, DeepEquals, []Dependency{})
|
||||
|
||||
missing, err = s.il.VerifyDependencies(DepFollowAllVariants, []string{"arm"}, s.il)
|
||||
|
||||
c.Check(err, IsNil)
|
||||
c.Check(missing, DeepEquals, []Dependency{Dependency{Pkg: "lib", Relation: VersionGreater, Version: "0.9", Architecture: "arm"},
|
||||
Dependency{Pkg: "mail-agent", Relation: VersionDontCare, Version: "", Architecture: "arm"}})
|
||||
|
||||
_, err = s.il.VerifyDependencies(0, []string{"i386", "amd64", "s390"}, s.il)
|
||||
|
||||
c.Check(err, ErrorMatches, "unable to process package app-1.0_s390:.*")
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestArchitectures(c *C) {
|
||||
archs := s.il.Architectures()
|
||||
sort.Strings(archs)
|
||||
c.Check(archs, DeepEquals, []string{"amd64", "arm", "i386", "s390"})
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestNewPackageListFromRefList(c *C) {
|
||||
db, _ := database.OpenDB(c.MkDir())
|
||||
coll := NewPackageCollection(db)
|
||||
coll.Update(s.p1)
|
||||
coll.Update(s.p3)
|
||||
|
||||
s.list.Add(s.p1)
|
||||
s.list.Add(s.p3)
|
||||
s.list.Add(s.p5)
|
||||
s.list.Add(s.p6)
|
||||
|
||||
reflist := NewPackageRefListFromPackageList(s.list)
|
||||
|
||||
_, err := NewPackageListFromRefList(reflist, coll)
|
||||
c.Assert(err, ErrorMatches, "unable to load package with key.*")
|
||||
|
||||
coll.Update(s.p5)
|
||||
coll.Update(s.p6)
|
||||
|
||||
list, err := NewPackageListFromRefList(reflist, coll)
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(list.Len(), Equals, 4)
|
||||
c.Check(list.Add(s.p4), ErrorMatches, "conflict in package.*")
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestNewPackageRefList(c *C) {
|
||||
s.list.Add(s.p1)
|
||||
s.list.Add(s.p3)
|
||||
@@ -119,3 +322,128 @@ func (s *PackageListSuite) TestPackageRefListForeach(c *C) {
|
||||
|
||||
c.Check(err, Equals, e)
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestDiff(c *C) {
|
||||
db, _ := database.OpenDB(c.MkDir())
|
||||
coll := NewPackageCollection(db)
|
||||
|
||||
packages := []*Package{
|
||||
&Package{Name: "lib", Version: "1.0", Architecture: "i386"}, //0
|
||||
&Package{Name: "dpkg", Version: "1.7", Architecture: "i386"}, //1
|
||||
&Package{Name: "data", Version: "1.1~bp1", Architecture: "all"}, //2
|
||||
&Package{Name: "app", Version: "1.1~bp1", Architecture: "i386"}, //3
|
||||
&Package{Name: "app", Version: "1.1~bp2", Architecture: "i386"}, //4
|
||||
&Package{Name: "app", Version: "1.1~bp2", Architecture: "amd64"}, //5
|
||||
&Package{Name: "xyz", Version: "3.0", Architecture: "sparc"}, //6
|
||||
}
|
||||
|
||||
for _, p := range packages {
|
||||
coll.Update(p)
|
||||
}
|
||||
|
||||
listA := NewPackageList()
|
||||
listA.Add(packages[0])
|
||||
listA.Add(packages[1])
|
||||
listA.Add(packages[2])
|
||||
listA.Add(packages[3])
|
||||
listA.Add(packages[6])
|
||||
|
||||
listB := NewPackageList()
|
||||
listB.Add(packages[0])
|
||||
listB.Add(packages[2])
|
||||
listB.Add(packages[4])
|
||||
listB.Add(packages[5])
|
||||
|
||||
reflistA := NewPackageRefListFromPackageList(listA)
|
||||
reflistB := NewPackageRefListFromPackageList(listB)
|
||||
|
||||
diffAA, err := reflistA.Diff(reflistA, coll)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(diffAA, HasLen, 0)
|
||||
|
||||
diffAB, err := reflistA.Diff(reflistB, coll)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(diffAB, HasLen, 4)
|
||||
|
||||
c.Check(diffAB[0].Left, IsNil)
|
||||
c.Check(diffAB[0].Right.String(), Equals, "app-1.1~bp2_amd64")
|
||||
|
||||
c.Check(diffAB[1].Left.String(), Equals, "app-1.1~bp1_i386")
|
||||
c.Check(diffAB[1].Right.String(), Equals, "app-1.1~bp2_i386")
|
||||
|
||||
c.Check(diffAB[2].Left.String(), Equals, "dpkg-1.7_i386")
|
||||
c.Check(diffAB[2].Right, IsNil)
|
||||
|
||||
c.Check(diffAB[3].Left.String(), Equals, "xyz-3.0_sparc")
|
||||
c.Check(diffAB[3].Right, IsNil)
|
||||
|
||||
diffBA, err := reflistB.Diff(reflistA, coll)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(diffBA, HasLen, 4)
|
||||
|
||||
c.Check(diffBA[0].Right, IsNil)
|
||||
c.Check(diffBA[0].Left.String(), Equals, "app-1.1~bp2_amd64")
|
||||
|
||||
c.Check(diffBA[1].Right.String(), Equals, "app-1.1~bp1_i386")
|
||||
c.Check(diffBA[1].Left.String(), Equals, "app-1.1~bp2_i386")
|
||||
|
||||
c.Check(diffBA[2].Right.String(), Equals, "dpkg-1.7_i386")
|
||||
c.Check(diffBA[2].Left, IsNil)
|
||||
|
||||
c.Check(diffBA[3].Right.String(), Equals, "xyz-3.0_sparc")
|
||||
c.Check(diffBA[3].Left, IsNil)
|
||||
|
||||
}
|
||||
|
||||
func (s *PackageListSuite) TestMerge(c *C) {
|
||||
db, _ := database.OpenDB(c.MkDir())
|
||||
coll := NewPackageCollection(db)
|
||||
|
||||
packages := []*Package{
|
||||
&Package{Name: "lib", Version: "1.0", Architecture: "i386"}, //0
|
||||
&Package{Name: "dpkg", Version: "1.7", Architecture: "i386"}, //1
|
||||
&Package{Name: "data", Version: "1.1~bp1", Architecture: "all"}, //2
|
||||
&Package{Name: "app", Version: "1.1~bp1", Architecture: "i386"}, //3
|
||||
&Package{Name: "app", Version: "1.1~bp2", Architecture: "i386"}, //4
|
||||
&Package{Name: "app", Version: "1.1~bp2", Architecture: "amd64"}, //5
|
||||
&Package{Name: "dpkg", Version: "1.0", Architecture: "i386"}, //6
|
||||
&Package{Name: "xyz", Version: "1.0", Architecture: "sparc"}, //7
|
||||
}
|
||||
|
||||
for _, p := range packages {
|
||||
coll.Update(p)
|
||||
}
|
||||
|
||||
listA := NewPackageList()
|
||||
listA.Add(packages[0])
|
||||
listA.Add(packages[1])
|
||||
listA.Add(packages[2])
|
||||
listA.Add(packages[3])
|
||||
listA.Add(packages[7])
|
||||
|
||||
listB := NewPackageList()
|
||||
listB.Add(packages[0])
|
||||
listB.Add(packages[2])
|
||||
listB.Add(packages[4])
|
||||
listB.Add(packages[5])
|
||||
listB.Add(packages[6])
|
||||
|
||||
reflistA := NewPackageRefListFromPackageList(listA)
|
||||
reflistB := NewPackageRefListFromPackageList(listB)
|
||||
|
||||
mergeAB := reflistA.Merge(reflistB)
|
||||
mergeBA := reflistB.Merge(reflistA)
|
||||
|
||||
toStrSlice := func(reflist *PackageRefList) (result []string) {
|
||||
result = make([]string, reflist.Len())
|
||||
for i, r := range reflist.Refs {
|
||||
result[i] = string(r)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c.Check(toStrSlice(mergeAB), DeepEquals,
|
||||
[]string{"Pall data 1.1~bp1", "Pamd64 app 1.1~bp2", "Pi386 app 1.1~bp2", "Pi386 dpkg 1.0", "Pi386 lib 1.0", "Psparc xyz 1.0"})
|
||||
c.Check(toStrSlice(mergeBA), DeepEquals,
|
||||
[]string{"Pall data 1.1~bp1", "Pamd64 app 1.1~bp2", "Pi386 app 1.1~bp1", "Pi386 dpkg 1.7", "Pi386 lib 1.0", "Psparc xyz 1.0"})
|
||||
}
|
||||
|
||||
Vendored
+185
-33
@@ -7,29 +7,48 @@ import (
|
||||
"github.com/smira/aptly/utils"
|
||||
"github.com/ugorji/go/codec"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PackageFile is a single file entry in package
|
||||
type PackageFile struct {
|
||||
Filename string
|
||||
Checksums utils.ChecksumInfo
|
||||
}
|
||||
|
||||
// Verify that package file is present and correct
|
||||
func (f *PackageFile) Verify(packageRepo *Repository) (bool, error) {
|
||||
poolPath, err := packageRepo.PoolPath(f.Filename, f.Checksums.MD5)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
st, err := os.Stat(poolPath)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// verify size
|
||||
// TODO: verify checksum if configured
|
||||
return st.Size() == f.Checksums.Size, nil
|
||||
}
|
||||
|
||||
// Package is single instance of Debian package
|
||||
//
|
||||
// TODO: support source & binary
|
||||
type Package struct {
|
||||
Name string
|
||||
Version string
|
||||
Filename string
|
||||
Filesize int64
|
||||
Architecture string
|
||||
Source string
|
||||
Provides []string
|
||||
// Various dependencies
|
||||
Depends []string
|
||||
PreDepends []string
|
||||
Suggests []string
|
||||
Recommends []string
|
||||
// Hashsums of package contents
|
||||
HashMD5 string
|
||||
HashSHA1 string
|
||||
HashSHA256 string
|
||||
// Files in package
|
||||
Files []PackageFile
|
||||
// Extra information from stanza
|
||||
Extra Stanza
|
||||
}
|
||||
@@ -42,7 +61,11 @@ func parseDependencies(input Stanza, key string) []string {
|
||||
|
||||
delete(input, key)
|
||||
|
||||
return strings.Split(value, ", ")
|
||||
result := strings.Split(value, ",")
|
||||
for i := range result {
|
||||
result[i] = strings.TrimSpace(result[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NewPackageFromControlFile creates Package from parsed Debian control file
|
||||
@@ -50,30 +73,39 @@ func NewPackageFromControlFile(input Stanza) *Package {
|
||||
result := &Package{
|
||||
Name: input["Package"],
|
||||
Version: input["Version"],
|
||||
Filename: input["Filename"],
|
||||
Architecture: input["Architecture"],
|
||||
Source: input["Source"],
|
||||
HashMD5: input["MD5sum"],
|
||||
HashSHA1: input["SHA1"],
|
||||
HashSHA256: input["SHA256"],
|
||||
Files: make([]PackageFile, 0, 1),
|
||||
}
|
||||
|
||||
delete(input, "Package")
|
||||
delete(input, "Version")
|
||||
delete(input, "Filename")
|
||||
delete(input, "Architecture")
|
||||
delete(input, "Source")
|
||||
|
||||
filesize, _ := strconv.ParseInt(input["Size"], 10, 64)
|
||||
|
||||
result.Files = append(result.Files, PackageFile{
|
||||
Filename: input["Filename"],
|
||||
Checksums: utils.ChecksumInfo{
|
||||
Size: filesize,
|
||||
MD5: strings.TrimSpace(input["MD5sum"]),
|
||||
SHA1: strings.TrimSpace(input["SHA1"]),
|
||||
SHA256: strings.TrimSpace(input["SHA256"]),
|
||||
},
|
||||
})
|
||||
|
||||
delete(input, "Filename")
|
||||
delete(input, "MD5sum")
|
||||
delete(input, "SHA1")
|
||||
delete(input, "SHA256")
|
||||
|
||||
result.Filesize, _ = strconv.ParseInt(input["Size"], 10, 64)
|
||||
delete(input, "Size")
|
||||
|
||||
result.Depends = parseDependencies(input, "Depends")
|
||||
result.PreDepends = parseDependencies(input, "Pre-Depends")
|
||||
result.Suggests = parseDependencies(input, "Suggests")
|
||||
result.Recommends = parseDependencies(input, "Recommends")
|
||||
result.Provides = parseDependencies(input, "Provides")
|
||||
|
||||
result.Extra = input
|
||||
|
||||
@@ -82,7 +114,7 @@ func NewPackageFromControlFile(input Stanza) *Package {
|
||||
|
||||
// Key returns unique key identifying package
|
||||
func (p *Package) Key() []byte {
|
||||
return []byte("P" + p.Name + " " + p.Version + " " + p.Architecture)
|
||||
return []byte("P" + p.Architecture + " " + p.Name + " " + p.Version)
|
||||
}
|
||||
|
||||
// Encode does msgpack encoding of Package
|
||||
@@ -106,23 +138,49 @@ func (p *Package) String() string {
|
||||
return fmt.Sprintf("%s-%s_%s", p.Name, p.Version, p.Architecture)
|
||||
}
|
||||
|
||||
// MatchesArchitecture checks whether packages matches specified architecture
|
||||
func (p *Package) MatchesArchitecture(arch string) bool {
|
||||
if p.Architecture == "all" {
|
||||
return true
|
||||
}
|
||||
|
||||
return p.Architecture == arch
|
||||
}
|
||||
|
||||
// GetDependencies compiles list of dependenices by flags from options
|
||||
func (p *Package) GetDependencies(options int) (dependencies []string) {
|
||||
dependencies = make([]string, 0, 30)
|
||||
dependencies = append(dependencies, p.Depends...)
|
||||
dependencies = append(dependencies, p.PreDepends...)
|
||||
|
||||
if options&DepFollowRecommends == DepFollowRecommends {
|
||||
dependencies = append(dependencies, p.Recommends...)
|
||||
}
|
||||
|
||||
if options&DepFollowSuggests == DepFollowSuggests {
|
||||
dependencies = append(dependencies, p.Suggests...)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Stanza creates original stanza from package
|
||||
func (p *Package) Stanza() (result Stanza) {
|
||||
result = p.Extra.Copy()
|
||||
result["Package"] = p.Name
|
||||
result["Version"] = p.Version
|
||||
result["Filename"] = p.Filename
|
||||
result["Filename"] = p.Files[0].Filename
|
||||
result["Architecture"] = p.Architecture
|
||||
result["Source"] = p.Source
|
||||
|
||||
if p.HashMD5 != "" {
|
||||
result["MD5sum"] = p.HashMD5
|
||||
if p.Files[0].Checksums.MD5 != "" {
|
||||
result["MD5sum"] = p.Files[0].Checksums.MD5
|
||||
}
|
||||
if p.HashSHA1 != "" {
|
||||
result["SHA1"] = p.HashSHA1
|
||||
if p.Files[0].Checksums.SHA1 != "" {
|
||||
result["SHA1"] = " " + p.Files[0].Checksums.SHA1
|
||||
}
|
||||
if p.HashSHA256 != "" {
|
||||
result["SHA256"] = p.HashSHA256
|
||||
if p.Files[0].Checksums.SHA256 != "" {
|
||||
result["SHA256"] = " " + p.Files[0].Checksums.SHA256
|
||||
}
|
||||
|
||||
if p.Depends != nil {
|
||||
@@ -137,29 +195,123 @@ func (p *Package) Stanza() (result Stanza) {
|
||||
if p.Recommends != nil {
|
||||
result["Recommends"] = strings.Join(p.Recommends, ", ")
|
||||
}
|
||||
if p.Provides != nil {
|
||||
result["Provides"] = strings.Join(p.Provides, ", ")
|
||||
}
|
||||
|
||||
result["Size"] = fmt.Sprintf("%d", p.Filesize)
|
||||
result["Size"] = fmt.Sprintf("%d", p.Files[0].Checksums.Size)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Equals compares two packages to be identical
|
||||
func (p *Package) Equals(p2 *Package) bool {
|
||||
return p.Name == p2.Name && p.Version == p2.Version && p.Filename == p2.Filename &&
|
||||
if len(p.Files) != len(p2.Files) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, f := range p.Files {
|
||||
if p2.Files[i] != f {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return p.Name == p2.Name && p.Version == p2.Version &&
|
||||
p.Architecture == p2.Architecture && utils.StrSlicesEqual(p.Depends, p2.Depends) &&
|
||||
utils.StrSlicesEqual(p.PreDepends, p2.PreDepends) && utils.StrSlicesEqual(p.Suggests, p2.Suggests) &&
|
||||
utils.StrSlicesEqual(p.Recommends, p2.Recommends) && utils.StrMapsEqual(p.Extra, p2.Extra) &&
|
||||
p.Filesize == p2.Filesize && p.HashMD5 == p2.HashMD5 && p.HashSHA1 == p2.HashSHA1 &&
|
||||
p.HashSHA256 == p2.HashSHA256 && p.Source == p2.Source
|
||||
p.Source == p2.Source && utils.StrSlicesEqual(p.Provides, p2.Provides)
|
||||
}
|
||||
|
||||
// VerifyFile verifies integrity and existence of local files for the package
|
||||
func (p *Package) VerifyFile(filepath string) bool {
|
||||
st, err := os.Stat(filepath)
|
||||
// LinkFromPool links package file from pool to dist's pool location
|
||||
func (p *Package) LinkFromPool(packageRepo *Repository, prefix string, component string) error {
|
||||
poolDir, err := p.PoolDirectory()
|
||||
if err != nil {
|
||||
return false
|
||||
return err
|
||||
}
|
||||
return st.Size() == p.Filesize
|
||||
|
||||
for i, f := range p.Files {
|
||||
sourcePath, err := packageRepo.PoolPath(f.Filename, f.Checksums.MD5)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
relPath, err := packageRepo.LinkFromPool(prefix, component, sourcePath, poolDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Files[i].Filename = relPath
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PoolDirectory returns directory in package pool for this package files
|
||||
func (p *Package) PoolDirectory() (string, error) {
|
||||
source := p.Source
|
||||
if source == "" {
|
||||
source = p.Name
|
||||
}
|
||||
|
||||
if len(source) < 2 {
|
||||
return "", fmt.Errorf("package source %s too short", source)
|
||||
}
|
||||
|
||||
var subdir string
|
||||
if strings.HasPrefix(source, "lib") {
|
||||
subdir = source[:4]
|
||||
} else {
|
||||
subdir = source[:1]
|
||||
|
||||
}
|
||||
|
||||
return filepath.Join(subdir, source), nil
|
||||
}
|
||||
|
||||
// PackageDownloadTask is a element of download queue for the package
|
||||
type PackageDownloadTask struct {
|
||||
RepoURI string
|
||||
DestinationPath string
|
||||
Checksums utils.ChecksumInfo
|
||||
}
|
||||
|
||||
// DownloadList returns list of missing package files for download in format
|
||||
// [[srcpath, dstpath]]
|
||||
func (p *Package) DownloadList(packageRepo *Repository) (result []PackageDownloadTask, err error) {
|
||||
result = make([]PackageDownloadTask, 0, 1)
|
||||
|
||||
for _, f := range p.Files {
|
||||
poolPath, err := packageRepo.PoolPath(f.Filename, f.Checksums.MD5)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
verified, err := f.Verify(packageRepo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !verified {
|
||||
result = append(result, PackageDownloadTask{RepoURI: f.Filename, DestinationPath: poolPath, Checksums: f.Checksums})
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// VerifyFiles verifies that all package files have neen correctly downloaded
|
||||
func (p *Package) VerifyFiles(packageRepo *Repository) (result bool, err error) {
|
||||
result = true
|
||||
|
||||
for _, f := range p.Files {
|
||||
result, err = f.Verify(packageRepo)
|
||||
if err != nil || !result {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PackageCollection does management of packages in DB
|
||||
|
||||
Vendored
+151
-7
@@ -2,10 +2,13 @@ package debian
|
||||
|
||||
import (
|
||||
"github.com/smira/aptly/database"
|
||||
"github.com/smira/aptly/utils"
|
||||
. "launchpad.net/gocheck"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var packageStanza = Stanza{"Source": "alien-arena", "Depends": "libc6 (>= 2.7), alien-arena-data (>= 7.40)", "Filename": "pool/contrib/a/alien-arena/alien-arena-common_7.40-2_i386.deb", "SHA1": "46955e48cad27410a83740a21d766ce362364024", "SHA256": "eb4afb9885cba6dc70cccd05b910b2dbccc02c5900578be5e99f0d3dbf9d76a5", "Priority": "extra", "Maintainer": "Debian Games Team <pkg-games-devel@lists.alioth.debian.org>", "Description": "Common files for Alien Arena client and server ALIEN ARENA is a standalone 3D first person online deathmatch shooter\n crafted from the original source code of Quake II and Quake III, released\n by id Software under the GPL license. With features including 32 bit\n graphics, new particle engine and effects, light blooms, reflective water,\n hi resolution textures and skins, hi poly models, stain maps, ALIEN ARENA\n pushes the envelope of graphical beauty rivaling today's top games.\n .\n This package installs the common files for Alien Arena.\n", "Homepage": "http://red.planetarena.org", "Tag": "role::app-data, role::shared-lib, special::auto-inst-parts", "Installed-Size": "456", "Version": "7.40-2", "Replaces": "alien-arena (<< 7.33-1)", "Size": "187518", "MD5sum": "1e8cba92c41420aa7baa8a5718d67122", "Package": "alien-arena-common", "Section": "contrib/games", "Architecture": "i386"}
|
||||
var packageStanza = Stanza{"Source": "alien-arena", "Pre-Depends": "dpkg (>= 1.6)", "Suggests": "alien-arena-mars", "Recommends": "aliean-arena-luna", "Depends": "libc6 (>= 2.7), alien-arena-data (>= 7.40)", "Filename": "pool/contrib/a/alien-arena/alien-arena-common_7.40-2_i386.deb", "SHA1": " 46955e48cad27410a83740a21d766ce362364024", "SHA256": " eb4afb9885cba6dc70cccd05b910b2dbccc02c5900578be5e99f0d3dbf9d76a5", "Priority": "extra", "Maintainer": "Debian Games Team <pkg-games-devel@lists.alioth.debian.org>", "Description": "Common files for Alien Arena client and server ALIEN ARENA is a standalone 3D first person online deathmatch shooter\n crafted from the original source code of Quake II and Quake III, released\n by id Software under the GPL license. With features including 32 bit\n graphics, new particle engine and effects, light blooms, reflective water,\n hi resolution textures and skins, hi poly models, stain maps, ALIEN ARENA\n pushes the envelope of graphical beauty rivaling today's top games.\n .\n This package installs the common files for Alien Arena.\n", "Homepage": "http://red.planetarena.org", "Tag": "role::app-data, role::shared-lib, special::auto-inst-parts", "Installed-Size": "456", "Version": "7.40-2", "Replaces": "alien-arena (<< 7.33-1)", "Size": "187518", "MD5sum": "1e8cba92c41420aa7baa8a5718d67122", "Package": "alien-arena-common", "Section": "contrib/games", "Architecture": "i386"}
|
||||
|
||||
type PackageSuite struct {
|
||||
stanza Stanza
|
||||
@@ -17,22 +20,70 @@ func (s *PackageSuite) SetUpTest(c *C) {
|
||||
s.stanza = packageStanza.Copy()
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestPackageFileVerify(c *C) {
|
||||
packageRepo := NewRepository(c.MkDir())
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
poolPath, _ := packageRepo.PoolPath(p.Files[0].Filename, p.Files[0].Checksums.MD5)
|
||||
|
||||
result, err := p.Files[0].Verify(packageRepo)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(result, Equals, false)
|
||||
|
||||
err = os.MkdirAll(filepath.Dir(poolPath), 0755)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
file, err := os.Create(poolPath)
|
||||
c.Assert(err, IsNil)
|
||||
file.WriteString("abcde")
|
||||
file.Close()
|
||||
|
||||
result, err = p.Files[0].Verify(packageRepo)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(result, Equals, false)
|
||||
|
||||
result, err = p.VerifyFiles(packageRepo)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(result, Equals, false)
|
||||
|
||||
p.Files[0].Checksums.Size = 5
|
||||
result, err = p.Files[0].Verify(packageRepo)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(result, Equals, true)
|
||||
|
||||
result, err = p.VerifyFiles(packageRepo)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(result, Equals, true)
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestNewFromPara(c *C) {
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
|
||||
c.Check(p.Name, Equals, "alien-arena-common")
|
||||
c.Check(p.Version, Equals, "7.40-2")
|
||||
c.Check(p.Architecture, Equals, "i386")
|
||||
c.Check(p.Filename, Equals, "pool/contrib/a/alien-arena/alien-arena-common_7.40-2_i386.deb")
|
||||
c.Check(p.Provides, DeepEquals, []string(nil))
|
||||
c.Check(p.Files, HasLen, 1)
|
||||
c.Check(p.Files[0].Filename, Equals, "pool/contrib/a/alien-arena/alien-arena-common_7.40-2_i386.deb")
|
||||
c.Check(p.Files[0].Checksums.Size, Equals, int64(187518))
|
||||
c.Check(p.Files[0].Checksums.MD5, Equals, "1e8cba92c41420aa7baa8a5718d67122")
|
||||
c.Check(p.Depends, DeepEquals, []string{"libc6 (>= 2.7)", "alien-arena-data (>= 7.40)"})
|
||||
c.Check(p.Suggests, IsNil)
|
||||
c.Check(p.Filesize, Equals, int64(187518))
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestWithProvides(c *C) {
|
||||
s.stanza["Provides"] = "arena"
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
|
||||
c.Check(p.Name, Equals, "alien-arena-common")
|
||||
c.Check(p.Provides, DeepEquals, []string{"arena"})
|
||||
|
||||
st := p.Stanza()
|
||||
c.Check(st["Provides"], Equals, "arena")
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestKey(c *C) {
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
|
||||
c.Check(p.Key(), DeepEquals, []byte("Palien-arena-common 7.40-2 i386"))
|
||||
c.Check(p.Key(), DeepEquals, []byte("Pi386 alien-arena-common 7.40-2"))
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestEncodeDecode(c *C) {
|
||||
@@ -60,12 +111,105 @@ func (s *PackageSuite) TestString(c *C) {
|
||||
func (s *PackageSuite) TestEquals(c *C) {
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
|
||||
stanza2 := packageStanza.Copy()
|
||||
p2 := NewPackageFromControlFile(stanza2)
|
||||
p2 := NewPackageFromControlFile(packageStanza.Copy())
|
||||
c.Check(p.Equals(p2), Equals, true)
|
||||
|
||||
p2.Depends = []string{"package1"}
|
||||
c.Check(p.Equals(p2), Equals, false)
|
||||
|
||||
p2 = NewPackageFromControlFile(packageStanza.Copy())
|
||||
p2.Files[0].Checksums.MD5 = "abcdefabcdef"
|
||||
c.Check(p.Equals(p2), Equals, false)
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestMatchesArchitecture(c *C) {
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
c.Check(p.MatchesArchitecture("i386"), Equals, true)
|
||||
c.Check(p.MatchesArchitecture("amd64"), Equals, false)
|
||||
|
||||
s.stanza = packageStanza.Copy()
|
||||
s.stanza["Architecture"] = "all"
|
||||
p = NewPackageFromControlFile(s.stanza)
|
||||
c.Check(p.MatchesArchitecture("i386"), Equals, true)
|
||||
c.Check(p.MatchesArchitecture("amd64"), Equals, true)
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestGetDependencies(c *C) {
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
c.Check(p.GetDependencies(0), DeepEquals, []string{"libc6 (>= 2.7)", "alien-arena-data (>= 7.40)", "dpkg (>= 1.6)"})
|
||||
c.Check(p.GetDependencies(DepFollowSuggests), DeepEquals, []string{"libc6 (>= 2.7)", "alien-arena-data (>= 7.40)", "dpkg (>= 1.6)", "alien-arena-mars"})
|
||||
c.Check(p.GetDependencies(DepFollowSuggests|DepFollowRecommends), DeepEquals, []string{"libc6 (>= 2.7)", "alien-arena-data (>= 7.40)", "dpkg (>= 1.6)", "aliean-arena-luna", "alien-arena-mars"})
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestPoolDirectory(c *C) {
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
dir, err := p.PoolDirectory()
|
||||
c.Check(err, IsNil)
|
||||
c.Check(dir, Equals, "a/alien-arena")
|
||||
|
||||
p = NewPackageFromControlFile(packageStanza.Copy())
|
||||
p.Source = ""
|
||||
dir, err = p.PoolDirectory()
|
||||
c.Check(err, IsNil)
|
||||
c.Check(dir, Equals, "a/alien-arena-common")
|
||||
|
||||
p = NewPackageFromControlFile(packageStanza.Copy())
|
||||
p.Source = "libarena"
|
||||
dir, err = p.PoolDirectory()
|
||||
c.Check(err, IsNil)
|
||||
c.Check(dir, Equals, "liba/libarena")
|
||||
|
||||
p = NewPackageFromControlFile(packageStanza.Copy())
|
||||
p.Source = "l"
|
||||
_, err = p.PoolDirectory()
|
||||
c.Check(err, ErrorMatches, ".* too short")
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestLinkFromPool(c *C) {
|
||||
packageRepo := NewRepository(c.MkDir())
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
|
||||
poolPath, _ := packageRepo.PoolPath(p.Files[0].Filename, p.Files[0].Checksums.MD5)
|
||||
err := os.MkdirAll(filepath.Dir(poolPath), 0755)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
file, err := os.Create(poolPath)
|
||||
c.Assert(err, IsNil)
|
||||
file.Close()
|
||||
|
||||
err = p.LinkFromPool(packageRepo, "", "non-free")
|
||||
c.Check(err, IsNil)
|
||||
c.Check(p.Files[0].Filename, Equals, "pool/non-free/a/alien-arena/alien-arena-common_7.40-2_i386.deb")
|
||||
}
|
||||
|
||||
func (s *PackageSuite) TestDownloadList(c *C) {
|
||||
packageRepo := NewRepository(c.MkDir())
|
||||
p := NewPackageFromControlFile(s.stanza)
|
||||
p.Files[0].Checksums.Size = 5
|
||||
poolPath, _ := packageRepo.PoolPath(p.Files[0].Filename, p.Files[0].Checksums.MD5)
|
||||
|
||||
list, err := p.DownloadList(packageRepo)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(list, DeepEquals, []PackageDownloadTask{
|
||||
PackageDownloadTask{
|
||||
RepoURI: "pool/contrib/a/alien-arena/alien-arena-common_7.40-2_i386.deb",
|
||||
DestinationPath: poolPath,
|
||||
Checksums: utils.ChecksumInfo{Size: 5,
|
||||
MD5: "1e8cba92c41420aa7baa8a5718d67122",
|
||||
SHA1: "46955e48cad27410a83740a21d766ce362364024",
|
||||
SHA256: "eb4afb9885cba6dc70cccd05b910b2dbccc02c5900578be5e99f0d3dbf9d76a5"}}})
|
||||
|
||||
err = os.MkdirAll(filepath.Dir(poolPath), 0755)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
file, err := os.Create(poolPath)
|
||||
c.Assert(err, IsNil)
|
||||
file.WriteString("abcde")
|
||||
file.Close()
|
||||
|
||||
list, err = p.DownloadList(packageRepo)
|
||||
c.Check(err, IsNil)
|
||||
c.Check(list, DeepEquals, []PackageDownloadTask{})
|
||||
}
|
||||
|
||||
type PackageCollectionSuite struct {
|
||||
|
||||
Vendored
+256
-37
@@ -2,8 +2,13 @@ package debian
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"fmt"
|
||||
"github.com/smira/aptly/database"
|
||||
"github.com/smira/aptly/utils"
|
||||
"github.com/ugorji/go/codec"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -11,6 +16,8 @@ import (
|
||||
|
||||
// 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
|
||||
@@ -24,15 +31,63 @@ type PublishedRepo struct {
|
||||
}
|
||||
|
||||
// NewPublishedRepo creates new published repository
|
||||
func NewPublishedRepo(prefix string, distribution string, component string, architectures []string, snapshot *Snapshot) *PublishedRepo {
|
||||
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
|
||||
@@ -48,38 +103,24 @@ func (p *PublishedRepo) Publish(repo *Repository, packageCollection *PackageColl
|
||||
}
|
||||
|
||||
// Load all packages
|
||||
list := NewPackageList()
|
||||
|
||||
err = p.snapshot.RefList().ForEach(func(key []byte) error {
|
||||
pkg, err := packageCollection.ByKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return list.Add(pkg)
|
||||
})
|
||||
list, err := NewPackageListFromRefList(p.snapshot.RefList(), packageCollection)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load packages: %s", err)
|
||||
}
|
||||
|
||||
if list.Len() == 0 {
|
||||
return fmt.Errorf("repository is empty, can't publish")
|
||||
return fmt.Errorf("snapshot is empty")
|
||||
}
|
||||
|
||||
if p.Architectures == nil {
|
||||
p.Architectures = make([]string, 0, 10)
|
||||
list.ForEach(func(pkg *Package) error {
|
||||
if pkg.Architecture != "all" && !utils.StrSliceHasItem(p.Architectures, pkg.Architecture) {
|
||||
p.Architectures = append(p.Architectures, pkg.Architecture)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if len(p.Architectures) == 0 {
|
||||
p.Architectures = list.Architectures()
|
||||
}
|
||||
|
||||
if len(p.Architectures) == 0 {
|
||||
return fmt.Errorf("unable to figure out list of architectures, please supply explicit list")
|
||||
}
|
||||
|
||||
generatedFiles := map[string]*utils.ChecksumInfo{}
|
||||
generatedFiles := map[string]utils.ChecksumInfo{}
|
||||
|
||||
// For all architectures, generate release file
|
||||
for _, arch := range p.Architectures {
|
||||
@@ -97,19 +138,12 @@ func (p *PublishedRepo) Publish(repo *Repository, packageCollection *PackageColl
|
||||
bufWriter := bufio.NewWriter(packagesFile)
|
||||
|
||||
err = list.ForEach(func(pkg *Package) error {
|
||||
if pkg.Architecture == arch || pkg.Architecture == "all" {
|
||||
source := pkg.Source
|
||||
if source == "" {
|
||||
source = pkg.Name
|
||||
}
|
||||
|
||||
path, err := repo.LinkFromPool(p.Prefix, p.Component, pkg.Filename, pkg.HashMD5, source)
|
||||
if pkg.MatchesArchitecture(arch) {
|
||||
err = pkg.LinkFromPool(repo, p.Prefix, p.Component)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pkg.Filename = path
|
||||
|
||||
err = pkg.Stanza().WriteTo(bufWriter)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -167,7 +201,7 @@ func (p *PublishedRepo) Publish(repo *Repository, packageCollection *PackageColl
|
||||
release["Date"] = time.Now().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST")
|
||||
release["Components"] = p.Component
|
||||
release["Architectures"] = strings.Join(p.Architectures, " ")
|
||||
release["Description"] = "Generated by aptly\n"
|
||||
release["Description"] = " Generated by aptly\n"
|
||||
release["MD5Sum"] = "\n"
|
||||
release["SHA1"] = "\n"
|
||||
release["SHA256"] = "\n"
|
||||
@@ -198,15 +232,200 @@ func (p *PublishedRepo) Publish(repo *Repository, packageCollection *PackageColl
|
||||
releaseFilename := releaseFile.Name()
|
||||
releaseFile.Close()
|
||||
|
||||
err = signer.DetachedSign(releaseFilename, releaseFilename+".gpg")
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to sign Release file: %s", err)
|
||||
}
|
||||
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)
|
||||
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(repo *Repository, removePrefix, removePoolComponent bool) error {
|
||||
if removePrefix {
|
||||
err := repo.RemoveDirs(filepath.Join(p.Prefix, "dists"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return repo.RemoveDirs(filepath.Join(p.Prefix, "pool"))
|
||||
}
|
||||
|
||||
err := repo.RemoveDirs(filepath.Join(p.Prefix, "dists", p.Distribution))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if removePoolComponent {
|
||||
err = repo.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(packageRepo *Repository, 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(packageRepo, 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())
|
||||
}
|
||||
|
||||
Vendored
+384
-3
@@ -1,14 +1,32 @@
|
||||
package debian
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/smira/aptly/database"
|
||||
. "launchpad.net/gocheck"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
type pathExistsChecker struct {
|
||||
*CheckerInfo
|
||||
}
|
||||
|
||||
var PathExists = &pathExistsChecker{
|
||||
&CheckerInfo{Name: "PathExists", Params: []string{"path"}},
|
||||
}
|
||||
|
||||
func (checker *pathExistsChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
_, err := os.Stat(params[0].(string))
|
||||
return err == nil, ""
|
||||
}
|
||||
|
||||
type NullSigner struct{}
|
||||
|
||||
func (n *NullSigner) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NullSigner) SetKey(keyRef string) {
|
||||
|
||||
}
|
||||
@@ -25,6 +43,7 @@ type PublishedRepoSuite struct {
|
||||
PackageListMixinSuite
|
||||
repo *PublishedRepo
|
||||
packageRepo *Repository
|
||||
snapshot *Snapshot
|
||||
db database.Storage
|
||||
packageCollection *PackageCollection
|
||||
}
|
||||
@@ -41,22 +60,91 @@ func (s *PublishedRepoSuite) SetUpTest(c *C) {
|
||||
repo, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{})
|
||||
repo.packageRefs = s.reflist
|
||||
|
||||
snapshot, _ := NewSnapshotFromRepository("snap", repo)
|
||||
s.snapshot, _ = NewSnapshotFromRepository("snap", repo)
|
||||
|
||||
s.repo = NewPublishedRepo("ppa", "squeeze", "main", nil, snapshot)
|
||||
s.repo, _ = NewPublishedRepo("ppa", "squeeze", "main", nil, s.snapshot)
|
||||
|
||||
s.packageCollection = NewPackageCollection(s.db)
|
||||
s.packageCollection.Update(s.p1)
|
||||
s.packageCollection.Update(s.p2)
|
||||
s.packageCollection.Update(s.p3)
|
||||
|
||||
poolPath, _ := s.packageRepo.PoolPath(s.p1.Filename, s.p1.HashMD5)
|
||||
poolPath, _ := s.packageRepo.PoolPath(s.p1.Files[0].Filename, s.p1.Files[0].Checksums.MD5)
|
||||
err := os.MkdirAll(filepath.Dir(poolPath), 0755)
|
||||
f, err := os.Create(poolPath)
|
||||
c.Assert(err, IsNil)
|
||||
f.Close()
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TearDownTest(c *C) {
|
||||
s.db.Close()
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestPrefixNormalization(c *C) {
|
||||
|
||||
for _, t := range []struct {
|
||||
prefix string
|
||||
expected string
|
||||
errorExpected string
|
||||
}{
|
||||
{
|
||||
prefix: "ppa",
|
||||
expected: "ppa",
|
||||
},
|
||||
{
|
||||
prefix: "",
|
||||
expected: ".",
|
||||
},
|
||||
{
|
||||
prefix: "/",
|
||||
expected: ".",
|
||||
},
|
||||
{
|
||||
prefix: "//",
|
||||
expected: ".",
|
||||
},
|
||||
{
|
||||
prefix: "//ppa/",
|
||||
expected: "ppa",
|
||||
},
|
||||
{
|
||||
prefix: "ppa/..",
|
||||
expected: ".",
|
||||
},
|
||||
{
|
||||
prefix: "ppa/ubuntu/",
|
||||
expected: "ppa/ubuntu",
|
||||
},
|
||||
{
|
||||
prefix: "ppa/../ubuntu/",
|
||||
expected: "ubuntu",
|
||||
},
|
||||
{
|
||||
prefix: "../ppa/",
|
||||
errorExpected: "invalid prefix .*",
|
||||
},
|
||||
{
|
||||
prefix: "../ppa/../ppa/",
|
||||
errorExpected: "invalid prefix .*",
|
||||
},
|
||||
{
|
||||
prefix: "ppa/dists",
|
||||
errorExpected: "invalid prefix .*",
|
||||
},
|
||||
{
|
||||
prefix: "ppa/pool",
|
||||
errorExpected: "invalid prefix .*",
|
||||
},
|
||||
} {
|
||||
repo, err := NewPublishedRepo(t.prefix, "squeeze", "main", nil, s.snapshot)
|
||||
if t.errorExpected != "" {
|
||||
c.Check(err, ErrorMatches, t.errorExpected)
|
||||
} else {
|
||||
c.Check(repo.Prefix, Equals, t.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestPublish(c *C) {
|
||||
err := s.repo.Publish(s.packageRepo, s.packageCollection, &NullSigner{})
|
||||
c.Assert(err, IsNil)
|
||||
@@ -93,3 +181,296 @@ func (s *PublishedRepoSuite) TestPublish(c *C) {
|
||||
_, err = os.Stat(filepath.Join(s.packageRepo.RootPath, "public/ppa/pool/main/a/alien-arena/alien-arena-common_7.40-2_i386.deb"))
|
||||
c.Assert(err, IsNil)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestPublishNoSigner(c *C) {
|
||||
err := s.repo.Publish(s.packageRepo, s.packageCollection, nil)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Check(filepath.Join(s.packageRepo.RootPath, "public/ppa/dists/squeeze/Release"), PathExists)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestString(c *C) {
|
||||
c.Check(s.repo.String(), Equals,
|
||||
"ppa/squeeze (main) publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
||||
repo, _ := NewPublishedRepo("", "squeeze", "main", nil, s.snapshot)
|
||||
c.Check(repo.String(), Equals,
|
||||
"./squeeze (main) publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
||||
repo, _ = NewPublishedRepo("", "squeeze", "main", []string{"i386", "amd64"}, s.snapshot)
|
||||
c.Check(repo.String(), Equals,
|
||||
"./squeeze (main) [i386, amd64] publishes [snap]: Snapshot from mirror [yandex]: http://mirror.yandex.ru/debian/ squeeze")
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestKey(c *C) {
|
||||
c.Check(s.repo.Key(), DeepEquals, []byte("Uppa>>squeeze"))
|
||||
}
|
||||
|
||||
func (s *PublishedRepoSuite) TestEncodeDecode(c *C) {
|
||||
encoded := s.repo.Encode()
|
||||
repo := &PublishedRepo{}
|
||||
err := repo.Decode(encoded)
|
||||
|
||||
s.repo.snapshot = nil
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(repo, DeepEquals, s.repo)
|
||||
}
|
||||
|
||||
type PublishedRepoCollectionSuite struct {
|
||||
PackageListMixinSuite
|
||||
db database.Storage
|
||||
snapshotCollection *SnapshotCollection
|
||||
collection *PublishedRepoCollection
|
||||
snap1, snap2 *Snapshot
|
||||
repo1, repo2, repo3 *PublishedRepo
|
||||
}
|
||||
|
||||
var _ = Suite(&PublishedRepoCollectionSuite{})
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) {
|
||||
s.db, _ = database.OpenDB(c.MkDir())
|
||||
|
||||
s.snapshotCollection = NewSnapshotCollection(s.db)
|
||||
|
||||
s.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1")
|
||||
s.snap2 = NewSnapshotFromPackageList("snap2", []*Snapshot{}, NewPackageList(), "desc2")
|
||||
|
||||
s.snapshotCollection.Add(s.snap1)
|
||||
s.snapshotCollection.Add(s.snap2)
|
||||
|
||||
s.repo1, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap1)
|
||||
s.repo2, _ = NewPublishedRepo("", "anaconda", "main", []string{}, s.snap2)
|
||||
s.repo3, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap2)
|
||||
|
||||
s.collection = NewPublishedRepoCollection(s.db)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TearDownTest(c *C) {
|
||||
s.db.Close()
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TestAddByPrefixDistribution(c *C) {
|
||||
r, err := s.collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Assert(err, ErrorMatches, "*.not found")
|
||||
|
||||
c.Assert(s.collection.Add(s.repo1), IsNil)
|
||||
c.Assert(s.collection.Add(s.repo1), ErrorMatches, ".*already exists")
|
||||
c.Assert(s.collection.CheckDuplicate(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.CheckDuplicate(s.repo3), Equals, s.repo1)
|
||||
|
||||
r, err = s.collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.collection.LoadComplete(r, s.snapshotCollection)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.String(), Equals, s.repo1.String())
|
||||
|
||||
collection := NewPublishedRepoCollection(s.db)
|
||||
r, err = collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.collection.LoadComplete(r, s.snapshotCollection)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.String(), Equals, s.repo1.String())
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TestByUUID(c *C) {
|
||||
r, err := s.collection.ByUUID(s.repo1.UUID)
|
||||
c.Assert(err, ErrorMatches, "*.not found")
|
||||
|
||||
c.Assert(s.collection.Add(s.repo1), IsNil)
|
||||
|
||||
r, err = s.collection.ByUUID(s.repo1.UUID)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.collection.LoadComplete(r, s.snapshotCollection)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.String(), Equals, s.repo1.String())
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TestUpdateLoadComplete(c *C) {
|
||||
c.Assert(s.collection.Update(s.repo1), IsNil)
|
||||
|
||||
collection := NewPublishedRepoCollection(s.db)
|
||||
r, err := collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(r.snapshot, IsNil)
|
||||
c.Assert(s.collection.LoadComplete(r, s.snapshotCollection), IsNil)
|
||||
c.Assert(r.snapshot.UUID, Equals, s.repo1.snapshot.UUID)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TestForEachAndLen(c *C) {
|
||||
s.collection.Add(s.repo1)
|
||||
|
||||
count := 0
|
||||
err := s.collection.ForEach(func(*PublishedRepo) error {
|
||||
count++
|
||||
return nil
|
||||
})
|
||||
c.Assert(count, Equals, 1)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Check(s.collection.Len(), Equals, 1)
|
||||
|
||||
e := errors.New("c")
|
||||
|
||||
err = s.collection.ForEach(func(*PublishedRepo) error {
|
||||
return e
|
||||
})
|
||||
c.Assert(err, Equals, e)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoCollectionSuite) TestBySnapshot(c *C) {
|
||||
c.Check(s.collection.Add(s.repo1), IsNil)
|
||||
c.Check(s.collection.Add(s.repo2), IsNil)
|
||||
|
||||
c.Check(s.collection.BySnapshot(s.snap1), DeepEquals, []*PublishedRepo{s.repo1})
|
||||
c.Check(s.collection.BySnapshot(s.snap2), DeepEquals, []*PublishedRepo{s.repo2})
|
||||
}
|
||||
|
||||
type PublishedRepoRemoveSuite struct {
|
||||
PackageListMixinSuite
|
||||
db database.Storage
|
||||
snapshotCollection *SnapshotCollection
|
||||
collection *PublishedRepoCollection
|
||||
packageRepo *Repository
|
||||
snap1 *Snapshot
|
||||
repo1, repo2, repo3, repo4 *PublishedRepo
|
||||
}
|
||||
|
||||
var _ = Suite(&PublishedRepoRemoveSuite{})
|
||||
|
||||
func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) {
|
||||
s.db, _ = database.OpenDB(c.MkDir())
|
||||
|
||||
s.snapshotCollection = NewSnapshotCollection(s.db)
|
||||
|
||||
s.snap1 = NewSnapshotFromPackageList("snap1", []*Snapshot{}, NewPackageList(), "desc1")
|
||||
|
||||
s.snapshotCollection.Add(s.snap1)
|
||||
|
||||
s.repo1, _ = NewPublishedRepo("ppa", "anaconda", "main", []string{}, s.snap1)
|
||||
s.repo2, _ = NewPublishedRepo("", "anaconda", "main", []string{}, s.snap1)
|
||||
s.repo3, _ = NewPublishedRepo("ppa", "meduza", "main", []string{}, s.snap1)
|
||||
s.repo4, _ = NewPublishedRepo("ppa", "osminog", "contrib", []string{}, s.snap1)
|
||||
|
||||
s.collection = NewPublishedRepoCollection(s.db)
|
||||
s.collection.Add(s.repo1)
|
||||
s.collection.Add(s.repo2)
|
||||
s.collection.Add(s.repo3)
|
||||
s.collection.Add(s.repo4)
|
||||
|
||||
s.packageRepo = NewRepository(c.MkDir())
|
||||
s.packageRepo.MkDir("ppa/dists/anaconda")
|
||||
s.packageRepo.MkDir("ppa/dists/meduza")
|
||||
s.packageRepo.MkDir("ppa/dists/osminog")
|
||||
s.packageRepo.MkDir("ppa/pool/main")
|
||||
s.packageRepo.MkDir("ppa/pool/contrib")
|
||||
s.packageRepo.MkDir("dists/anaconda")
|
||||
s.packageRepo.MkDir("pool/main")
|
||||
}
|
||||
|
||||
func (s *PublishedRepoRemoveSuite) TearDownTest(c *C) {
|
||||
s.db.Close()
|
||||
}
|
||||
|
||||
func (s *PublishedRepoRemoveSuite) TestRemoveFilesOnlyDist(c *C) {
|
||||
s.repo1.RemoveFiles(s.packageRepo, false, false)
|
||||
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/meduza"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/osminog"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/main"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/contrib"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "dists/anaconda"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "pool/main"), PathExists)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPool(c *C) {
|
||||
s.repo1.RemoveFiles(s.packageRepo, false, true)
|
||||
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/meduza"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/osminog"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/main"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/contrib"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "dists/anaconda"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "pool/main"), PathExists)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPrefix(c *C) {
|
||||
s.repo1.RemoveFiles(s.packageRepo, true, true)
|
||||
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/meduza"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/osminog"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/main"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/contrib"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "dists/anaconda"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "pool/main"), PathExists)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPrefixRoot(c *C) {
|
||||
s.repo2.RemoveFiles(s.packageRepo, true, true)
|
||||
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/anaconda"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/meduza"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/main"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/contrib"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "dists/anaconda"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "pool/main"), Not(PathExists))
|
||||
}
|
||||
|
||||
func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2(c *C) {
|
||||
err := s.collection.Remove(s.packageRepo, "ppa", "anaconda")
|
||||
c.Check(err, IsNil)
|
||||
|
||||
_, err = s.collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Check(err, ErrorMatches, ".*not found")
|
||||
|
||||
collection := NewPublishedRepoCollection(s.db)
|
||||
_, err = collection.ByPrefixDistribution("ppa", "anaconda")
|
||||
c.Check(err, ErrorMatches, ".*not found")
|
||||
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/meduza"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/osminog"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/main"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/contrib"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "dists/anaconda"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "pool/main"), PathExists)
|
||||
|
||||
err = s.collection.Remove(s.packageRepo, "ppa", "anaconda")
|
||||
c.Check(err, ErrorMatches, ".*not found")
|
||||
|
||||
err = s.collection.Remove(s.packageRepo, "ppa", "meduza")
|
||||
c.Check(err, IsNil)
|
||||
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/meduza"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/osminog"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/main"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/contrib"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "dists/anaconda"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "pool/main"), PathExists)
|
||||
}
|
||||
|
||||
func (s *PublishedRepoRemoveSuite) TestRemoveRepo3(c *C) {
|
||||
err := s.collection.Remove(s.packageRepo, ".", "anaconda")
|
||||
c.Check(err, IsNil)
|
||||
|
||||
_, err = s.collection.ByPrefixDistribution(".", "anaconda")
|
||||
c.Check(err, ErrorMatches, ".*not found")
|
||||
|
||||
collection := NewPublishedRepoCollection(s.db)
|
||||
_, err = collection.ByPrefixDistribution(".", "anaconda")
|
||||
c.Check(err, ErrorMatches, ".*not found")
|
||||
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/anaconda"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/meduza"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/dists/osminog"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/main"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "ppa/pool/contrib"), PathExists)
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "dists/"), Not(PathExists))
|
||||
c.Check(filepath.Join(s.packageRepo.PublicPath(), "pool/"), Not(PathExists))
|
||||
}
|
||||
|
||||
Vendored
+259
-59
@@ -10,6 +10,8 @@ import (
|
||||
"github.com/ugorji/go/codec"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -35,6 +37,8 @@ type RemoteRepo struct {
|
||||
Meta Stanza
|
||||
// Last update date
|
||||
LastDownloadDate time.Time
|
||||
// Checksums for release files
|
||||
ReleaseFiles map[string]utils.ChecksumInfo
|
||||
// "Snapshot" of current list of packages
|
||||
packageRefs *PackageRefList
|
||||
// Parsed archived root
|
||||
@@ -56,6 +60,17 @@ func NewRemoteRepo(name string, archiveRoot string, distribution string, compone
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.Distribution == "." || result.Distribution == "./" {
|
||||
// flat repo
|
||||
result.Distribution = ""
|
||||
result.Architectures = nil
|
||||
if len(result.Components) > 0 {
|
||||
return nil, fmt.Errorf("components aren't supported for flat repos")
|
||||
}
|
||||
result.Components = nil
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -70,6 +85,11 @@ func (repo *RemoteRepo) String() string {
|
||||
return fmt.Sprintf("[%s]: %s %s", repo.Name, repo.ArchiveRoot, repo.Distribution)
|
||||
}
|
||||
|
||||
// IsFlat determines if repository is flat
|
||||
func (repo *RemoteRepo) IsFlat() bool {
|
||||
return repo.Distribution == ""
|
||||
}
|
||||
|
||||
// NumPackages return number of packages retrived from remore repo
|
||||
func (repo *RemoteRepo) NumPackages() int {
|
||||
if repo.packageRefs == nil {
|
||||
@@ -78,10 +98,27 @@ func (repo *RemoteRepo) NumPackages() int {
|
||||
return repo.packageRefs.Len()
|
||||
}
|
||||
|
||||
// ReleaseURL returns URL to Release file in repo root
|
||||
// TODO: InRelease, Release.gz, Release.bz2 handling
|
||||
func (repo *RemoteRepo) ReleaseURL() *url.URL {
|
||||
path := &url.URL{Path: fmt.Sprintf("dists/%s/Release", repo.Distribution)}
|
||||
// RefList returns package list for repo
|
||||
func (repo *RemoteRepo) RefList() *PackageRefList {
|
||||
return repo.packageRefs
|
||||
}
|
||||
|
||||
// ReleaseURL returns URL to Release* files in repo root
|
||||
func (repo *RemoteRepo) ReleaseURL(name string) *url.URL {
|
||||
var path *url.URL
|
||||
|
||||
if !repo.IsFlat() {
|
||||
path = &url.URL{Path: fmt.Sprintf("dists/%s/%s", repo.Distribution, name)}
|
||||
} else {
|
||||
path = &url.URL{Path: name}
|
||||
}
|
||||
|
||||
return repo.archiveRootURL.ResolveReference(path)
|
||||
}
|
||||
|
||||
// FlatBinaryURL returns URL to Package files for flat repo
|
||||
func (repo *RemoteRepo) FlatBinaryURL() *url.URL {
|
||||
path := &url.URL{Path: "Packages"}
|
||||
return repo.archiveRootURL.ResolveReference(path)
|
||||
}
|
||||
|
||||
@@ -100,12 +137,57 @@ func (repo *RemoteRepo) PackageURL(filename string) *url.URL {
|
||||
}
|
||||
|
||||
// Fetch updates information about repository
|
||||
func (repo *RemoteRepo) Fetch(d utils.Downloader) error {
|
||||
// Download release file to temporary URL
|
||||
release, err := utils.DownloadTemp(d, repo.ReleaseURL().String())
|
||||
if err != nil {
|
||||
return err
|
||||
func (repo *RemoteRepo) Fetch(d utils.Downloader, verifier utils.Verifier) error {
|
||||
var (
|
||||
release *os.File
|
||||
err error
|
||||
)
|
||||
|
||||
if verifier == nil {
|
||||
// 0. Just download release file to temporary URL
|
||||
release, err = utils.DownloadTemp(d, repo.ReleaseURL("Release").String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 1. try InRelease file
|
||||
inrelease, err := utils.DownloadTemp(d, repo.ReleaseURL("InRelease").String())
|
||||
if err != nil {
|
||||
goto splitsignature
|
||||
}
|
||||
defer inrelease.Close()
|
||||
|
||||
release, err = verifier.VerifyClearsigned(inrelease)
|
||||
if err != nil {
|
||||
goto splitsignature
|
||||
}
|
||||
|
||||
goto ok
|
||||
|
||||
splitsignature:
|
||||
// 2. try Release + Release.gpg
|
||||
release, err = utils.DownloadTemp(d, repo.ReleaseURL("Release").String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
releasesig, err := utils.DownloadTemp(d, repo.ReleaseURL("Release.gpg").String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = verifier.VerifyDetachedSignature(releasesig, release)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = release.Seek(0, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
ok:
|
||||
|
||||
defer release.Close()
|
||||
|
||||
sreader := NewControlFileReader(release)
|
||||
@@ -114,69 +196,132 @@ func (repo *RemoteRepo) Fetch(d utils.Downloader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
architectures := strings.Split(stanza["Architectures"], " ")
|
||||
if len(repo.Architectures) == 0 {
|
||||
repo.Architectures = architectures
|
||||
} else {
|
||||
err = utils.StringsIsSubset(repo.Architectures, architectures,
|
||||
fmt.Sprintf("architecture %%s not available in repo %s", repo))
|
||||
if err != nil {
|
||||
return err
|
||||
if !repo.IsFlat() {
|
||||
architectures := strings.Split(stanza["Architectures"], " ")
|
||||
if len(repo.Architectures) == 0 {
|
||||
repo.Architectures = architectures
|
||||
} else {
|
||||
err = utils.StringsIsSubset(repo.Architectures, architectures,
|
||||
fmt.Sprintf("architecture %%s not available in repo %s", repo))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
components := strings.Split(stanza["Components"], " ")
|
||||
if len(repo.Components) == 0 {
|
||||
repo.Components = components
|
||||
} else {
|
||||
err = utils.StringsIsSubset(repo.Components, components,
|
||||
fmt.Sprintf("component %%s not available in repo %s", repo))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
components := strings.Split(stanza["Components"], " ")
|
||||
if len(repo.Components) == 0 {
|
||||
repo.Components = components
|
||||
} else {
|
||||
err = utils.StringsIsSubset(repo.Components, components,
|
||||
fmt.Sprintf("component %%s not available in repo %s", repo))
|
||||
if err != nil {
|
||||
return err
|
||||
repo.ReleaseFiles = make(map[string]utils.ChecksumInfo)
|
||||
|
||||
parseSums := func(field string, setter func(sum *utils.ChecksumInfo, data string)) error {
|
||||
for _, line := range strings.Split(stanza[field], "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
|
||||
if len(parts) != 3 {
|
||||
return fmt.Errorf("unparseable hash sum line: %#v", line)
|
||||
}
|
||||
|
||||
size, err := strconv.ParseInt(parts[1], 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to parse size: %s", err)
|
||||
}
|
||||
|
||||
sum := repo.ReleaseFiles[parts[2]]
|
||||
|
||||
sum.Size = size
|
||||
setter(&sum, parts[0])
|
||||
|
||||
repo.ReleaseFiles[parts[2]] = sum
|
||||
}
|
||||
|
||||
delete(stanza, field)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err = parseSums("MD5Sum", func(sum *utils.ChecksumInfo, data string) { sum.MD5 = data })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = parseSums("SHA1", func(sum *utils.ChecksumInfo, data string) { sum.SHA1 = data })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = parseSums("SHA256", func(sum *utils.ChecksumInfo, data string) { sum.SHA256 = data })
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delete(stanza, "MD5Sum")
|
||||
delete(stanza, "SHA1")
|
||||
delete(stanza, "SHA256")
|
||||
repo.Meta = stanza
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Download downloads all repo files
|
||||
func (repo *RemoteRepo) Download(d utils.Downloader, packageCollection *PackageCollection, packageRepo *Repository) error {
|
||||
func (repo *RemoteRepo) Download(d utils.Downloader, packageCollection *PackageCollection, packageRepo *Repository, ignoreMismatch bool) error {
|
||||
list := NewPackageList()
|
||||
|
||||
// Download and parse all Release files
|
||||
for _, component := range repo.Components {
|
||||
for _, architecture := range repo.Architectures {
|
||||
packagesReader, packagesFile, err := utils.DownloadTryCompression(d, repo.BinaryURL(component, architecture).String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer packagesFile.Close()
|
||||
d.GetProgress().Printf("Downloading & parsing package files...\n")
|
||||
|
||||
sreader := NewControlFileReader(packagesReader)
|
||||
// Download and parse all Packages files
|
||||
packagesURLs := []string{}
|
||||
|
||||
for {
|
||||
stanza, err := sreader.ReadStanza()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if stanza == nil {
|
||||
break
|
||||
}
|
||||
|
||||
p := NewPackageFromControlFile(stanza)
|
||||
|
||||
list.Add(p)
|
||||
if repo.IsFlat() {
|
||||
packagesURLs = append(packagesURLs, repo.FlatBinaryURL().String())
|
||||
} else {
|
||||
for _, component := range repo.Components {
|
||||
for _, architecture := range repo.Architectures {
|
||||
packagesURLs = append(packagesURLs, repo.BinaryURL(component, architecture).String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, url := range packagesURLs {
|
||||
packagesReader, packagesFile, err := utils.DownloadTryCompression(d, url, repo.ReleaseFiles, ignoreMismatch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer packagesFile.Close()
|
||||
|
||||
sreader := NewControlFileReader(packagesReader)
|
||||
|
||||
for {
|
||||
stanza, err := sreader.ReadStanza()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if stanza == nil {
|
||||
break
|
||||
}
|
||||
|
||||
p := NewPackageFromControlFile(stanza)
|
||||
|
||||
list.Add(p)
|
||||
}
|
||||
}
|
||||
|
||||
d.GetProgress().Printf("Saving packages to database...\n")
|
||||
|
||||
d.GetProgress().InitBar(int64(list.Len()), false)
|
||||
|
||||
// Save package meta information to DB
|
||||
err := list.ForEach(func(p *Package) error {
|
||||
d.GetProgress().AddBar(1)
|
||||
return packageCollection.Update(p)
|
||||
})
|
||||
|
||||
@@ -184,30 +329,52 @@ func (repo *RemoteRepo) Download(d utils.Downloader, packageCollection *PackageC
|
||||
return fmt.Errorf("unable to save packages to db: %s", err)
|
||||
}
|
||||
|
||||
// Download all package files
|
||||
ch := make(chan error, list.Len())
|
||||
d.GetProgress().ShutdownBar()
|
||||
|
||||
d.GetProgress().Printf("Building download queue...\n")
|
||||
|
||||
// Build download queue
|
||||
queued := make(map[string]PackageDownloadTask, list.Len())
|
||||
count := 0
|
||||
downloadSize := int64(0)
|
||||
|
||||
err = list.ForEach(func(p *Package) error {
|
||||
poolPath, err := packageRepo.PoolPath(p.Filename, p.HashMD5)
|
||||
list, err := p.DownloadList(packageRepo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !p.VerifyFile(poolPath) {
|
||||
d.Download(repo.PackageURL(p.Filename).String(), poolPath, ch)
|
||||
count++
|
||||
for _, task := range list {
|
||||
key := task.RepoURI + "-" + task.DestinationPath
|
||||
_, found := queued[key]
|
||||
if !found {
|
||||
count++
|
||||
downloadSize += task.Checksums.Size
|
||||
queued[key] = task
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to download packages: %s", err)
|
||||
return fmt.Errorf("unable to build download queue: %s", err)
|
||||
}
|
||||
|
||||
errors := make([]string, 0)
|
||||
d.GetProgress().Printf("Download queue: %d items, %.2f GiB size\n", count, float64(downloadSize)/(1024.0*1024.0*1024.0))
|
||||
|
||||
d.GetProgress().InitBar(downloadSize, true)
|
||||
|
||||
// Download all package files
|
||||
ch := make(chan error, len(queued))
|
||||
|
||||
for _, task := range queued {
|
||||
d.DownloadWithChecksum(repo.PackageURL(task.RepoURI).String(), task.DestinationPath, ch, task.Checksums, ignoreMismatch)
|
||||
}
|
||||
|
||||
// Wait for all downloads to finish
|
||||
errors := make([]string, 0)
|
||||
|
||||
for count > 0 {
|
||||
err = <-ch
|
||||
if err != nil {
|
||||
@@ -216,8 +383,10 @@ func (repo *RemoteRepo) Download(d utils.Downloader, packageCollection *PackageC
|
||||
count--
|
||||
}
|
||||
|
||||
d.GetProgress().ShutdownBar()
|
||||
|
||||
if len(errors) > 0 {
|
||||
return fmt.Errorf("download errors: %s", strings.Join(errors, ", "))
|
||||
return fmt.Errorf("download errors:\n %s\n", strings.Join(errors, "\n "))
|
||||
}
|
||||
|
||||
repo.LastDownloadDate = time.Now()
|
||||
@@ -360,3 +529,34 @@ func (collection *RemoteRepoCollection) ForEach(handler func(*RemoteRepo) error)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Len returns number of remote repos
|
||||
func (collection *RemoteRepoCollection) Len() int {
|
||||
return len(collection.list)
|
||||
}
|
||||
|
||||
// Drop removes remote repo from collection
|
||||
func (collection *RemoteRepoCollection) Drop(repo *RemoteRepo) error {
|
||||
repoPosition := -1
|
||||
|
||||
for i, r := range collection.list {
|
||||
if r == repo {
|
||||
repoPosition = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if repoPosition == -1 {
|
||||
panic("repo not found!")
|
||||
}
|
||||
|
||||
collection.list[len(collection.list)-1], collection.list[repoPosition], collection.list =
|
||||
nil, collection.list[len(collection.list)-1], collection.list[:len(collection.list)-1]
|
||||
|
||||
err := collection.db.Delete(repo.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return collection.db.Delete(repo.RefKey())
|
||||
}
|
||||
|
||||
Vendored
+156
-15
@@ -4,7 +4,10 @@ import (
|
||||
"errors"
|
||||
"github.com/smira/aptly/database"
|
||||
"github.com/smira/aptly/utils"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
. "launchpad.net/gocheck"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -13,6 +16,29 @@ func Test(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
||||
|
||||
type NullVerifier struct {
|
||||
}
|
||||
|
||||
func (n *NullVerifier) InitKeyring() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NullVerifier) AddKeyring(keyring string) {
|
||||
}
|
||||
|
||||
func (n *NullVerifier) VerifyDetachedSignature(signature, cleartext io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NullVerifier) VerifyClearsigned(clearsigned io.Reader) (text *os.File, err error) {
|
||||
text, _ = ioutil.TempFile("", "aptly-test")
|
||||
io.Copy(text, clearsigned)
|
||||
text.Seek(0, 0)
|
||||
os.Remove(text.Name())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type PackageListMixinSuite struct {
|
||||
p1, p2, p3 *Package
|
||||
list *PackageList
|
||||
@@ -40,6 +66,7 @@ func (s *PackageListMixinSuite) SetUpPackages() {
|
||||
type RemoteRepoSuite struct {
|
||||
PackageListMixinSuite
|
||||
repo *RemoteRepo
|
||||
flat *RemoteRepo
|
||||
downloader *utils.FakeDownloader
|
||||
db database.Storage
|
||||
packageCollection *PackageCollection
|
||||
@@ -50,6 +77,7 @@ var _ = Suite(&RemoteRepoSuite{})
|
||||
|
||||
func (s *RemoteRepoSuite) SetUpTest(c *C) {
|
||||
s.repo, _ = NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{})
|
||||
s.flat, _ = NewRemoteRepo("exp42", "http://repos.express42.com/virool/precise/", "./", []string{}, []string{})
|
||||
s.downloader = utils.NewFakeDownloader().ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile)
|
||||
s.db, _ = database.OpenDB(c.MkDir())
|
||||
s.packageCollection = NewPackageCollection(s.db)
|
||||
@@ -66,42 +94,100 @@ func (s *RemoteRepoSuite) TestInvalidURL(c *C) {
|
||||
c.Assert(err, ErrorMatches, ".*hexadecimal escape in host.*")
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestFlatCreation(c *C) {
|
||||
c.Check(s.flat.Distribution, Equals, "")
|
||||
c.Check(s.flat.Architectures, IsNil)
|
||||
c.Check(s.flat.Components, IsNil)
|
||||
|
||||
_, err := NewRemoteRepo("fl", "http://some.repo/", "./", []string{"main"}, []string{})
|
||||
c.Check(err, ErrorMatches, "components aren't supported for flat repos")
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestNumPackages(c *C) {
|
||||
c.Check(s.repo.NumPackages(), Equals, 0)
|
||||
s.repo.packageRefs = s.reflist
|
||||
c.Check(s.repo.NumPackages(), Equals, 3)
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestIsFlat(c *C) {
|
||||
c.Check(s.repo.IsFlat(), Equals, false)
|
||||
c.Check(s.flat.IsFlat(), Equals, true)
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestRefList(c *C) {
|
||||
s.repo.packageRefs = s.reflist
|
||||
c.Check(s.repo.RefList(), Equals, s.reflist)
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestReleaseURL(c *C) {
|
||||
c.Assert(s.repo.ReleaseURL().String(), Equals, "http://mirror.yandex.ru/debian/dists/squeeze/Release")
|
||||
c.Assert(s.repo.ReleaseURL("Release").String(), Equals, "http://mirror.yandex.ru/debian/dists/squeeze/Release")
|
||||
c.Assert(s.repo.ReleaseURL("InRelease").String(), Equals, "http://mirror.yandex.ru/debian/dists/squeeze/InRelease")
|
||||
|
||||
c.Assert(s.flat.ReleaseURL("Release").String(), Equals, "http://repos.express42.com/virool/precise/Release")
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestBinaryURL(c *C) {
|
||||
c.Assert(s.repo.BinaryURL("main", "amd64").String(), Equals, "http://mirror.yandex.ru/debian/dists/squeeze/main/binary-amd64/Packages")
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestFlatBinaryURL(c *C) {
|
||||
c.Assert(s.flat.FlatBinaryURL().String(), Equals, "http://repos.express42.com/virool/precise/Packages")
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestPackageURL(c *C) {
|
||||
c.Assert(s.repo.PackageURL("pool/main/0/0ad/0ad_0~r11863-2_i386.deb").String(), Equals,
|
||||
"http://mirror.yandex.ru/debian/pool/main/0/0ad/0ad_0~r11863-2_i386.deb")
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestFetch(c *C) {
|
||||
err := s.repo.Fetch(s.downloader)
|
||||
err := s.repo.Fetch(s.downloader, nil)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"})
|
||||
c.Assert(s.repo.Components, DeepEquals, []string{"main"})
|
||||
c.Assert(s.downloader.Empty(), Equals, true)
|
||||
|
||||
c.Check(s.repo.ReleaseFiles, HasLen, 39)
|
||||
c.Check(s.repo.ReleaseFiles["main/binary-i386/Packages.bz2"], DeepEquals,
|
||||
utils.ChecksumInfo{
|
||||
Size: 734,
|
||||
MD5: "7954ed80936429687122b554620c1b5b",
|
||||
SHA1: "95a463a0739bf9ff622c8d68f6e4598d400f5248",
|
||||
SHA256: "377890a26f99db55e117dfc691972dcbbb7d8be1630c8fc8297530c205377f2b"})
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestFetchNullVerifier1(c *C) {
|
||||
downloader := utils.NewFakeDownloader()
|
||||
downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/InRelease", errors.New("404"))
|
||||
downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release", exampleReleaseFile)
|
||||
downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/Release.gpg", "GPG")
|
||||
|
||||
err := s.repo.Fetch(downloader, &NullVerifier{})
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"})
|
||||
c.Assert(s.repo.Components, DeepEquals, []string{"main"})
|
||||
c.Assert(downloader.Empty(), Equals, true)
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestFetchNullVerifier2(c *C) {
|
||||
downloader := utils.NewFakeDownloader()
|
||||
downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/InRelease", exampleReleaseFile)
|
||||
|
||||
err := s.repo.Fetch(downloader, &NullVerifier{})
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(s.repo.Architectures, DeepEquals, []string{"amd64", "armel", "armhf", "i386", "powerpc"})
|
||||
c.Assert(s.repo.Components, DeepEquals, []string{"main"})
|
||||
c.Assert(downloader.Empty(), Equals, true)
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestFetchWrongArchitecture(c *C) {
|
||||
s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{"xyz"})
|
||||
err := s.repo.Fetch(s.downloader)
|
||||
err := s.repo.Fetch(s.downloader, nil)
|
||||
c.Assert(err, ErrorMatches, "architecture xyz not available in repo.*")
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestFetchWrongComponent(c *C) {
|
||||
s.repo, _ = NewRemoteRepo("s", "http://mirror.yandex.ru/debian/", "squeeze", []string{"xyz"}, []string{"i386"})
|
||||
err := s.repo.Fetch(s.downloader)
|
||||
err := s.repo.Fetch(s.downloader, nil)
|
||||
c.Assert(err, ErrorMatches, "component xyz not available in repo.*")
|
||||
}
|
||||
|
||||
@@ -128,7 +214,7 @@ func (s *RemoteRepoSuite) TestRefKey(c *C) {
|
||||
func (s *RemoteRepoSuite) TestDownload(c *C) {
|
||||
s.repo.Architectures = []string{"i386"}
|
||||
|
||||
err := s.repo.Fetch(s.downloader)
|
||||
err := s.repo.Fetch(s.downloader, nil)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
s.downloader.ExpectError("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages.bz2", errors.New("HTTP 404"))
|
||||
@@ -136,7 +222,7 @@ func (s *RemoteRepoSuite) TestDownload(c *C) {
|
||||
s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/dists/squeeze/main/binary-i386/Packages", examplePackagesFile)
|
||||
s.downloader.ExpectResponse("http://mirror.yandex.ru/debian/pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb", "xyz")
|
||||
|
||||
err = s.repo.Download(s.downloader, s.packageCollection, s.packageRepo)
|
||||
err = s.repo.Download(s.downloader, s.packageCollection, s.packageRepo, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(s.downloader.Empty(), Equals, true)
|
||||
c.Assert(s.repo.packageRefs, NotNil)
|
||||
@@ -144,8 +230,35 @@ func (s *RemoteRepoSuite) TestDownload(c *C) {
|
||||
pkg, err := s.packageCollection.ByKey(s.repo.packageRefs.Refs[0])
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
poolPath, _ := s.packageRepo.PoolPath(pkg.Filename, pkg.HashMD5)
|
||||
c.Check(pkg.VerifyFile(poolPath), Equals, true)
|
||||
result, err := pkg.VerifyFiles(s.packageRepo)
|
||||
c.Check(result, Equals, true)
|
||||
c.Check(err, IsNil)
|
||||
|
||||
c.Check(pkg.Name, Equals, "amanda-client")
|
||||
}
|
||||
|
||||
func (s *RemoteRepoSuite) TestDownloadFlat(c *C) {
|
||||
downloader := utils.NewFakeDownloader()
|
||||
downloader.ExpectResponse("http://repos.express42.com/virool/precise/Release", exampleReleaseFile)
|
||||
downloader.ExpectError("http://repos.express42.com/virool/precise/Packages.bz2", errors.New("HTTP 404"))
|
||||
downloader.ExpectError("http://repos.express42.com/virool/precise/Packages.gz", errors.New("HTTP 404"))
|
||||
downloader.ExpectResponse("http://repos.express42.com/virool/precise/Packages", examplePackagesFile)
|
||||
downloader.ExpectResponse("http://repos.express42.com/virool/precise/pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb", "xyz")
|
||||
|
||||
err := s.flat.Fetch(downloader, nil)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = s.flat.Download(downloader, s.packageCollection, s.packageRepo, false)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(downloader.Empty(), Equals, true)
|
||||
c.Assert(s.flat.packageRefs, NotNil)
|
||||
|
||||
pkg, err := s.packageCollection.ByKey(s.flat.packageRefs.Refs[0])
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
result, err := pkg.VerifyFiles(s.packageRepo)
|
||||
c.Check(result, Equals, true)
|
||||
c.Check(err, IsNil)
|
||||
|
||||
c.Check(pkg.Name, Equals, "amanda-client")
|
||||
}
|
||||
@@ -219,7 +332,7 @@ func (s *RemoteRepoCollectionSuite) TestUpdateLoadComplete(c *C) {
|
||||
c.Assert(r.NumPackages(), Equals, 3)
|
||||
}
|
||||
|
||||
func (s *RemoteRepoCollectionSuite) TestForEach(c *C) {
|
||||
func (s *RemoteRepoCollectionSuite) TestForEachAndLen(c *C) {
|
||||
repo, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{})
|
||||
s.collection.Add(repo)
|
||||
|
||||
@@ -231,6 +344,8 @@ func (s *RemoteRepoCollectionSuite) TestForEach(c *C) {
|
||||
c.Assert(count, Equals, 1)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Check(s.collection.Len(), Equals, 1)
|
||||
|
||||
e := errors.New("c")
|
||||
|
||||
err = s.collection.ForEach(func(*RemoteRepo) error {
|
||||
@@ -239,6 +354,32 @@ func (s *RemoteRepoCollectionSuite) TestForEach(c *C) {
|
||||
c.Assert(err, Equals, e)
|
||||
}
|
||||
|
||||
func (s *RemoteRepoCollectionSuite) TestDrop(c *C) {
|
||||
repo1, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{})
|
||||
s.collection.Add(repo1)
|
||||
|
||||
repo2, _ := NewRemoteRepo("tyndex", "http://mirror.yandex.ru/debian/", "wheezy", []string{"main"}, []string{})
|
||||
s.collection.Add(repo2)
|
||||
|
||||
r1, _ := s.collection.ByUUID(repo1.UUID)
|
||||
c.Check(r1, Equals, repo1)
|
||||
|
||||
err := s.collection.Drop(repo1)
|
||||
c.Check(err, IsNil)
|
||||
|
||||
_, err = s.collection.ByUUID(repo1.UUID)
|
||||
c.Check(err, ErrorMatches, "mirror .* not found")
|
||||
|
||||
collection := NewRemoteRepoCollection(s.db)
|
||||
_, err = collection.ByName("yandex")
|
||||
c.Check(err, ErrorMatches, "mirror .* not found")
|
||||
|
||||
r2, _ := collection.ByName("tyndex")
|
||||
c.Check(r2.String(), Equals, repo2.String())
|
||||
|
||||
c.Check(func() { s.collection.Drop(repo1) }, Panics, "repo not found!")
|
||||
}
|
||||
|
||||
const exampleReleaseFile = `Origin: LP-PPA-agenda-developers-daily
|
||||
Label: Agenda Daily Builds
|
||||
Suite: precise
|
||||
@@ -261,7 +402,7 @@ MD5Sum:
|
||||
c63d31e8e3a5650c29a7124e541d6c23 134 main/binary-armhf/Release
|
||||
4059d198768f9f8dc9372dc1c54bc3c3 14 main/binary-armhf/Packages.bz2
|
||||
d41d8cd98f00b204e9800998ecf8427e 0 main/binary-armhf/Packages
|
||||
708fc548e709eea0dfd2d7edb6098829 1344 main/binary-i386/Packages
|
||||
c8d336856df67d509032bb54145c2f89 826 main/binary-i386/Packages
|
||||
92262f0668b265401291f0467bc93763 133 main/binary-i386/Release
|
||||
7954ed80936429687122b554620c1b5b 734 main/binary-i386/Packages.bz2
|
||||
e2eef4fe7d285b12c511adfa3a39069e 641 main/binary-i386/Packages.gz
|
||||
@@ -301,7 +442,7 @@ SHA1:
|
||||
585a452e27c2e7e047c49d4b0a7459d8c627aa08 134 main/binary-armhf/Release
|
||||
64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 main/binary-armhf/Packages.bz2
|
||||
da39a3ee5e6b4b0d3255bfef95601890afd80709 0 main/binary-armhf/Packages
|
||||
2bfad956c2d2437924a8527970858c59823451b7 1344 main/binary-i386/Packages
|
||||
1d2f0cd7a3c9e687b853eb277e241cd712b6e3b1 826 main/binary-i386/Packages
|
||||
16020809662f9bda36eb516d0995658dd94d1ad5 133 main/binary-i386/Release
|
||||
95a463a0739bf9ff622c8d68f6e4598d400f5248 734 main/binary-i386/Packages.bz2
|
||||
bf8c0dec9665ba78311c97cae1755d4b2e60af76 641 main/binary-i386/Packages.gz
|
||||
@@ -341,7 +482,7 @@ SHA256:
|
||||
d25382b633c4a1621f8df6ce86e5c63da2e506a377e05ae9453238bb18191540 134 main/binary-armhf/Release
|
||||
d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 main/binary-armhf/Packages.bz2
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-armhf/Packages
|
||||
9cd4bad3462e795bad509a44bae48622f2e9c9e56aafc999419cc5221f087dc8 1344 main/binary-i386/Packages
|
||||
b1bb341bb613363ca29440c2eb9c08a9289de5458209990ec502ed27711a83a2 826 main/binary-i386/Packages
|
||||
e5aaceaac5ecb59143a4b4ed2bf700fe85d6cf08addd10cf2058bde697b7b219 133 main/binary-i386/Release
|
||||
377890a26f99db55e117dfc691972dcbbb7d8be1630c8fc8297530c205377f2b 734 main/binary-i386/Packages.bz2
|
||||
6361e8efc67d2e7c1a8db45388aec0311007c0a1bd96698623ddeb5ed0bdc914 641 main/binary-i386/Packages.gz
|
||||
@@ -385,7 +526,7 @@ Section: utils
|
||||
Priority: optional
|
||||
Filename: pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb
|
||||
Size: 3
|
||||
MD5sum: cdc997dc06126e18ea9ba843efed9811
|
||||
SHA1: 049ba341d520c447fa2e6a1f8c871b3dbbe00106
|
||||
SHA256: 4487115ca47fe9acd95355b9278f30e18c53f33c385252252d3d7948d650d1d0
|
||||
MD5sum: d16fb36f0911f878998c136191af705e
|
||||
SHA1: 66b27417d37e024c46526c2f6d358a754fc552f3
|
||||
SHA256: 3608bca1e44ea6c4d268eb6db02260269892c0b42b86bbf1e77a6fa16c3c9282
|
||||
`
|
||||
|
||||
Vendored
+13
-23
@@ -5,7 +5,6 @@ import (
|
||||
"github.com/smira/aptly/utils"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Repository directory structure:
|
||||
@@ -60,30 +59,21 @@ func (r *Repository) CreateFile(path string) (*os.File, error) {
|
||||
return os.Create(filepath.Join(r.RootPath, "public", path))
|
||||
}
|
||||
|
||||
// RemoveDirs removes directory structure under public path
|
||||
func (r *Repository) RemoveDirs(path string) error {
|
||||
filepath := filepath.Join(r.RootPath, "public", path)
|
||||
fmt.Printf("Removing %s...\n", filepath)
|
||||
return os.RemoveAll(filepath)
|
||||
}
|
||||
|
||||
// LinkFromPool links package file from pool to dist's pool location
|
||||
func (r *Repository) LinkFromPool(prefix string, component string, filename string, hashMD5 string, source string) (string, error) {
|
||||
sourcePath, err := r.PoolPath(filename, hashMD5)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
func (r *Repository) LinkFromPool(prefix string, component string, sourcePath string, poolDirectory string) (string, error) {
|
||||
baseName := filepath.Base(sourcePath)
|
||||
|
||||
if len(source) < 2 {
|
||||
return "", fmt.Errorf("package source %s too short", source)
|
||||
}
|
||||
relPath := filepath.Join("pool", component, poolDirectory, baseName)
|
||||
poolPath := filepath.Join(r.RootPath, "public", prefix, "pool", component, poolDirectory)
|
||||
|
||||
var subdir string
|
||||
if strings.HasPrefix(source, "lib") {
|
||||
subdir = source[:4]
|
||||
} else {
|
||||
subdir = source[:1]
|
||||
|
||||
}
|
||||
|
||||
baseName := filepath.Base(filename)
|
||||
relPath := filepath.Join("pool", component, subdir, source, baseName)
|
||||
poolPath := filepath.Join(r.RootPath, "public", prefix, "pool", component, subdir, source)
|
||||
|
||||
err = os.MkdirAll(poolPath, 0755)
|
||||
err := os.MkdirAll(poolPath, 0755)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -98,6 +88,6 @@ func (r *Repository) LinkFromPool(prefix string, component string, filename stri
|
||||
}
|
||||
|
||||
// ChecksumsForFile proxies requests to utils.ChecksumsForFile, joining public path
|
||||
func (r *Repository) ChecksumsForFile(path string) (*utils.ChecksumInfo, error) {
|
||||
func (r *Repository) ChecksumsForFile(path string) (utils.ChecksumInfo, error) {
|
||||
return utils.ChecksumsForFile(filepath.Join(r.RootPath, "public", path))
|
||||
}
|
||||
|
||||
Vendored
+44
-19
@@ -52,51 +52,76 @@ func (s *RepositorySuite) TestCreateFile(c *C) {
|
||||
c.Assert(err, IsNil)
|
||||
}
|
||||
|
||||
func (s *RepositorySuite) TestRemoveDirs(c *C) {
|
||||
err := s.repo.MkDir("ppa/dists/squeeze/")
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
file, err := s.repo.CreateFile("ppa/dists/squeeze/Release")
|
||||
c.Assert(err, IsNil)
|
||||
defer file.Close()
|
||||
|
||||
err = s.repo.RemoveDirs("ppa/dists/")
|
||||
|
||||
_, err = os.Stat(filepath.Join(s.repo.RootPath, "public/ppa/dists/squeeze/Release"))
|
||||
c.Assert(err, NotNil)
|
||||
c.Assert(os.IsNotExist(err), Equals, true)
|
||||
}
|
||||
|
||||
func (s *RepositorySuite) TestLinkFromPool(c *C) {
|
||||
tests := []struct {
|
||||
packageFilename string
|
||||
MD5 string
|
||||
source string
|
||||
prefix string
|
||||
component string
|
||||
sourcePath string
|
||||
poolDirectory string
|
||||
expectedFilename string
|
||||
}{
|
||||
{ // package name regular
|
||||
packageFilename: "pool/m/mars-invaders_1.03.deb",
|
||||
MD5: "91b1a1480b90b9e269ca44d897b12575",
|
||||
source: "mars-invaders",
|
||||
prefix: "",
|
||||
component: "main",
|
||||
sourcePath: "pool/01/ae/mars-invaders_1.03.deb",
|
||||
poolDirectory: "m/mars-invaders",
|
||||
expectedFilename: "pool/main/m/mars-invaders/mars-invaders_1.03.deb",
|
||||
},
|
||||
{ // lib-like filename
|
||||
packageFilename: "pool/libm/libmars-invaders_1.03.deb",
|
||||
MD5: "12c2a1480b90b9e269ca44d897b12575",
|
||||
source: "libmars-invaders",
|
||||
prefix: "",
|
||||
component: "main",
|
||||
sourcePath: "pool/01/ae/libmars-invaders_1.03.deb",
|
||||
poolDirectory: "libm/libmars-invaders",
|
||||
expectedFilename: "pool/main/libm/libmars-invaders/libmars-invaders_1.03.deb",
|
||||
},
|
||||
{ // duplicate link, shouldn't panic
|
||||
packageFilename: "pool/m/mars-invaders_1.03.deb",
|
||||
MD5: "91b1a1480b90b9e269ca44d897b12575",
|
||||
source: "mars-invaders",
|
||||
prefix: "",
|
||||
component: "main",
|
||||
sourcePath: "pool/01/ae/mars-invaders_1.03.deb",
|
||||
poolDirectory: "m/mars-invaders",
|
||||
expectedFilename: "pool/main/m/mars-invaders/mars-invaders_1.03.deb",
|
||||
},
|
||||
{ // prefix & component
|
||||
prefix: "ppa",
|
||||
component: "contrib",
|
||||
sourcePath: "pool/01/ae/libmars-invaders_1.04.deb",
|
||||
poolDirectory: "libm/libmars-invaders",
|
||||
expectedFilename: "pool/contrib/libm/libmars-invaders/libmars-invaders_1.04.deb",
|
||||
},
|
||||
}
|
||||
|
||||
for _, t := range tests {
|
||||
poolPath, err := s.repo.PoolPath(t.packageFilename, t.MD5)
|
||||
t.sourcePath = filepath.Join(s.repo.RootPath, t.sourcePath)
|
||||
|
||||
err := os.MkdirAll(filepath.Dir(t.sourcePath), 0755)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
err = os.MkdirAll(filepath.Dir(poolPath), 0755)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
file, err := os.Create(poolPath)
|
||||
file, err := os.Create(t.sourcePath)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
file.Write([]byte("Contents"))
|
||||
file.Close()
|
||||
|
||||
path, err := s.repo.LinkFromPool("", "main", t.packageFilename, t.MD5, t.source)
|
||||
path, err := s.repo.LinkFromPool(t.prefix, t.component, t.sourcePath, t.poolDirectory)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(path, Equals, t.expectedFilename)
|
||||
|
||||
st, err := os.Stat(filepath.Join(s.repo.RootPath, "public", t.expectedFilename))
|
||||
st, err := os.Stat(filepath.Join(s.repo.RootPath, "public", t.prefix, t.expectedFilename))
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
info := st.Sys().(*syscall.Stat_t)
|
||||
|
||||
Vendored
+90
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/smira/aptly/database"
|
||||
"github.com/smira/aptly/utils"
|
||||
"github.com/ugorji/go/codec"
|
||||
"log"
|
||||
"time"
|
||||
@@ -46,6 +47,29 @@ func NewSnapshotFromRepository(name string, repo *RemoteRepo) (*Snapshot, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewSnapshotFromPackageList creates snapshot from PackageList
|
||||
func NewSnapshotFromPackageList(name string, sources []*Snapshot, list *PackageList, description string) *Snapshot {
|
||||
return NewSnapshotFromRefList(name, sources, NewPackageRefListFromPackageList(list), description)
|
||||
}
|
||||
|
||||
// NewSnapshotFromRefList creates snapshot from PackageRefList
|
||||
func NewSnapshotFromRefList(name string, sources []*Snapshot, list *PackageRefList, description string) *Snapshot {
|
||||
sourceUUIDs := make([]string, len(sources))
|
||||
for i := range sources {
|
||||
sourceUUIDs[i] = sources[i].UUID
|
||||
}
|
||||
|
||||
return &Snapshot{
|
||||
UUID: uuid.New(),
|
||||
Name: name,
|
||||
CreatedAt: time.Now(),
|
||||
SourceKind: "snapshot",
|
||||
SourceIDs: sourceUUIDs,
|
||||
Description: description,
|
||||
packageRefs: list,
|
||||
}
|
||||
}
|
||||
|
||||
// String returns string representation of snapshot
|
||||
func (s *Snapshot) String() string {
|
||||
return fmt.Sprintf("[%s]: %s", s.Name, s.Description)
|
||||
@@ -161,6 +185,40 @@ func (collection *SnapshotCollection) ByName(name string) (*Snapshot, error) {
|
||||
return nil, fmt.Errorf("snapshot with name %s not found", name)
|
||||
}
|
||||
|
||||
// ByUUID looks up snapshot by UUID
|
||||
func (collection *SnapshotCollection) ByUUID(uuid string) (*Snapshot, error) {
|
||||
for _, s := range collection.list {
|
||||
if s.UUID == uuid {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("snapshot with uuid %s not found", uuid)
|
||||
}
|
||||
|
||||
// ByRemoteRepoSource looks up snapshots that have specified RepoteRepo as a source
|
||||
func (collection *SnapshotCollection) ByRemoteRepoSource(repo *RemoteRepo) []*Snapshot {
|
||||
result := make([]*Snapshot, 0)
|
||||
|
||||
for _, s := range collection.list {
|
||||
if s.SourceKind == "repo" && utils.StrSliceHasItem(s.SourceIDs, repo.UUID) {
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BySnapshotSource looks up snapshots that have specified snapshot as a source
|
||||
func (collection *SnapshotCollection) BySnapshotSource(snapshot *Snapshot) []*Snapshot {
|
||||
result := make([]*Snapshot, 0)
|
||||
|
||||
for _, s := range collection.list {
|
||||
if s.SourceKind == "snapshot" && utils.StrSliceHasItem(s.SourceIDs, snapshot.UUID) {
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ForEach runs method for each snapshot
|
||||
func (collection *SnapshotCollection) ForEach(handler func(*Snapshot) error) error {
|
||||
var err error
|
||||
@@ -172,3 +230,35 @@ func (collection *SnapshotCollection) ForEach(handler func(*Snapshot) error) err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Len returns number of snapshots in collection
|
||||
// ForEach runs method for each snapshot
|
||||
func (collection *SnapshotCollection) Len() int {
|
||||
return len(collection.list)
|
||||
}
|
||||
|
||||
// Drop removes snapshot from collection
|
||||
func (collection *SnapshotCollection) Drop(snapshot *Snapshot) error {
|
||||
snapshotPosition := -1
|
||||
|
||||
for i, s := range collection.list {
|
||||
if s == snapshot {
|
||||
snapshotPosition = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if snapshotPosition == -1 {
|
||||
panic("snapshot not found!")
|
||||
}
|
||||
|
||||
collection.list[len(collection.list)-1], collection.list[snapshotPosition], collection.list =
|
||||
nil, collection.list[len(collection.list)-1], collection.list[:len(collection.list)-1]
|
||||
|
||||
err := collection.db.Delete(snapshot.Key())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return collection.db.Delete(snapshot.RefKey())
|
||||
}
|
||||
|
||||
Vendored
+79
-2
@@ -24,12 +24,34 @@ func (s *SnapshotSuite) TestNewSnapshotFromRepository(c *C) {
|
||||
c.Check(snapshot.Name, Equals, "snap1")
|
||||
c.Check(snapshot.NumPackages(), Equals, 3)
|
||||
c.Check(snapshot.RefList().Len(), Equals, 3)
|
||||
c.Check(snapshot.SourceKind, Equals, "repo")
|
||||
c.Check(snapshot.SourceIDs, DeepEquals, []string{s.repo.UUID})
|
||||
|
||||
s.repo.packageRefs = nil
|
||||
_, err := NewSnapshotFromRepository("snap2", s.repo)
|
||||
c.Check(err, ErrorMatches, ".*not updated")
|
||||
}
|
||||
|
||||
func (s *SnapshotSuite) TestNewSnapshotFromPackageList(c *C) {
|
||||
snap, _ := NewSnapshotFromRepository("snap1", s.repo)
|
||||
|
||||
snapshot := NewSnapshotFromPackageList("snap2", []*Snapshot{snap}, s.list, "Pulled")
|
||||
c.Check(snapshot.Name, Equals, "snap2")
|
||||
c.Check(snapshot.NumPackages(), Equals, 3)
|
||||
c.Check(snapshot.SourceKind, Equals, "snapshot")
|
||||
c.Check(snapshot.SourceIDs, DeepEquals, []string{snap.UUID})
|
||||
}
|
||||
|
||||
func (s *SnapshotSuite) TestNewSnapshotFromRefList(c *C) {
|
||||
snap, _ := NewSnapshotFromRepository("snap1", s.repo)
|
||||
|
||||
snapshot := NewSnapshotFromRefList("snap2", []*Snapshot{snap}, s.reflist, "Merged")
|
||||
c.Check(snapshot.Name, Equals, "snap2")
|
||||
c.Check(snapshot.NumPackages(), Equals, 3)
|
||||
c.Check(snapshot.SourceKind, Equals, "snapshot")
|
||||
c.Check(snapshot.SourceIDs, DeepEquals, []string{snap.UUID})
|
||||
}
|
||||
|
||||
func (s *SnapshotSuite) TestKey(c *C) {
|
||||
snapshot, _ := NewSnapshotFromRepository("snap1", s.repo)
|
||||
c.Assert(len(snapshot.Key()), Equals, 37)
|
||||
@@ -81,7 +103,7 @@ func (s *SnapshotCollectionSuite) TearDownTest(c *C) {
|
||||
s.db.Close()
|
||||
}
|
||||
|
||||
func (s *SnapshotCollectionSuite) TestAddByName(c *C) {
|
||||
func (s *SnapshotCollectionSuite) TestAddByNameByUUID(c *C) {
|
||||
snapshot, err := s.collection.ByName("snap1")
|
||||
c.Assert(err, ErrorMatches, "*.not found")
|
||||
|
||||
@@ -98,6 +120,10 @@ func (s *SnapshotCollectionSuite) TestAddByName(c *C) {
|
||||
snapshot, err = collection.ByName("snap1")
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(snapshot.String(), Equals, s.snapshot1.String())
|
||||
|
||||
snapshot, err = collection.ByUUID(s.snapshot1.UUID)
|
||||
c.Assert(err, IsNil)
|
||||
c.Assert(snapshot.String(), Equals, s.snapshot1.String())
|
||||
}
|
||||
|
||||
func (s *SnapshotCollectionSuite) TestUpdateLoadComplete(c *C) {
|
||||
@@ -112,7 +138,7 @@ func (s *SnapshotCollectionSuite) TestUpdateLoadComplete(c *C) {
|
||||
c.Assert(snapshot.NumPackages(), Equals, 3)
|
||||
}
|
||||
|
||||
func (s *SnapshotCollectionSuite) TestForEach(c *C) {
|
||||
func (s *SnapshotCollectionSuite) TestForEachAndLen(c *C) {
|
||||
s.collection.Add(s.snapshot1)
|
||||
s.collection.Add(s.snapshot2)
|
||||
|
||||
@@ -124,9 +150,60 @@ func (s *SnapshotCollectionSuite) TestForEach(c *C) {
|
||||
c.Assert(count, Equals, 2)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
c.Check(s.collection.Len(), Equals, 2)
|
||||
|
||||
e := errors.New("d")
|
||||
err = s.collection.ForEach(func(*Snapshot) error {
|
||||
return e
|
||||
})
|
||||
c.Assert(err, Equals, e)
|
||||
}
|
||||
|
||||
func (s *SnapshotCollectionSuite) TestFindByRemoteRepoSource(c *C) {
|
||||
c.Assert(s.collection.Add(s.snapshot1), IsNil)
|
||||
c.Assert(s.collection.Add(s.snapshot2), IsNil)
|
||||
|
||||
c.Check(s.collection.ByRemoteRepoSource(s.repo1), DeepEquals, []*Snapshot{s.snapshot1})
|
||||
c.Check(s.collection.ByRemoteRepoSource(s.repo2), DeepEquals, []*Snapshot{s.snapshot2})
|
||||
|
||||
repo3, _ := NewRemoteRepo("other", "http://mirror.yandex.ru/debian/", "lenny", []string{"main"}, []string{})
|
||||
|
||||
c.Check(s.collection.ByRemoteRepoSource(repo3), DeepEquals, []*Snapshot{})
|
||||
}
|
||||
|
||||
func (s *SnapshotCollectionSuite) TestFindSnapshotSource(c *C) {
|
||||
snapshot3 := NewSnapshotFromRefList("snap3", []*Snapshot{s.snapshot1, s.snapshot2}, s.reflist, "desc1")
|
||||
snapshot4 := NewSnapshotFromRefList("snap4", []*Snapshot{s.snapshot1}, s.reflist, "desc2")
|
||||
snapshot5 := NewSnapshotFromRefList("snap5", []*Snapshot{snapshot3}, s.reflist, "desc3")
|
||||
|
||||
c.Assert(s.collection.Add(s.snapshot1), IsNil)
|
||||
c.Assert(s.collection.Add(s.snapshot2), IsNil)
|
||||
c.Assert(s.collection.Add(snapshot3), IsNil)
|
||||
c.Assert(s.collection.Add(snapshot4), IsNil)
|
||||
c.Assert(s.collection.Add(snapshot5), IsNil)
|
||||
|
||||
c.Check(s.collection.BySnapshotSource(s.snapshot1), DeepEquals, []*Snapshot{snapshot3, snapshot4})
|
||||
c.Check(s.collection.BySnapshotSource(s.snapshot2), DeepEquals, []*Snapshot{snapshot3})
|
||||
c.Check(s.collection.BySnapshotSource(snapshot5), DeepEquals, []*Snapshot{})
|
||||
}
|
||||
|
||||
func (s *SnapshotCollectionSuite) TestDrop(c *C) {
|
||||
s.collection.Add(s.snapshot1)
|
||||
s.collection.Add(s.snapshot2)
|
||||
|
||||
snap, _ := s.collection.ByUUID(s.snapshot1.UUID)
|
||||
c.Check(snap, Equals, s.snapshot1)
|
||||
|
||||
err := s.collection.Drop(s.snapshot1)
|
||||
c.Check(err, IsNil)
|
||||
|
||||
_, err = s.collection.ByUUID(s.snapshot1.UUID)
|
||||
c.Check(err, ErrorMatches, "snapshot .* not found")
|
||||
|
||||
collection := NewSnapshotCollection(s.db)
|
||||
|
||||
_, err = collection.ByUUID(s.snapshot1.UUID)
|
||||
c.Check(err, ErrorMatches, "snapshot .* not found")
|
||||
|
||||
c.Check(func() { s.collection.Drop(s.snapshot1) }, Panics, "snapshot not found!")
|
||||
}
|
||||
|
||||
Vendored
+271
@@ -0,0 +1,271 @@
|
||||
package debian
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Using documentation from: http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
|
||||
|
||||
// CompareVersions compares two package versions
|
||||
func CompareVersions(ver1, ver2 string) int {
|
||||
e1, u1, d1 := parseVersion(ver1)
|
||||
e2, u2, d2 := parseVersion(ver2)
|
||||
|
||||
r := compareVersionPart(e1, e2)
|
||||
if r != 0 {
|
||||
return r
|
||||
}
|
||||
|
||||
r = compareVersionPart(u1, u2)
|
||||
if r != 0 {
|
||||
return r
|
||||
}
|
||||
|
||||
return compareVersionPart(d1, d2)
|
||||
}
|
||||
|
||||
// parseVersions breaks down full version to components (possibly empty)
|
||||
func parseVersion(ver string) (epoch, upstream, debian string) {
|
||||
i := strings.LastIndex(ver, "-")
|
||||
if i != -1 {
|
||||
debian, ver = ver[i+1:], ver[:i]
|
||||
}
|
||||
|
||||
i = strings.Index(ver, ":")
|
||||
if i != -1 {
|
||||
epoch, ver = ver[:i], ver[i+1:]
|
||||
}
|
||||
|
||||
upstream = ver
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// compareLexicographic compares in "Debian lexicographic" way, see below compareVersionPart for details
|
||||
func compareLexicographic(s1, s2 string) int {
|
||||
i := 0
|
||||
l1, l2 := len(s1), len(s2)
|
||||
|
||||
for {
|
||||
if i == l1 && i == l2 {
|
||||
// s1 equal to s2
|
||||
break
|
||||
}
|
||||
|
||||
if i == l2 {
|
||||
// s1 is longer than s2
|
||||
if s1[i] == '~' {
|
||||
return -1 // s1 < s2
|
||||
}
|
||||
return 1 // s1 > s2
|
||||
}
|
||||
|
||||
if i == l1 {
|
||||
// s2 is longer than s1
|
||||
if s2[i] == '~' {
|
||||
return 1 // s1 > s2
|
||||
}
|
||||
return -1 // s1 < s2
|
||||
}
|
||||
|
||||
if s1[i] == s2[i] {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
if s1[i] == '~' {
|
||||
return -1
|
||||
}
|
||||
|
||||
if s2[i] == '~' {
|
||||
return 1
|
||||
}
|
||||
|
||||
c1, c2 := unicode.IsLetter(rune(s1[i])), unicode.IsLetter(rune(s2[i]))
|
||||
if c1 && !c2 {
|
||||
return -1
|
||||
}
|
||||
if !c1 && c2 {
|
||||
return 1
|
||||
}
|
||||
|
||||
if s1[i] < s2[i] {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// compareVersionPart compares parts of full version
|
||||
//
|
||||
// From Debian Policy Manual:
|
||||
//
|
||||
// "The strings are compared from left to right.
|
||||
//
|
||||
// First the initial part of each string consisting entirely of non-digit characters is
|
||||
// determined. These two parts (one of which may be empty) are compared lexically. If a
|
||||
// difference is found it is returned. The lexical comparison is a comparison of ASCII values
|
||||
// modified so that all the letters sort earlier than all the non-letters and so that a tilde
|
||||
// sorts before anything, even the end of a part. For example, the following parts are in sorted
|
||||
// order from earliest to latest: ~~, ~~a, ~, the empty part.
|
||||
//
|
||||
// Then the initial part of the remainder of each string which consists entirely of digit
|
||||
// characters is determined. The numerical values of these two parts are compared, and any difference
|
||||
// found is returned as the result of the comparison. For these purposes an empty string (which can only occur at
|
||||
// the end of one or both version strings being compared) counts as zero.
|
||||
|
||||
// These two steps (comparing and removing initial non-digit strings and initial digit strings) are
|
||||
// repeated until a difference is found or both strings are exhausted."
|
||||
func compareVersionPart(part1, part2 string) int {
|
||||
i1, i2 := 0, 0
|
||||
l1, l2 := len(part1), len(part2)
|
||||
|
||||
for {
|
||||
j1, j2 := i1, i2
|
||||
for j1 < l1 && !unicode.IsDigit(rune(part1[j1])) {
|
||||
j1++
|
||||
}
|
||||
|
||||
for j2 < l2 && !unicode.IsDigit(rune(part2[j2])) {
|
||||
j2++
|
||||
}
|
||||
|
||||
s1, s2 := part1[i1:j1], part2[i2:j2]
|
||||
r := compareLexicographic(s1, s2)
|
||||
if r != 0 {
|
||||
return r
|
||||
}
|
||||
|
||||
i1, i2 = j1, j2
|
||||
|
||||
for j1 < l1 && unicode.IsDigit(rune(part1[j1])) {
|
||||
j1++
|
||||
}
|
||||
|
||||
for j2 < l2 && unicode.IsDigit(rune(part2[j2])) {
|
||||
j2++
|
||||
}
|
||||
|
||||
s1, s2 = part1[i1:j1], part2[i2:j2]
|
||||
n1, _ := strconv.Atoi(s1)
|
||||
n2, _ := strconv.Atoi(s2)
|
||||
|
||||
if n1 < n2 {
|
||||
return -1
|
||||
}
|
||||
if n1 > n2 {
|
||||
return 1
|
||||
}
|
||||
|
||||
i1, i2 = j1, j2
|
||||
|
||||
if i1 == l1 && i2 == l2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Version relations
|
||||
const (
|
||||
VersionDontCare = iota
|
||||
VersionLess
|
||||
VersionLessOrEqual
|
||||
VersionEqual
|
||||
VersionGreaterOrEqual
|
||||
VersionGreater
|
||||
)
|
||||
|
||||
// Dependency is a parsed version of Debian dependency to package
|
||||
type Dependency struct {
|
||||
Pkg string
|
||||
Relation int
|
||||
Version string
|
||||
Architecture string
|
||||
}
|
||||
|
||||
// Hash calculates some predefined unique ID of Dependency
|
||||
func (d *Dependency) Hash() string {
|
||||
return fmt.Sprintf("%s:%s:%d:%s", d.Architecture, d.Pkg, d.Relation, d.Version)
|
||||
}
|
||||
|
||||
// String produces human-readable representation
|
||||
func (d *Dependency) String() string {
|
||||
var rel string
|
||||
switch d.Relation {
|
||||
case VersionEqual:
|
||||
rel = "="
|
||||
case VersionGreater:
|
||||
rel = ">>"
|
||||
case VersionLess:
|
||||
rel = "<<"
|
||||
case VersionGreaterOrEqual:
|
||||
rel = ">="
|
||||
case VersionLessOrEqual:
|
||||
rel = "<="
|
||||
case VersionDontCare:
|
||||
return fmt.Sprintf("%s [%s]", d.Pkg, d.Architecture)
|
||||
}
|
||||
return fmt.Sprintf("%s (%s %s) [%s]", d.Pkg, rel, d.Version, d.Architecture)
|
||||
}
|
||||
|
||||
// ParseDependencyVariants parses dependencies in format "pkg (>= 1.35) | other-package"
|
||||
func ParseDependencyVariants(variants string) (l []Dependency, err error) {
|
||||
parts := strings.Split(variants, "|")
|
||||
l = make([]Dependency, len(parts))
|
||||
|
||||
for i, part := range parts {
|
||||
l[i], err = ParseDependency(strings.TrimSpace(part))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ParseDependency parses dependency in format "pkg (>= 1.35)" into parts
|
||||
func ParseDependency(dep string) (d Dependency, err error) {
|
||||
if !strings.HasSuffix(dep, ")") {
|
||||
d.Pkg = strings.TrimSpace(dep)
|
||||
d.Relation = VersionDontCare
|
||||
return
|
||||
}
|
||||
|
||||
i := strings.Index(dep, "(")
|
||||
if i == -1 {
|
||||
err = fmt.Errorf("unable to parse dependency: %s", dep)
|
||||
return
|
||||
}
|
||||
|
||||
d.Pkg = strings.TrimSpace(dep[0:i])
|
||||
|
||||
rel := dep[i+1 : i+2]
|
||||
if dep[i+2] == '>' || dep[i+2] == '<' || dep[i+2] == '=' {
|
||||
rel += dep[i+2 : i+3]
|
||||
d.Version = strings.TrimSpace(dep[i+3 : len(dep)-1])
|
||||
} else {
|
||||
d.Version = strings.TrimSpace(dep[i+2 : len(dep)-1])
|
||||
}
|
||||
|
||||
switch rel {
|
||||
case "<", "<=":
|
||||
d.Relation = VersionLessOrEqual
|
||||
case ">", ">=":
|
||||
d.Relation = VersionGreaterOrEqual
|
||||
case "<<":
|
||||
d.Relation = VersionLess
|
||||
case ">>":
|
||||
d.Relation = VersionGreater
|
||||
case "=":
|
||||
d.Relation = VersionEqual
|
||||
default:
|
||||
err = fmt.Errorf("relation unknown: %s", rel)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
Vendored
+186
@@ -0,0 +1,186 @@
|
||||
package debian
|
||||
|
||||
import (
|
||||
. "launchpad.net/gocheck"
|
||||
)
|
||||
|
||||
type VersionSuite struct {
|
||||
stanza Stanza
|
||||
}
|
||||
|
||||
var _ = Suite(&VersionSuite{})
|
||||
|
||||
func (s *VersionSuite) TestParseVersion(c *C) {
|
||||
e, u, d := parseVersion("1.3.4")
|
||||
c.Check([]string{e, u, d}, DeepEquals, []string{"", "1.3.4", ""})
|
||||
|
||||
e, u, d = parseVersion("4:1.3:4")
|
||||
c.Check([]string{e, u, d}, DeepEquals, []string{"4", "1.3:4", ""})
|
||||
|
||||
e, u, d = parseVersion("1.3.4-1")
|
||||
c.Check([]string{e, u, d}, DeepEquals, []string{"", "1.3.4", "1"})
|
||||
|
||||
e, u, d = parseVersion("1.3-pre4-1")
|
||||
c.Check([]string{e, u, d}, DeepEquals, []string{"", "1.3-pre4", "1"})
|
||||
|
||||
e, u, d = parseVersion("4:1.3-pre4-1")
|
||||
c.Check([]string{e, u, d}, DeepEquals, []string{"4", "1.3-pre4", "1"})
|
||||
}
|
||||
|
||||
func (s *VersionSuite) TestCompareLexicographic(c *C) {
|
||||
c.Check(compareLexicographic("", ""), Equals, 0)
|
||||
c.Check(compareLexicographic("pre", "pre"), Equals, 0)
|
||||
|
||||
c.Check(compareLexicographic("pr", "pre"), Equals, -1)
|
||||
c.Check(compareLexicographic("pre", "pr"), Equals, 1)
|
||||
|
||||
c.Check(compareLexicographic("pra", "prb"), Equals, -1)
|
||||
c.Check(compareLexicographic("prb", "pra"), Equals, 1)
|
||||
|
||||
c.Check(compareLexicographic("prx", "pr+"), Equals, -1)
|
||||
c.Check(compareLexicographic("pr+", "prx"), Equals, 1)
|
||||
|
||||
c.Check(compareLexicographic("pr~", "pra"), Equals, -1)
|
||||
c.Check(compareLexicographic("pra", "pr~"), Equals, 1)
|
||||
|
||||
c.Check(compareLexicographic("~~", "~~a"), Equals, -1)
|
||||
c.Check(compareLexicographic("~~a", "~"), Equals, -1)
|
||||
c.Check(compareLexicographic("~", ""), Equals, -1)
|
||||
|
||||
c.Check(compareLexicographic("~~a", "~~"), Equals, 1)
|
||||
c.Check(compareLexicographic("~", "~~a"), Equals, 1)
|
||||
c.Check(compareLexicographic("", "~"), Equals, 1)
|
||||
}
|
||||
|
||||
func (s *VersionSuite) TestCompareVersionPart(c *C) {
|
||||
c.Check(compareVersionPart("", ""), Equals, 0)
|
||||
c.Check(compareVersionPart("pre", "pre"), Equals, 0)
|
||||
c.Check(compareVersionPart("12", "12"), Equals, 0)
|
||||
c.Check(compareVersionPart("1.3.5", "1.3.5"), Equals, 0)
|
||||
c.Check(compareVersionPart("1.3.5-pre1", "1.3.5-pre1"), Equals, 0)
|
||||
|
||||
c.Check(compareVersionPart("1.0~beta1~svn1245", "1.0~beta1"), Equals, -1)
|
||||
c.Check(compareVersionPart("1.0~beta1", "1.0"), Equals, -1)
|
||||
|
||||
c.Check(compareVersionPart("1.0~beta1", "1.0~beta1~svn1245"), Equals, 1)
|
||||
c.Check(compareVersionPart("1.0", "1.0~beta1"), Equals, 1)
|
||||
|
||||
c.Check(compareVersionPart("1.pr", "1.pre"), Equals, -1)
|
||||
c.Check(compareVersionPart("1.pre", "1.pr"), Equals, 1)
|
||||
|
||||
c.Check(compareVersionPart("1.pra", "1.prb"), Equals, -1)
|
||||
c.Check(compareVersionPart("1.prb", "1.pra"), Equals, 1)
|
||||
|
||||
c.Check(compareVersionPart("3.prx", "3.pr+"), Equals, -1)
|
||||
c.Check(compareVersionPart("3.pr+", "3.prx"), Equals, 1)
|
||||
|
||||
c.Check(compareVersionPart("3.pr~", "3.pra"), Equals, -1)
|
||||
c.Check(compareVersionPart("3.pra", "3.pr~"), Equals, 1)
|
||||
|
||||
c.Check(compareVersionPart("2~~", "2~~a"), Equals, -1)
|
||||
c.Check(compareVersionPart("2~~a", "2~"), Equals, -1)
|
||||
c.Check(compareVersionPart("2~", "2"), Equals, -1)
|
||||
|
||||
c.Check(compareVersionPart("2~~a", "2~~"), Equals, 1)
|
||||
c.Check(compareVersionPart("2~", "2~~a"), Equals, 1)
|
||||
c.Check(compareVersionPart("2", "2~"), Equals, 1)
|
||||
}
|
||||
|
||||
func (s *VersionSuite) TestCompareVersions(c *C) {
|
||||
c.Check(CompareVersions("3:1.0~beta1~svn1245-1", "3:1.0~beta1~svn1245-1"), Equals, 0)
|
||||
|
||||
c.Check(CompareVersions("1:1.0~beta1~svn1245-1", "3:1.0~beta1~svn1245-1"), Equals, -1)
|
||||
c.Check(CompareVersions("1:1.0~beta1~svn1245-1", "1.0~beta1~svn1245-1"), Equals, 1)
|
||||
c.Check(CompareVersions("1.0~beta1~svn1245-1", "1.0~beta1~svn1245-2"), Equals, -1)
|
||||
c.Check(CompareVersions("3:1.0~beta1~svn1245-1", "3:1.0~beta1-1"), Equals, -1)
|
||||
|
||||
c.Check(CompareVersions("1.0~beta1~svn1245", "1.0~beta1"), Equals, -1)
|
||||
c.Check(CompareVersions("1.0~beta1", "1.0"), Equals, -1)
|
||||
}
|
||||
|
||||
func (s *VersionSuite) TestParseDependency(c *C) {
|
||||
d, e := ParseDependency("dpkg (>= 1.6)")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(d.Pkg, Equals, "dpkg")
|
||||
c.Check(d.Relation, Equals, VersionGreaterOrEqual)
|
||||
c.Check(d.Version, Equals, "1.6")
|
||||
|
||||
d, e = ParseDependency("dpkg(>>1.6)")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(d.Pkg, Equals, "dpkg")
|
||||
c.Check(d.Relation, Equals, VersionGreater)
|
||||
c.Check(d.Version, Equals, "1.6")
|
||||
|
||||
d, e = ParseDependency("dpkg (> 1.6)")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(d.Pkg, Equals, "dpkg")
|
||||
c.Check(d.Relation, Equals, VersionGreaterOrEqual)
|
||||
c.Check(d.Version, Equals, "1.6")
|
||||
|
||||
d, e = ParseDependency("dpkg (< 1.6)")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(d.Pkg, Equals, "dpkg")
|
||||
c.Check(d.Relation, Equals, VersionLessOrEqual)
|
||||
c.Check(d.Version, Equals, "1.6")
|
||||
|
||||
d, e = ParseDependency("dpkg (= 1.6)")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(d.Pkg, Equals, "dpkg")
|
||||
c.Check(d.Relation, Equals, VersionEqual)
|
||||
c.Check(d.Version, Equals, "1.6")
|
||||
|
||||
d, e = ParseDependency("dpkg (<< 1.6)")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(d.Pkg, Equals, "dpkg")
|
||||
c.Check(d.Relation, Equals, VersionLess)
|
||||
c.Check(d.Version, Equals, "1.6")
|
||||
|
||||
d, e = ParseDependency("dpkg(>>1.6)")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(d.Pkg, Equals, "dpkg")
|
||||
c.Check(d.Relation, Equals, VersionGreater)
|
||||
c.Check(d.Version, Equals, "1.6")
|
||||
|
||||
d, e = ParseDependency("dpkg ")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(d.Pkg, Equals, "dpkg")
|
||||
c.Check(d.Relation, Equals, VersionDontCare)
|
||||
c.Check(d.Version, Equals, "")
|
||||
|
||||
d, e = ParseDependency("dpkg(==1.6)")
|
||||
c.Check(e, ErrorMatches, "relation unknown.*")
|
||||
|
||||
d, e = ParseDependency("dpkg==1.6)")
|
||||
c.Check(e, ErrorMatches, "unable to parse.*")
|
||||
}
|
||||
|
||||
func (s *VersionSuite) TestParseDependencyVariants(c *C) {
|
||||
l, e := ParseDependencyVariants("dpkg (>= 1.6)")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(l, HasLen, 1)
|
||||
c.Check(l[0].Pkg, Equals, "dpkg")
|
||||
c.Check(l[0].Relation, Equals, VersionGreaterOrEqual)
|
||||
c.Check(l[0].Version, Equals, "1.6")
|
||||
|
||||
l, e = ParseDependencyVariants("dpkg (>= 1.6) | mailer-agent")
|
||||
c.Check(e, IsNil)
|
||||
c.Check(l, HasLen, 2)
|
||||
c.Check(l[0].Pkg, Equals, "dpkg")
|
||||
c.Check(l[0].Relation, Equals, VersionGreaterOrEqual)
|
||||
c.Check(l[0].Version, Equals, "1.6")
|
||||
c.Check(l[1].Pkg, Equals, "mailer-agent")
|
||||
c.Check(l[1].Relation, Equals, VersionDontCare)
|
||||
|
||||
_, e = ParseDependencyVariants("dpkg(==1.6)")
|
||||
c.Check(e, ErrorMatches, "relation unknown.*")
|
||||
}
|
||||
|
||||
func (s *VersionSuite) TestDependencyString(c *C) {
|
||||
d, _ := ParseDependency("dpkg(>>1.6)")
|
||||
d.Architecture = "i386"
|
||||
c.Check(d.String(), Equals, "dpkg (>> 1.6) [i386]")
|
||||
|
||||
d, _ = ParseDependency("dpkg")
|
||||
d.Architecture = "i386"
|
||||
c.Check(d.String(), Equals, "dpkg [i386]")
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/database"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/smira/aptly/utils"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// aptly version
|
||||
const Version = "0.1"
|
||||
const Version = "0.3"
|
||||
|
||||
var cmd *commander.Command
|
||||
|
||||
@@ -21,7 +22,7 @@ func init() {
|
||||
UsageLine: os.Args[0],
|
||||
Short: "Debian repository management tool",
|
||||
Long: `
|
||||
aptly allows to create partial and full mirrors of remote
|
||||
aptly is a tool to create partial and full mirrors of remote
|
||||
repositories, filter them, merge, upgrade individual packages,
|
||||
take snapshots and publish them back as Debian repositories.`,
|
||||
Flag: *flag.NewFlagSet("aptly", flag.ExitOnError),
|
||||
@@ -29,55 +30,97 @@ take snapshots and publish them back as Debian repositories.`,
|
||||
makeCmdMirror(),
|
||||
makeCmdSnapshot(),
|
||||
makeCmdPublish(),
|
||||
makeCmdServe(),
|
||||
makeCmdGraph(),
|
||||
makeCmdVersion(),
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("dep-follow-suggests", false, "when processing dependencies, follow Suggests")
|
||||
cmd.Flag.Bool("dep-follow-recommends", false, "when processing dependencies, follow Recommends")
|
||||
cmd.Flag.Bool("dep-follow-all-variants", false, "when processing dependencies, follow a & b if depdency is 'a|b'")
|
||||
cmd.Flag.String("architectures", "", "list of architectures to consider during (comma-separated), default to all available")
|
||||
cmd.Flag.String("config", "", "location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)")
|
||||
}
|
||||
|
||||
var context struct {
|
||||
downloader utils.Downloader
|
||||
database database.Storage
|
||||
packageRepository *debian.Repository
|
||||
dependencyOptions int
|
||||
architecturesList []string
|
||||
}
|
||||
|
||||
func fatal(err error) {
|
||||
fmt.Printf("ERROR: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := cmd.Flag.Parse(os.Args[1:])
|
||||
if err != nil {
|
||||
log.Fatalf("%s", err)
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
configLocations := []string{
|
||||
filepath.Join(os.Getenv("HOME"), ".aptly.conf"),
|
||||
"/etc/aptly.conf",
|
||||
}
|
||||
|
||||
for _, configLocation := range configLocations {
|
||||
configLocation := cmd.Flag.Lookup("config").Value.String()
|
||||
if configLocation != "" {
|
||||
err = utils.LoadConfig(configLocation, &utils.Config)
|
||||
if err == nil {
|
||||
break
|
||||
|
||||
if err != nil {
|
||||
fatal(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))
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Config file not found, creating default config at %s\n\n", configLocations[0])
|
||||
utils.SaveConfig(configLocations[0], &utils.Config)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Config file not found, creating default config at %s\n\n", configLocations[0])
|
||||
utils.SaveConfig(configLocations[0], &utils.Config)
|
||||
context.dependencyOptions = 0
|
||||
if utils.Config.DepFollowSuggests || cmd.Flag.Lookup("dep-follow-suggests").Value.Get().(bool) {
|
||||
context.dependencyOptions |= debian.DepFollowSuggests
|
||||
}
|
||||
if utils.Config.DepFollowRecommends || cmd.Flag.Lookup("dep-follow-recommends").Value.Get().(bool) {
|
||||
context.dependencyOptions |= debian.DepFollowRecommends
|
||||
}
|
||||
if utils.Config.DepFollowAllVariants || cmd.Flag.Lookup("dep-follow-all-variants").Value.Get().(bool) {
|
||||
context.dependencyOptions |= debian.DepFollowAllVariants
|
||||
}
|
||||
|
||||
context.architecturesList = utils.Config.Architectures
|
||||
optionArchitectures := cmd.Flag.Lookup("architectures").Value.String()
|
||||
if optionArchitectures != "" {
|
||||
context.architecturesList = strings.Split(optionArchitectures, ",")
|
||||
}
|
||||
|
||||
context.downloader = utils.NewDownloader(utils.Config.DownloadConcurrency)
|
||||
defer context.downloader.Shutdown()
|
||||
|
||||
// TODO: configure DB dir
|
||||
context.database, err = database.OpenDB(filepath.Join(utils.Config.RootDir, "db"))
|
||||
if err != nil {
|
||||
log.Fatalf("can't open database: %s", err)
|
||||
fatal(fmt.Errorf("can't open database: %s", err))
|
||||
}
|
||||
defer context.database.Close()
|
||||
|
||||
// TODO:configure pool dir
|
||||
context.packageRepository = debian.NewRepository(utils.Config.RootDir)
|
||||
|
||||
err = cmd.Dispatch(os.Args[1:])
|
||||
err = cmd.Dispatch(cmd.Flag.Args())
|
||||
if err != nil {
|
||||
log.Fatalf("%s", err)
|
||||
fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
System test for aptly
|
||||
Binary file not shown.
@@ -0,0 +1,19 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1.4.5 (GNU/Linux)
|
||||
|
||||
mQGiBE9p65cRBACFOL5YS4kW6xieXa98meE+RVu1hfBi1n7ajAy+ZQOfNa2Xb9if
|
||||
H8WAcwJD4cTZYB19/O/xVxCYf1hnC/T34XGC5PUzMzBDKde86UDqvT4YNHDQA/E1
|
||||
I6UUzE0MgLINO4Dt7Mw62koVrlPXklc2Zn83ucZB7YgBzJOIBFUQLghikwCgnubS
|
||||
n/9lw8Hm8CIsg4nWtHwHGPED/jXIsH7ON3PBx2wIdRsealsx5sPGHQSlq1grRHcN
|
||||
YT5/glXmVqnexY/+IFhcpjjb3vMMQ5LYq8+bDWGVMQx3GZrJs66rwPbo4kZ92OdC
|
||||
RTnY/nznJlf5gS86DaFl+NFuO7F1k8ju4CurXXGXPF7nk8cgV6CrYHz1AtNyLVqa
|
||||
306IA/9j9rdD/MY9SYT16eFMo7C2ieIS0RxxU3q9w0e8EucQKiHWMtjTPJ0Ik0GO
|
||||
TY5lAPasnD6ZBA15XSiTi2Ck2QoZQZCxdtId/nL7lNG4+vQ8HACNDkxxK4yHJiFa
|
||||
frMdlWi5cYgAMYzbYPekbhaamDR7Gh4NU7z72QZTPELKyZD/pbRGaG9tZTpEZWVw
|
||||
RGl2ZXIxOTc1IE9CUyBQcm9qZWN0IDxob21lOkRlZXBEaXZlcjE5NzVAYnVpbGQu
|
||||
b3BlbnN1c2Uub3JnPohlBBMRAgAmBQJPaeuXAhsDBQkEHrAABgsJCAcDAgQVAggD
|
||||
BBYCAwECHgECF4AACgkQuCWWGBBIwf+tEgCcDEzTAilZDvOr0OKHHmguuKFXoHMA
|
||||
ljX7B6nKOYoiHoGpBeOwr8U5ZB6IRgQTEQIABgUCT2nrlwAKCRA7MBG3a51lI7Rt
|
||||
AJ4mYeomQiHHfd+7c8T0JhbGKUIDlACglHyTlouU5vCpUEHDyLvwrHFylpk=
|
||||
=b/6f
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
@@ -0,0 +1,14 @@
|
||||
aptly -architectures=i386,amd64 mirror create wheezy-main http://mirror.yandex.ru/debian/ wheezy main
|
||||
aptly -architectures=i386,amd64 mirror create wheezy-contrib http://mirror.yandex.ru/debian/ wheezy contrib
|
||||
aptly -architectures=i386,amd64 mirror create wheezy-non-free http://mirror.yandex.ru/debian/ wheezy non-free
|
||||
aptly -architectures=i386,amd64 mirror create wheezy-updates http://mirror.yandex.ru/debian/ wheezy-updates
|
||||
aptly -architectures=i386,amd64 mirror create wheezy-backports http://mirror.yandex.ru/debian/ wheezy-backports
|
||||
|
||||
aptly mirror update wheezy-main
|
||||
aptly mirror update wheezy-contrib
|
||||
aptly mirror update wheezy-non-free
|
||||
aptly mirror update wheezy-updates
|
||||
aptly mirror update wheezy-backports
|
||||
|
||||
aptly mirror create gnuplot-maverick http://ppa.launchpad.net/gladky-anton/gnuplot/ubuntu/ maverick
|
||||
aptly mirror update gnuplot-maverick
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
"""
|
||||
Test library.
|
||||
"""
|
||||
|
||||
import difflib
|
||||
import inspect
|
||||
import json
|
||||
import subprocess
|
||||
import os
|
||||
import posixpath
|
||||
import shlex
|
||||
import shutil
|
||||
import string
|
||||
import threading
|
||||
import urllib
|
||||
import SocketServer
|
||||
import SimpleHTTPServer
|
||||
|
||||
|
||||
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
|
||||
pass
|
||||
|
||||
|
||||
class FileHTTPServerRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
def translate_path(self, path):
|
||||
"""Translate a /-separated PATH to the local filename syntax.
|
||||
|
||||
Components that mean special things to the local file system
|
||||
(e.g. drive or directory names) are ignored. (XXX They should
|
||||
probably be diagnosed.)
|
||||
|
||||
"""
|
||||
# abandon query parameters
|
||||
path = path.split('?', 1)[0]
|
||||
path = path.split('#', 1)[0]
|
||||
path = posixpath.normpath(urllib.unquote(path))
|
||||
words = path.split('/')
|
||||
words = filter(None, words)
|
||||
path = self.rootPath
|
||||
for word in words:
|
||||
drive, word = os.path.splitdrive(word)
|
||||
head, word = os.path.split(word)
|
||||
if word in (os.curdir, os.pardir):
|
||||
continue
|
||||
path = os.path.join(path, word)
|
||||
return path
|
||||
|
||||
def log_message(self, format, *args):
|
||||
pass
|
||||
|
||||
|
||||
class BaseTest(object):
|
||||
"""
|
||||
Base class for all tests.
|
||||
"""
|
||||
|
||||
longTest = False
|
||||
fixturePool = False
|
||||
fixtureDB = False
|
||||
fixtureGpg = False
|
||||
fixtureWebServer = False
|
||||
|
||||
expectedCode = 0
|
||||
configFile = {
|
||||
"rootDir": "%s/.aptly" % os.environ["HOME"],
|
||||
"downloadConcurrency": 4,
|
||||
"architectures": [],
|
||||
"dependencyFollowSuggests": False,
|
||||
"dependencyFollowRecommends": False,
|
||||
"dependencyFollowAllVariants": False,
|
||||
"gpgDisableVerify": False,
|
||||
"gpgDisableSign": False,
|
||||
}
|
||||
configOverride = {}
|
||||
|
||||
fixtureDBDir = os.path.join(os.environ["HOME"], "aptly-fixture-db")
|
||||
fixturePoolDir = os.path.join(os.environ["HOME"], "aptly-fixture-pool")
|
||||
|
||||
outputMatchPrepare = None
|
||||
|
||||
def test(self):
|
||||
self.prepare()
|
||||
self.run()
|
||||
self.check()
|
||||
|
||||
def prepare_remove_all(self):
|
||||
if os.path.exists(os.path.join(os.environ["HOME"], ".aptly")):
|
||||
shutil.rmtree(os.path.join(os.environ["HOME"], ".aptly"))
|
||||
if os.path.exists(os.path.join(os.environ["HOME"], ".aptly.conf")):
|
||||
os.remove(os.path.join(os.environ["HOME"], ".aptly.conf"))
|
||||
if os.path.exists(os.path.join(os.environ["HOME"], ".gnupg", "aptlytest.gpg")):
|
||||
os.remove(os.path.join(os.environ["HOME"], ".gnupg", "aptlytest.gpg"))
|
||||
|
||||
def prepare_default_config(self):
|
||||
cfg = self.configFile.copy()
|
||||
cfg.update(**self.configOverride)
|
||||
f = open(os.path.join(os.environ["HOME"], ".aptly.conf"), "w")
|
||||
f.write(json.dumps(cfg))
|
||||
f.close()
|
||||
|
||||
def fixture_available(self):
|
||||
if self.fixturePool and not os.path.exists(self.fixturePoolDir):
|
||||
return False
|
||||
if self.fixtureDB and not os.path.exists(self.fixtureDBDir):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def prepare_fixture(self):
|
||||
if self.fixturePool:
|
||||
os.makedirs(os.path.join(os.environ["HOME"], ".aptly"), 0755)
|
||||
os.symlink(self.fixturePoolDir, os.path.join(os.environ["HOME"], ".aptly", "pool"))
|
||||
|
||||
if self.fixtureDB:
|
||||
shutil.copytree(self.fixtureDBDir, os.path.join(os.environ["HOME"], ".aptly", "db"))
|
||||
|
||||
if self.fixtureWebServer:
|
||||
self.webServerUrl = self.start_webserver(os.path.join(os.path.dirname(inspect.getsourcefile(self.__class__)),
|
||||
self.fixtureWebServer))
|
||||
|
||||
if self.fixtureGpg:
|
||||
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", "flat.key")])
|
||||
|
||||
if hasattr(self, "fixtureCmds"):
|
||||
if self.fixtureWebServer:
|
||||
params = {'url': self.webServerUrl}
|
||||
self.fixtureCmds = [string.Template(cmd).substitute(params) for cmd in self.fixtureCmds]
|
||||
for cmd in self.fixtureCmds:
|
||||
self.run_cmd(cmd)
|
||||
|
||||
def run(self):
|
||||
self.output = self.output_processor(self.run_cmd(self.runCmd, self.expectedCode))
|
||||
|
||||
def run_cmd(self, command, expected_code=0):
|
||||
try:
|
||||
if not hasattr(command, "__iter__"):
|
||||
command = shlex.split(command)
|
||||
environ = os.environ.copy()
|
||||
environ["LC_ALL"] = "C"
|
||||
proc = subprocess.Popen(command, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, env=environ)
|
||||
output, _ = proc.communicate()
|
||||
if proc.returncode != expected_code:
|
||||
raise Exception("exit code %d != %d (output: %s)" % (proc.returncode, expected_code, output))
|
||||
return output
|
||||
except Exception, e:
|
||||
raise Exception("Running command %s failed: %s" % (command, str(e)))
|
||||
|
||||
def gold_processor(self, gold):
|
||||
return gold
|
||||
|
||||
def output_processor(self, output):
|
||||
return output
|
||||
|
||||
def expand_environ(self, gold):
|
||||
return string.Template(gold).substitute(os.environ)
|
||||
|
||||
def get_gold(self, gold_name="gold"):
|
||||
gold = os.path.join(os.path.dirname(inspect.getsourcefile(self.__class__)), self.__class__.__name__ + "_" + gold_name)
|
||||
return self.gold_processor(open(gold, "r").read())
|
||||
|
||||
def check_output(self):
|
||||
self.verify_match(self.get_gold(), self.output, match_prepare=self.outputMatchPrepare)
|
||||
|
||||
def check_cmd_output(self, command, gold_name, match_prepare=None, expected_code=0):
|
||||
self.verify_match(self.get_gold(gold_name), self.run_cmd(command, expected_code=expected_code), match_prepare)
|
||||
|
||||
def read_file(self, path):
|
||||
with open(os.path.join(os.environ["HOME"], ".aptly", path), "r") as f:
|
||||
return f.read()
|
||||
|
||||
def check_file_contents(self, path, gold_name, match_prepare=None):
|
||||
contents = self.read_file(path)
|
||||
|
||||
self.verify_match(self.get_gold(gold_name), contents, match_prepare=match_prepare)
|
||||
|
||||
def check_file(self):
|
||||
self.verify_match(self.get_gold(), open(self.checkedFile, "r").read())
|
||||
|
||||
def check_exists(self, path):
|
||||
if not os.path.exists(os.path.join(os.environ["HOME"], ".aptly", path)):
|
||||
raise Exception("path %s doesn't exist" % (path, ))
|
||||
|
||||
def check_not_exists(self, path):
|
||||
if os.path.exists(os.path.join(os.environ["HOME"], ".aptly", path)):
|
||||
raise Exception("path %s exists" % (path, ))
|
||||
|
||||
def verify_match(self, a, b, match_prepare=None):
|
||||
if match_prepare is not None:
|
||||
a = match_prepare(a)
|
||||
b = match_prepare(b)
|
||||
|
||||
if a != b:
|
||||
diff = "".join(difflib.unified_diff([l + "\n" for l in a.split("\n")], [l + "\n" for l in b.split("\n")]))
|
||||
|
||||
raise Exception("content doesn't match:\n" + diff + "\n")
|
||||
|
||||
check = check_output
|
||||
|
||||
def prepare(self):
|
||||
self.prepare_remove_all()
|
||||
self.prepare_default_config()
|
||||
self.prepare_fixture()
|
||||
|
||||
def start_webserver(self, directory):
|
||||
FileHTTPServerRequestHandler.rootPath = directory
|
||||
self.webserver = ThreadedTCPServer(("localhost", 0), FileHTTPServerRequestHandler)
|
||||
|
||||
server_thread = threading.Thread(target=self.webserver.serve_forever)
|
||||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
|
||||
return "http://%s:%d/" % self.webserver.server_address
|
||||
|
||||
def shutdown(self):
|
||||
if hasattr(self, 'webserver'):
|
||||
self.shutdown_webserver()
|
||||
|
||||
def shutdown_webserver(self):
|
||||
self.webserver.shutdown()
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
#!/usr/local/bin/python
|
||||
|
||||
import glob
|
||||
import importlib
|
||||
import os
|
||||
import inspect
|
||||
import sys
|
||||
|
||||
from lib import BaseTest
|
||||
|
||||
try:
|
||||
from termcolor import colored
|
||||
except ImportError:
|
||||
def colored(s, **kwargs):
|
||||
return s
|
||||
|
||||
|
||||
def run(include_long_tests=False, tests=None):
|
||||
"""
|
||||
Run system test.
|
||||
"""
|
||||
if tests is None:
|
||||
tests = glob.glob("t*_*")
|
||||
fails = []
|
||||
numTests = numFailed = numSkipped = 0
|
||||
|
||||
for test in tests:
|
||||
|
||||
testModule = importlib.import_module(test)
|
||||
|
||||
for name in dir(testModule):
|
||||
o = getattr(testModule, name)
|
||||
|
||||
if not (inspect.isclass(o) and issubclass(o, BaseTest) and o is not BaseTest):
|
||||
continue
|
||||
|
||||
t = o()
|
||||
if t.longTest and not include_long_tests or not t.fixture_available():
|
||||
numSkipped += 1
|
||||
continue
|
||||
|
||||
numTests += 1
|
||||
|
||||
sys.stdout.write("%s:%s... " % (test, o.__name__))
|
||||
|
||||
try:
|
||||
t.test()
|
||||
except BaseException, e:
|
||||
numFailed += 1
|
||||
fails.append((test, t, e, testModule))
|
||||
sys.stdout.write(colored("FAIL\n", color="red"))
|
||||
else:
|
||||
sys.stdout.write(colored("OK\n", color="green"))
|
||||
|
||||
t.shutdown()
|
||||
|
||||
print "TESTS: %d SUCCESS: %d FAIL: %d SKIP: %d" % (numTests, numTests - numFailed, numFailed, numSkipped)
|
||||
|
||||
if len(fails) > 0:
|
||||
print "\nFAILURES (%d):" % (len(fails), )
|
||||
|
||||
for (test, t, e, testModule) in fails:
|
||||
print "%s:%s %s" % (test, t.__class__.__name__, testModule.__doc__.strip() + ": " + t.__doc__.strip())
|
||||
print "ERROR: %s" % (e, )
|
||||
print "=" * 60
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.chdir(os.path.realpath(os.path.dirname(sys.argv[0])))
|
||||
include_long_tests = False
|
||||
tests = None
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] == "--long":
|
||||
include_long_tests = True
|
||||
else:
|
||||
tests = sys.argv[1:]
|
||||
run(include_long_tests, tests)
|
||||
@@ -0,0 +1 @@
|
||||
aptly version: 0.3
|
||||
@@ -0,0 +1,13 @@
|
||||
"""
|
||||
Test aptly version
|
||||
"""
|
||||
|
||||
from lib import BaseTest
|
||||
|
||||
|
||||
class VersionTest(BaseTest):
|
||||
"""
|
||||
version should match
|
||||
"""
|
||||
|
||||
runCmd = "aptly version"
|
||||
@@ -0,0 +1 @@
|
||||
ERROR: error loading config file ${HOME}/.aptly.conf: invalid character 's' looking for beginning of object key string
|
||||
@@ -0,0 +1,20 @@
|
||||
aptly - Debian repository management tool
|
||||
|
||||
Commands:
|
||||
|
||||
graph display graph of dependencies between aptly objects (requires graphviz)
|
||||
mirror manage mirrors of remote repositories
|
||||
publish manage published repositories
|
||||
serve start embedded HTTP server to 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-suggests=false: when processing dependencies, follow Suggests
|
||||
@@ -0,0 +1 @@
|
||||
ERROR: open nosuchfile.conf: no such file or directory
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"rootDir": "${HOME}/.aptly",
|
||||
"downloadConcurrency": 4,
|
||||
"architectures": [],
|
||||
"dependencyFollowSuggests": false,
|
||||
"dependencyFollowRecommends": false,
|
||||
"dependencyFollowAllVariants": false,
|
||||
"gpgDisableSign": false,
|
||||
"gpgDisableVerify": false
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Test config file
|
||||
"""
|
||||
|
||||
import os
|
||||
import inspect
|
||||
from lib import BaseTest
|
||||
|
||||
|
||||
class CreateConfigTest(BaseTest):
|
||||
"""
|
||||
new file is generated if missing
|
||||
"""
|
||||
runCmd = "aptly"
|
||||
checkedFile = os.path.join(os.environ["HOME"], ".aptly.conf")
|
||||
|
||||
check = BaseTest.check_file
|
||||
gold_processor = BaseTest.expand_environ
|
||||
prepare = BaseTest.prepare_remove_all
|
||||
|
||||
|
||||
class BadConfigTest(BaseTest):
|
||||
"""
|
||||
broken config file
|
||||
"""
|
||||
runCmd = "aptly"
|
||||
expectedCode = 1
|
||||
|
||||
gold_processor = BaseTest.expand_environ
|
||||
|
||||
def prepare(self):
|
||||
self.prepare_remove_all()
|
||||
|
||||
f = open(os.path.join(os.environ["HOME"], ".aptly.conf"), "w")
|
||||
f.write("{some crap")
|
||||
f.close()
|
||||
|
||||
|
||||
class ConfigInFileTest(BaseTest):
|
||||
"""
|
||||
config in other file test
|
||||
"""
|
||||
runCmd = ["aptly", "-config=%s" % (os.path.join(os.path.dirname(inspect.getsourcefile(BadConfigTest)), "aptly.conf"), )]
|
||||
prepare = BaseTest.prepare_remove_all
|
||||
|
||||
|
||||
class ConfigInMissingFileTest(BaseTest):
|
||||
"""
|
||||
config in other file test
|
||||
"""
|
||||
runCmd = ["aptly", "-config=nosuchfile.conf"]
|
||||
expectedCode = 1
|
||||
prepare = BaseTest.prepare_remove_all
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"rootDir": "/tmp/aptly",
|
||||
"downloadConcurrency": 4,
|
||||
"architectures": [],
|
||||
"dependencyFollowSuggests": false,
|
||||
"dependencyFollowRecommends": false,
|
||||
"dependencyFollowAllVariants": false,
|
||||
"gpgDisableSign": false,
|
||||
"gpgDisableVerify": false
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
aptly is a tool to create partial and full mirrors of remote
|
||||
repositories, filter them, merge, upgrade individual packages,
|
||||
take snapshots and publish them back as Debian repositories.
|
||||
|
||||
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-suggests=false: when processing dependencies, follow Suggests
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
aptly - Debian repository management tool
|
||||
|
||||
Commands:
|
||||
|
||||
graph display graph of dependencies between aptly objects (requires graphviz)
|
||||
mirror manage mirrors of remote repositories
|
||||
publish manage published repositories
|
||||
serve start embedded HTTP server to 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-suggests=false: when processing dependencies, follow Suggests
|
||||
@@ -0,0 +1,11 @@
|
||||
Usage: aptly mirror create <name> <archive url> <distribution> [<component1> ...]
|
||||
|
||||
Create records information about new mirror and fetches Release file (it doesn't download packages).
|
||||
|
||||
ex:
|
||||
$ aptly mirror create wheezy-main http://mirror.yandex.ru/debian/ wheezy main
|
||||
|
||||
Options:
|
||||
-ignore-signatures=false: disable verification of Release file signatures
|
||||
-keyring=: gpg keyring to use when verifying Release file (could be specified multiple times)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Usage: aptly mirror create <name> <archive url> <distribution> [<component1> ...]
|
||||
|
||||
aptly mirror create - create new mirror of Debian repository
|
||||
|
||||
|
||||
Options:
|
||||
-ignore-signatures=false: disable verification of Release file signatures
|
||||
-keyring=: gpg keyring to use when verifying Release file (could be specified multiple times)
|
||||
@@ -0,0 +1,12 @@
|
||||
aptly mirror - manage mirrors of remote repositories
|
||||
|
||||
Commands:
|
||||
|
||||
create create new mirror of Debian repository
|
||||
drop delete remote repository mirror
|
||||
list list mirrors of remote repositories
|
||||
show show details about remote repository mirror
|
||||
update update packages from remote mirror
|
||||
|
||||
Use "mirror help <command>" for more information about a command.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
aptly mirror - manage mirrors of remote repositories
|
||||
|
||||
Commands:
|
||||
|
||||
create create new mirror of Debian repository
|
||||
drop delete remote repository mirror
|
||||
list list mirrors of remote repositories
|
||||
show show details about remote repository mirror
|
||||
update update packages from remote mirror
|
||||
|
||||
Use "mirror help <command>" for more information about a command.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
"""
|
||||
Test help screens
|
||||
"""
|
||||
|
||||
from lib import BaseTest
|
||||
|
||||
|
||||
class MainTest(BaseTest):
|
||||
"""
|
||||
main
|
||||
"""
|
||||
runCmd = "aptly"
|
||||
|
||||
|
||||
class MirrorTest(BaseTest):
|
||||
"""
|
||||
main
|
||||
"""
|
||||
runCmd = "aptly mirror"
|
||||
|
||||
|
||||
class MirrorCreateTest(BaseTest):
|
||||
"""
|
||||
main
|
||||
"""
|
||||
runCmd = "aptly mirror create"
|
||||
|
||||
|
||||
class MainHelpTest(BaseTest):
|
||||
"""
|
||||
main
|
||||
"""
|
||||
runCmd = "aptly help"
|
||||
|
||||
|
||||
class MirrorHelpTest(BaseTest):
|
||||
"""
|
||||
main
|
||||
"""
|
||||
runCmd = "aptly help mirror"
|
||||
|
||||
|
||||
class MirrorCreateHelpTest(BaseTest):
|
||||
"""
|
||||
main
|
||||
"""
|
||||
runCmd = "aptly help mirror create"
|
||||
@@ -0,0 +1,10 @@
|
||||
Downloading http://mirror.yandex.ru/debian-backports/dists/squeeze-backports/InRelease...
|
||||
gpgv: keyblock resource `${HOME}/.gnupg/aptlytest.gpg': file open error
|
||||
gpgv: RSA key ID 46925553
|
||||
gpgv: Can't check signature: public key not found
|
||||
Downloading http://mirror.yandex.ru/debian-backports/dists/squeeze-backports/Release...
|
||||
Downloading http://mirror.yandex.ru/debian-backports/dists/squeeze-backports/Release.gpg...
|
||||
gpgv: keyblock resource `${HOME}/.gnupg/aptlytest.gpg': file open error
|
||||
gpgv: RSA key ID 46925553
|
||||
gpgv: Can't check signature: public key not found
|
||||
ERROR: unable to fetch mirror: verification of detached signature failed: exit status 2
|
||||
@@ -0,0 +1,10 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/squeeze/InRelease...
|
||||
Downloading http://mirror.yandex.ru/debian/dists/squeeze/Release...
|
||||
Downloading http://mirror.yandex.ru/debian/dists/squeeze/Release.gpg...
|
||||
gpgv: RSA key ID 473041FA
|
||||
gpgv: Good signature from "Debian Archive Automatic Signing Key (6.0/squeeze) <ftpmaster@debian.org>"
|
||||
gpgv: RSA key ID B98321F9
|
||||
gpgv: Good signature from "Squeeze Stable Release Key <debian-release@lists.debian.org>"
|
||||
|
||||
Mirror [mirror11]: http://mirror.yandex.ru/debian/ squeeze successfully added.
|
||||
You can run 'aptly mirror update mirror11' to download repository contents.
|
||||
@@ -0,0 +1,18 @@
|
||||
Name: mirror11
|
||||
Archive Root URL: http://mirror.yandex.ru/debian/
|
||||
Distribution: squeeze
|
||||
Components: main, contrib, non-free
|
||||
Architectures: amd64, armel, i386, ia64, kfreebsd-amd64, kfreebsd-i386, mips, mipsel, powerpc, s390, sparc
|
||||
Last update: never
|
||||
|
||||
Information from release file:
|
||||
Architectures: amd64 armel i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 sparc
|
||||
Codename: squeeze
|
||||
Components: main contrib non-free
|
||||
Date: Sat, 19 Oct 2013 13:54:21 UTC
|
||||
Description: Debian 6.0.8 Released 19 October 2013
|
||||
|
||||
Label: Debian
|
||||
Origin: Debian
|
||||
Suite: oldstable
|
||||
Version: 6.0.8
|
||||
@@ -0,0 +1,9 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/squeeze/InRelease...
|
||||
Downloading http://mirror.yandex.ru/debian/dists/squeeze/Release...
|
||||
Downloading http://mirror.yandex.ru/debian/dists/squeeze/Release.gpg...
|
||||
gpgv: keyblock resource `${HOME}/.gnupg/aptlytest.gpg': file open error
|
||||
gpgv: RSA key ID 473041FA
|
||||
gpgv: Can't check signature: public key not found
|
||||
gpgv: RSA key ID B98321F9
|
||||
gpgv: Can't check signature: public key not found
|
||||
ERROR: unable to fetch mirror: verification of detached signature failed: exit status 2
|
||||
@@ -0,0 +1,4 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/wheezy/Release...
|
||||
|
||||
Mirror [mirror13]: http://mirror.yandex.ru/debian/ wheezy successfully added.
|
||||
You can run 'aptly mirror update mirror13' to download repository contents.
|
||||
@@ -0,0 +1,18 @@
|
||||
Name: mirror13
|
||||
Archive Root URL: http://mirror.yandex.ru/debian/
|
||||
Distribution: wheezy
|
||||
Components: main, contrib, non-free
|
||||
Architectures: amd64, armel, armhf, i386, ia64, kfreebsd-amd64, kfreebsd-i386, mips, mipsel, powerpc, s390, s390x, sparc
|
||||
Last update: never
|
||||
|
||||
Information from release file:
|
||||
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
|
||||
Codename: wheezy
|
||||
Components: main contrib non-free
|
||||
Date: Sat, 08 Feb 2014 10:36:03 UTC
|
||||
Description: Debian 7.4 Released 08 February 2014
|
||||
|
||||
Label: Debian
|
||||
Origin: Debian
|
||||
Suite: stable
|
||||
Version: 7.4
|
||||
@@ -0,0 +1,8 @@
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/InRelease...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/Release...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/Release.gpg...
|
||||
gpgv: Signature made Tue May 21 23:01:30 2013 MSK using DSA key ID 1048C1FF
|
||||
gpgv: Good signature from "home:DeepDiver1975 OBS Project <home:DeepDiver1975@build.opensuse.org>"
|
||||
|
||||
Mirror [mirror14]: http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/ successfully added.
|
||||
You can run 'aptly mirror update mirror14' to download repository contents.
|
||||
@@ -0,0 +1,14 @@
|
||||
Name: mirror14
|
||||
Archive Root URL: http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/
|
||||
Distribution:
|
||||
Components:
|
||||
Architectures:
|
||||
Last update: never
|
||||
|
||||
Information from release file:
|
||||
Date: Tue May 21 21:01:30 2013
|
||||
Description: Open Build Service home:DeepDiver1975 xUbuntu_10.04
|
||||
|
||||
Label: DeepDiver1975's Home Project (xUbuntu_10.04)
|
||||
Origin: Open Build Service home:DeepDiver1975 xUbuntu_10.04
|
||||
Version: 0.00
|
||||
@@ -0,0 +1 @@
|
||||
ERROR: unable to create mirror: components aren't supported for flat repos
|
||||
@@ -0,0 +1,4 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/wheezy/Release...
|
||||
|
||||
Mirror [mirror1]: http://mirror.yandex.ru/debian/ wheezy successfully added.
|
||||
You can run 'aptly mirror update mirror1' to download repository contents.
|
||||
@@ -0,0 +1,18 @@
|
||||
Name: mirror1
|
||||
Archive Root URL: http://mirror.yandex.ru/debian/
|
||||
Distribution: wheezy
|
||||
Components: main, contrib, non-free
|
||||
Architectures: amd64, armel, armhf, i386, ia64, kfreebsd-amd64, kfreebsd-i386, mips, mipsel, powerpc, s390, s390x, sparc
|
||||
Last update: never
|
||||
|
||||
Information from release file:
|
||||
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
|
||||
Codename: wheezy
|
||||
Components: main contrib non-free
|
||||
Date: Sat, 08 Feb 2014 10:36:03 UTC
|
||||
Description: Debian 7.4 Released 08 February 2014
|
||||
|
||||
Label: Debian
|
||||
Origin: Debian
|
||||
Suite: stable
|
||||
Version: 7.4
|
||||
@@ -0,0 +1,4 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/wheezy/Release...
|
||||
|
||||
Mirror [mirror2]: http://mirror.yandex.ru/debian/ wheezy successfully added.
|
||||
You can run 'aptly mirror update mirror2' to download repository contents.
|
||||
@@ -0,0 +1,18 @@
|
||||
Name: mirror2
|
||||
Archive Root URL: http://mirror.yandex.ru/debian/
|
||||
Distribution: wheezy
|
||||
Components: main
|
||||
Architectures: amd64, armel, armhf, i386, ia64, kfreebsd-amd64, kfreebsd-i386, mips, mipsel, powerpc, s390, s390x, sparc
|
||||
Last update: never
|
||||
|
||||
Information from release file:
|
||||
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
|
||||
Codename: wheezy
|
||||
Components: main contrib non-free
|
||||
Date: Sat, 08 Feb 2014 10:36:03 UTC
|
||||
Description: Debian 7.4 Released 08 February 2014
|
||||
|
||||
Label: Debian
|
||||
Origin: Debian
|
||||
Suite: stable
|
||||
Version: 7.4
|
||||
@@ -0,0 +1,4 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/wheezy/Release...
|
||||
|
||||
Mirror [mirror3]: http://mirror.yandex.ru/debian/ wheezy successfully added.
|
||||
You can run 'aptly mirror update mirror3' to download repository contents.
|
||||
@@ -0,0 +1,18 @@
|
||||
Name: mirror3
|
||||
Archive Root URL: http://mirror.yandex.ru/debian/
|
||||
Distribution: wheezy
|
||||
Components: main, contrib
|
||||
Architectures: i386, amd64
|
||||
Last update: never
|
||||
|
||||
Information from release file:
|
||||
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
|
||||
Codename: wheezy
|
||||
Components: main contrib non-free
|
||||
Date: Sat, 08 Feb 2014 10:36:03 UTC
|
||||
Description: Debian 7.4 Released 08 February 2014
|
||||
|
||||
Label: Debian
|
||||
Origin: Debian
|
||||
Suite: stable
|
||||
Version: 7.4
|
||||
@@ -0,0 +1,2 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/wheezy/Release...
|
||||
ERROR: unable to fetch mirror: component life not available in repo [mirror4]: http://mirror.yandex.ru/debian/ wheezy
|
||||
@@ -0,0 +1,2 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/wheezy/Release...
|
||||
ERROR: unable to fetch mirror: architecture nano68 not available in repo [mirror5]: http://mirror.yandex.ru/debian/ wheezy
|
||||
@@ -0,0 +1,3 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/suslik/InRelease...
|
||||
Downloading http://mirror.yandex.ru/debian/dists/suslik/Release...
|
||||
ERROR: unable to fetch mirror: HTTP code 404 while fetching http://mirror.yandex.ru/debian/dists/suslik/Release
|
||||
@@ -0,0 +1,4 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/wheezy/Release...
|
||||
|
||||
Mirror [mirror7]: http://mirror.yandex.ru/debian/ wheezy successfully added.
|
||||
You can run 'aptly mirror update mirror7' to download repository contents.
|
||||
@@ -0,0 +1,18 @@
|
||||
Name: mirror7
|
||||
Archive Root URL: http://mirror.yandex.ru/debian/
|
||||
Distribution: wheezy
|
||||
Components: main, contrib
|
||||
Architectures: i386, amd64
|
||||
Last update: never
|
||||
|
||||
Information from release file:
|
||||
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
|
||||
Codename: wheezy
|
||||
Components: main contrib non-free
|
||||
Date: Sat, 08 Feb 2014 10:36:03 UTC
|
||||
Description: Debian 7.4 Released 08 February 2014
|
||||
|
||||
Label: Debian
|
||||
Origin: Debian
|
||||
Suite: stable
|
||||
Version: 7.4
|
||||
@@ -0,0 +1,2 @@
|
||||
Downloading http://mirror.yandex.ru/debian/dists/wheezy/Release...
|
||||
ERROR: unable to add mirror: mirror with name mirror8 already exists
|
||||
@@ -0,0 +1,9 @@
|
||||
Downloading http://mirror.yandex.ru/debian-backports/dists/squeeze-backports/InRelease...
|
||||
gpgv: Signature made Fri Feb 7 06:56:50 2014 MSK using RSA key ID 46925553
|
||||
gpgv: Good signature from "Debian Archive Automatic Signing Key (7.0/wheezy) <ftpmaster@debian.org>"
|
||||
gpg: Signature made Fri Feb 7 06:56:50 2014 MSK using RSA key ID 46925553
|
||||
gpg: Good signature from "Debian Archive Automatic Signing Key (7.0/wheezy) <ftpmaster@debian.org>"
|
||||
gpg: WARNING: Using untrusted key!
|
||||
|
||||
Mirror [mirror9]: http://mirror.yandex.ru/debian-backports/ squeeze-backports successfully added.
|
||||
You can run 'aptly mirror update mirror9' to download repository contents.
|
||||
@@ -0,0 +1,20 @@
|
||||
Name: mirror9
|
||||
Archive Root URL: http://mirror.yandex.ru/debian-backports/
|
||||
Distribution: squeeze-backports
|
||||
Components: main, contrib, non-free
|
||||
Architectures: amd64, armel, i386, ia64, kfreebsd-amd64, kfreebsd-i386, mips, mipsel, powerpc, s390, sparc
|
||||
Last update: never
|
||||
|
||||
Information from release file:
|
||||
Architectures: amd64 armel i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 sparc
|
||||
ButAutomaticUpgrades: yes
|
||||
Codename: squeeze-backports
|
||||
Components: main contrib non-free
|
||||
Date: Fri, 07 Feb 2014 02:56:49 UTC
|
||||
Description: Backports for the Squeeze Distribution
|
||||
|
||||
Label: Debian Backports
|
||||
NotAutomatic: yes
|
||||
Origin: Debian Backports
|
||||
Suite: squeeze-backports
|
||||
Valid-Until: Fri, 14 Feb 2014 02:56:49 UTC
|
||||
@@ -0,0 +1 @@
|
||||
Mirror `mirror1` has been removed.
|
||||
@@ -0,0 +1 @@
|
||||
ERROR: unable to show: mirror with name mirror1 not found
|
||||
@@ -0,0 +1,3 @@
|
||||
Mirror `wheezy-main` was used to create following snapshots:
|
||||
* [wheez]: Snapshot from mirror [wheezy-main]: http://mirror.yandex.ru/debian/ wheezy
|
||||
ERROR: won't delete mirror with snapshots, use -force to override
|
||||
@@ -0,0 +1 @@
|
||||
Mirror `wheezy-main` has been removed.
|
||||
@@ -0,0 +1 @@
|
||||
ERROR: unable to drop: mirror with name mirror1 not found
|
||||
@@ -0,0 +1,6 @@
|
||||
List of mirrors:
|
||||
* [mirror1]: http://mirror.yandex.ru/debian/ wheezy
|
||||
* [mirror2]: http://mirror.yandex.ru/debian/ squeeze
|
||||
* [mirror3]: http://mirror.yandex.ru/debian/ squeeze
|
||||
|
||||
To get more information about mirror, run `aptly mirror show <name>`.
|
||||
@@ -0,0 +1 @@
|
||||
No mirrors found, create one with `aptly mirror create ...`.
|
||||
@@ -0,0 +1,18 @@
|
||||
Name: mirror1
|
||||
Archive Root URL: http://mirror.yandex.ru/debian/
|
||||
Distribution: wheezy
|
||||
Components: main, contrib, non-free
|
||||
Architectures: amd64, armel, armhf, i386, ia64, kfreebsd-amd64, kfreebsd-i386, mips, mipsel, powerpc, s390, s390x, sparc
|
||||
Last update: never
|
||||
|
||||
Information from release file:
|
||||
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
|
||||
Codename: wheezy
|
||||
Components: main contrib non-free
|
||||
Date: Sat, 08 Feb 2014 10:36:03 UTC
|
||||
Description: Debian 7.4 Released 08 February 2014
|
||||
|
||||
Label: Debian
|
||||
Origin: Debian
|
||||
Suite: stable
|
||||
Version: 7.4
|
||||
@@ -0,0 +1 @@
|
||||
ERROR: unable to show: mirror with name mirror-xx not found
|
||||
@@ -0,0 +1,345 @@
|
||||
Name: wheezy-contrib
|
||||
Archive Root URL: http://mirror.yandex.ru/debian/
|
||||
Distribution: wheezy
|
||||
Components: contrib
|
||||
Architectures: i386, amd64
|
||||
Last update: 2014-01-21 19:09:24 MSK
|
||||
Number of packages: 325
|
||||
|
||||
Information from release file:
|
||||
Architectures: amd64 armel armhf i386 ia64 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390 s390x sparc
|
||||
Codename: wheezy
|
||||
Components: main contrib non-free
|
||||
Date: Sat, 14 Dec 2013 10:51:30 UTC
|
||||
Description: Debian 7.3 Released 14 December 2013
|
||||
|
||||
Label: Debian
|
||||
Origin: Debian
|
||||
Suite: stable
|
||||
Version: 7.3
|
||||
Packages:
|
||||
bgoffice-dict-downloader-0.09_all
|
||||
biomaj-watcher-1.2.1-1_all
|
||||
cicero-0.7.2-2_all
|
||||
cl-sql-oracle-6.2.0-1_all
|
||||
cl-umlisp-1:2007ac.2-6_all
|
||||
cl-umlisp-orf-3.3.2-3_all
|
||||
cltl-1.0.26_all
|
||||
crafty-bitmaps-1.0-1_all
|
||||
crafty-books-medium-1.0.debian1-2_all
|
||||
crafty-books-medtosmall-1.0.debian1-2_all
|
||||
crafty-books-small-1.0.debian1-2_all
|
||||
cytadela-data-1.0.1-2_all
|
||||
dynagen-0.11.0-6_all
|
||||
dynare-matlab-4.3.0-2_all
|
||||
esix-1-2_all
|
||||
festvox-don-1.4.0-4_all
|
||||
festvox-en1-1.95-1_all
|
||||
festvox-rablpc16k-1.4.0-2_all
|
||||
festvox-rablpc8k-1.4.0-2_all
|
||||
festvox-us1-1.95-1_all
|
||||
festvox-us2-1.95-1_all
|
||||
festvox-us3-1.95-1_all
|
||||
firmware-b43-installer-1:015-14.1_all
|
||||
firmware-b43-lpphy-installer-1:015-14.1_all
|
||||
firmware-b43legacy-installer-1:015-14.1_all
|
||||
game-data-packager-30_all
|
||||
geoip-database-contrib-1.8_all
|
||||
gns3-0.7.4-1_all
|
||||
gnuvd-gnome-1.0.11-1_all
|
||||
googleearth-package-0.7.0_all
|
||||
horae-071~svn536-1_all
|
||||
hts-voice-nitech-jp-atr503-m001-1.04-1_all
|
||||
hyperspec-1.30+nmu2_all
|
||||
ifeffit-doc-2:1.2.11d-8_all
|
||||
imgtex-0.20050123-8_all
|
||||
java-package-0.50+nmu2_all
|
||||
kcemu-common-0.5.1+dfsg-5_all
|
||||
libgooglecharts-ruby-1.6.8-2_all
|
||||
libgooglecharts-ruby1.8-1.6.8-2_all
|
||||
libjlapack-java-0.8~dfsg-1_all
|
||||
libmtj-java-0.9.14~dfsg-2_all
|
||||
libmtj-java-doc-0.9.14~dfsg-2_all
|
||||
libnetlib-java-0.9.3-1_all
|
||||
libviennacl-dev-1.2.0-2_all
|
||||
libviennacl-doc-1.2.0-2_all
|
||||
linux-wlan-ng-firmware-0.2.9+dfsg-5_all
|
||||
mathematica-fonts-16_all
|
||||
matlab-gdf-0.1.2-2_all
|
||||
matlab-support-0.0.18_all
|
||||
mess-desktop-entries-0.2-2_all
|
||||
netdisco-mibs-installer-1.7.1_all
|
||||
opendict-plugins-lingvosoft-0.8-2_all
|
||||
ora2pg-8.11-1_all
|
||||
phoronix-test-suite-3.8.0-1_all
|
||||
playonlinux-4.1.1-1_all
|
||||
premail-0.46-9_all
|
||||
python-ldap-doc-2.3-2.2_all
|
||||
python-pycuda-doc-2012.1-1_all
|
||||
python-pycuda-headers-2012.1-1_all
|
||||
python-pyopencl-doc-2012.1.dfsg-1_all
|
||||
python-pyopencl-headers-2012.1.dfsg-1_all
|
||||
qmhandle-1.3.2-1_all
|
||||
quake-2_all
|
||||
quake-server-2_all
|
||||
quake3-1.4_all
|
||||
quake3-server-1.4_all
|
||||
raccoon-1.0-1_all
|
||||
ruby-googlecharts-1.6.8-2_all
|
||||
sabnzbdplus-0.6.15-1_all
|
||||
sabnzbdplus-theme-classic-0.6.15-1_all
|
||||
sabnzbdplus-theme-iphone-0.6.15-1_all
|
||||
sabnzbdplus-theme-mobile-0.6.15-1_all
|
||||
sabnzbdplus-theme-plush-0.6.15-1_all
|
||||
sabnzbdplus-theme-smpl-0.6.15-1_all
|
||||
sapgui-package-0.0.10_all
|
||||
sauerbraten-wake6-1.0-1.1_all
|
||||
sdic-2.1.3-22_all
|
||||
sdic-edict-2.1.3-22_all
|
||||
sdic-eijiro-2.1.3-22_all
|
||||
sdic-gene95-2.1.3-22_all
|
||||
series60-remote-0.4.0+dfsg.1-1_all
|
||||
sixpack-1:0.68-1_all
|
||||
sqldeveloper-package-0.2.4_all
|
||||
sugar-etoys-activity-116-3_all
|
||||
susv2-1.1_all
|
||||
susv3-6.1_all
|
||||
tightvnc-java-1.2.7-8_all
|
||||
ttf-mathematica4.1-16_all
|
||||
ttf-mscorefonts-installer-3.4+nmu1_all
|
||||
ttf-root-installer-5.34.00-2_all
|
||||
uqm-russian-1.0.2-5_all
|
||||
vmware-manager-0.2.0-3_all
|
||||
vnc-java-3.3.3r2-8_all
|
||||
vusb-analyzer-1.1-3_all
|
||||
winetricks-0.0+20121030+svn918-1_all
|
||||
wnn7egg-1.02-8_all
|
||||
x-pgp-sig-el-1.3.5.1-4.1_all
|
||||
alien-arena-7.53+dfsg-3_amd64
|
||||
alien-arena-server-7.53+dfsg-3_amd64
|
||||
alsa-firmware-loaders-1.0.25-2_amd64
|
||||
amoeba-1.1-26_amd64
|
||||
assaultcube-1.1.0.4+dfsg2-1_amd64
|
||||
atari800-2.2.1-2_amd64
|
||||
b43-fwcutter-1:015-14.1_amd64
|
||||
basilisk2-0.9.20120331-2_amd64
|
||||
boinc-nvidia-cuda-7.0.27+dfsg-5_amd64
|
||||
cbedic-4.0-3_amd64
|
||||
chocolate-doom-1.7.0-3+b1_amd64
|
||||
conky-all-1.9.0-2_amd64
|
||||
cpp-doc-5:4_amd64
|
||||
cytadela-1.0.1-2_amd64
|
||||
cytadela-dbg-1.0.1-2_amd64
|
||||
dosemu-1.4.0+svn.2080-1_amd64
|
||||
e-uae-0.8.29-WIP4-10_amd64
|
||||
e-uae-dbg-0.8.29-WIP4-10_amd64
|
||||
easyspice-0.6.8-2_amd64
|
||||
exult-1.2-15.2_amd64
|
||||
exult-studio-1.2-15.2_amd64
|
||||
flashplugin-nonfree-1:3.2_amd64
|
||||
frogatto-1.2+dfsg-1+b1_amd64
|
||||
gcc-doc-5:4_amd64
|
||||
gcj-doc-5:4_amd64
|
||||
gfortran-doc-5:4_amd64
|
||||
glx-alternative-fglrx-0.2.2_amd64
|
||||
glx-alternative-mesa-0.2.2_amd64
|
||||
glx-alternative-nvidia-0.2.2_amd64
|
||||
glx-diversions-0.2.2_amd64
|
||||
gnat-doc-5:4_amd64
|
||||
gnome-speech-swift-1:0.4.25-5_amd64
|
||||
gnome-video-arcade-0.8.3-1_amd64
|
||||
gnuboy-sdl-1.0.3-6.1_amd64
|
||||
gnuboy-svga-1.0.3-6.1_amd64
|
||||
gnuboy-x-1.0.3-6.1_amd64
|
||||
gnuvd-1.0.11-1_amd64
|
||||
gobi-loader-0.6-1_amd64
|
||||
gtktrain-0.9b-13_amd64
|
||||
hannah-foo2zjs-1:1_amd64
|
||||
ifeffit-2:1.2.11d-8_amd64
|
||||
isdnactivecards-1:3.9.20060704-11_amd64
|
||||
isight-firmware-tools-1.6-1_amd64
|
||||
iucode-tool-0.8.3-1_amd64
|
||||
ivtv-utils-1.4.1-2_amd64
|
||||
kcemu-0.5.1+dfsg-5_amd64
|
||||
libcplgasgano20-6.1.1-2_amd64
|
||||
libdbd-oracle-perl-1.44-1_amd64
|
||||
libifeffit-perl-2:1.2.11d-8_amd64
|
||||
libpgplot-perl-1:2.21-3_amd64
|
||||
libsocl-contrib-1.0-1.0.1+dfsg-1_amd64
|
||||
libstarpu-contrib-1.0-1.0.1+dfsg-1_amd64
|
||||
libstarpu-contrib-dev-1.0.1+dfsg-1_amd64
|
||||
libstarpu-contribfft-1.0-1.0.1+dfsg-1_amd64
|
||||
libstarpu-contribmpi-1.0-1.0.1+dfsg-1_amd64
|
||||
libsuitesparse-metis-3.1.0-3.1.0-2_amd64
|
||||
libsuitesparse-metis-dbg-3.1.0-2_amd64
|
||||
libsuitesparse-metis-dev-3.1.0-2_amd64
|
||||
libtrain-bin-0.9b-11_amd64
|
||||
libtrain-dev-0.9b-11_amd64
|
||||
libtrain1-0.9b-11_amd64
|
||||
libxnvctrl-dev-304.88-1_amd64
|
||||
libxnvctrl0-304.88-1_amd64
|
||||
libydpdict2-1.0.2-1_amd64
|
||||
libydpdict2-dev-1.0.2-1_amd64
|
||||
lugaru-0~20110520.1+hge4354+dfsg-3_amd64
|
||||
microcode.ctl-1.18~0+nmu2_amd64
|
||||
nvidia-installer-cleanup-20120630+3_amd64
|
||||
nvidia-kernel-common-20120630+3_amd64
|
||||
nvidia-settings-304.88-1_amd64
|
||||
nvidia-settings-legacy-173xx-173.14.35-2_amd64
|
||||
nvidia-support-20120630+3_amd64
|
||||
nvidia-xconfig-304.48-1_amd64
|
||||
pidgin-skype-20110407+svn628+dfsg-1_amd64
|
||||
pidgin-skype-dbg-20110407+svn628+dfsg-1_amd64
|
||||
prism2-usb-firmware-installer-0.2.9+dfsg-5_amd64
|
||||
pvpgn-1.8.1-2.1+b1_amd64
|
||||
python-ifeffit-2:1.2.11d-8_amd64
|
||||
python-pycuda-2012.1-1_amd64
|
||||
python-pyopencl-2012.1.dfsg-1_amd64
|
||||
python3-pyopencl-2012.1.dfsg-1_amd64
|
||||
r-cran-surveillance-1.2-1-3_amd64
|
||||
redeclipse-1.2-3_amd64
|
||||
redeclipse-dbg-1.2-3_amd64
|
||||
redeclipse-server-1.2-3_amd64
|
||||
redeclipse-server-dbg-1.2-3_amd64
|
||||
reminiscence-0.2.1-1_amd64
|
||||
rocksndiamonds-3.3.0.1+dfsg1-2.2_amd64
|
||||
rott-1.1.2-1_amd64
|
||||
ruby-pgplot-0.1.3-6_amd64
|
||||
ruby-pgplot-dbg-0.1.3-6_amd64
|
||||
sandboxgamemaker-2.7.1+dfsg-2_amd64
|
||||
sauerbraten-0.0.20100728.dfsg+repack-3_amd64
|
||||
sauerbraten-dbg-0.0.20100728.dfsg+repack-3_amd64
|
||||
sauerbraten-server-0.0.20100728.dfsg+repack-3_amd64
|
||||
spectemu-common-0.94a-15_amd64
|
||||
spectemu-svga-0.94a-15_amd64
|
||||
spectemu-x11-0.94a-15_amd64
|
||||
starpu-contrib-examples-1.0.1+dfsg-1_amd64
|
||||
starpu-contrib-tools-1.0.1+dfsg-1_amd64
|
||||
uae-0.8.29-7_amd64
|
||||
uae-dbg-0.8.29-7_amd64
|
||||
uqm-0.6.2.dfsg-9_amd64
|
||||
vice-2.3.dfsg-4_amd64
|
||||
vmware-view-open-client-4.5.0-297975+dfsg-4+b1_amd64
|
||||
vor-0.5.5-2_amd64
|
||||
wdq2wav-0.8.3-2_amd64
|
||||
wolf4sdl-1.7+svn262+dfsg1-1_amd64
|
||||
xserver-xorg-video-ivtv-1.1.2-1+b3_amd64
|
||||
xserver-xorg-video-ivtv-dbg-1.1.2-1+b3_amd64
|
||||
xtrs-4.9c-3.4_amd64
|
||||
xvba-va-driver-0.8.0-5_amd64
|
||||
ydpdict-1.0.0-2_amd64
|
||||
alien-arena-7.53+dfsg-3_i386
|
||||
alien-arena-server-7.53+dfsg-3_i386
|
||||
alsa-firmware-loaders-1.0.25-2_i386
|
||||
amoeba-1.1-26_i386
|
||||
assaultcube-1.1.0.4+dfsg2-1_i386
|
||||
atari800-2.2.1-2_i386
|
||||
b43-fwcutter-1:015-14.1_i386
|
||||
basilisk2-0.9.20120331-2_i386
|
||||
boinc-nvidia-cuda-7.0.27+dfsg-5_i386
|
||||
cbedic-4.0-3_i386
|
||||
chocolate-doom-1.7.0-3_i386
|
||||
conky-all-1.9.0-2_i386
|
||||
cpp-doc-5:4_i386
|
||||
cytadela-1.0.1-2_i386
|
||||
cytadela-dbg-1.0.1-2_i386
|
||||
dosemu-1.4.0+svn.2080-1_i386
|
||||
e-uae-0.8.29-WIP4-10_i386
|
||||
e-uae-dbg-0.8.29-WIP4-10_i386
|
||||
easyspice-0.6.8-2_i386
|
||||
exult-1.2-15.2_i386
|
||||
exult-studio-1.2-15.2_i386
|
||||
flashplugin-nonfree-1:3.2_i386
|
||||
flashplugin-nonfree-extrasound-0.0.svn2431-3_i386
|
||||
frogatto-1.2+dfsg-1_i386
|
||||
gcc-doc-5:4_i386
|
||||
gcj-doc-5:4_i386
|
||||
gfortran-doc-5:4_i386
|
||||
glx-alternative-fglrx-0.2.2_i386
|
||||
glx-alternative-mesa-0.2.2_i386
|
||||
glx-alternative-nvidia-0.2.2_i386
|
||||
glx-diversions-0.2.2_i386
|
||||
gnat-doc-5:4_i386
|
||||
gnome-speech-dectalk-1:0.4.25-5_i386
|
||||
gnome-speech-ibmtts-1:0.4.25-5_i386
|
||||
gnome-speech-swift-1:0.4.25-5_i386
|
||||
gnome-video-arcade-0.8.3-1_i386
|
||||
gnuboy-sdl-1.0.3-6.1_i386
|
||||
gnuboy-svga-1.0.3-6.1_i386
|
||||
gnuboy-x-1.0.3-6.1_i386
|
||||
gnuvd-1.0.11-1_i386
|
||||
gobi-loader-0.6-1_i386
|
||||
gtktrain-0.9b-13_i386
|
||||
hannah-foo2zjs-1:1_i386
|
||||
ifeffit-2:1.2.11d-8_i386
|
||||
isdnactivecards-1:3.9.20060704-11_i386
|
||||
isight-firmware-tools-1.6-1_i386
|
||||
iucode-tool-0.8.3-1_i386
|
||||
ivtv-utils-1.4.1-2_i386
|
||||
kcemu-0.5.1+dfsg-5_i386
|
||||
libcplgasgano20-6.1.1-2_i386
|
||||
libdbd-oracle-perl-1.44-1_i386
|
||||
libifeffit-perl-2:1.2.11d-8_i386
|
||||
libpgplot-perl-1:2.21-3_i386
|
||||
libsocl-contrib-1.0-1.0.1+dfsg-1_i386
|
||||
libstarpu-contrib-1.0-1.0.1+dfsg-1_i386
|
||||
libstarpu-contrib-dev-1.0.1+dfsg-1_i386
|
||||
libstarpu-contribfft-1.0-1.0.1+dfsg-1_i386
|
||||
libstarpu-contribmpi-1.0-1.0.1+dfsg-1_i386
|
||||
libsuitesparse-metis-3.1.0-3.1.0-2_i386
|
||||
libsuitesparse-metis-dbg-3.1.0-2_i386
|
||||
libsuitesparse-metis-dev-3.1.0-2_i386
|
||||
libtrain-bin-0.9b-11_i386
|
||||
libtrain-dev-0.9b-11_i386
|
||||
libtrain1-0.9b-11_i386
|
||||
libxnvctrl-dev-304.88-1_i386
|
||||
libxnvctrl0-304.88-1_i386
|
||||
libydpdict2-1.0.2-1_i386
|
||||
libydpdict2-dev-1.0.2-1_i386
|
||||
lugaru-0~20110520.1+hge4354+dfsg-3_i386
|
||||
microcode.ctl-1.18~0+nmu2_i386
|
||||
nvidia-installer-cleanup-20120630+3_i386
|
||||
nvidia-kernel-common-20120630+3_i386
|
||||
nvidia-settings-304.88-1_i386
|
||||
nvidia-settings-legacy-173xx-173.14.35-2_i386
|
||||
nvidia-support-20120630+3_i386
|
||||
nvidia-xconfig-304.48-1_i386
|
||||
pidgin-skype-20110407+svn628+dfsg-1_i386
|
||||
pidgin-skype-dbg-20110407+svn628+dfsg-1_i386
|
||||
prism2-usb-firmware-installer-0.2.9+dfsg-5_i386
|
||||
pvpgn-1.8.1-2.1+b1_i386
|
||||
python-ifeffit-2:1.2.11d-8_i386
|
||||
python-pycuda-2012.1-1_i386
|
||||
python-pyopencl-2012.1.dfsg-1_i386
|
||||
python3-pyopencl-2012.1.dfsg-1_i386
|
||||
q-tools-0.4-1_i386
|
||||
r-cran-surveillance-1.2-1-3_i386
|
||||
redeclipse-1.2-3_i386
|
||||
redeclipse-dbg-1.2-3_i386
|
||||
redeclipse-server-1.2-3_i386
|
||||
redeclipse-server-dbg-1.2-3_i386
|
||||
reminiscence-0.2.1-1_i386
|
||||
rocksndiamonds-3.3.0.1+dfsg1-2.2_i386
|
||||
rott-1.1.2-1_i386
|
||||
sandboxgamemaker-2.7.1+dfsg-2_i386
|
||||
sauerbraten-0.0.20100728.dfsg+repack-3_i386
|
||||
sauerbraten-dbg-0.0.20100728.dfsg+repack-3_i386
|
||||
sauerbraten-server-0.0.20100728.dfsg+repack-3_i386
|
||||
spectemu-common-0.94a-15_i386
|
||||
spectemu-svga-0.94a-15_i386
|
||||
spectemu-x11-0.94a-15_i386
|
||||
starpu-contrib-examples-1.0.1+dfsg-1_i386
|
||||
starpu-contrib-tools-1.0.1+dfsg-1_i386
|
||||
uae-0.8.29-7_i386
|
||||
uae-dbg-0.8.29-7_i386
|
||||
uqm-0.6.2.dfsg-9_i386
|
||||
vice-2.3.dfsg-4_i386
|
||||
vmware-view-open-client-4.5.0-297975+dfsg-4+b1_i386
|
||||
vor-0.5.5-2_i386
|
||||
wdq2wav-0.8.3-2_i386
|
||||
wolf4sdl-1.7+svn262+dfsg1-1_i386
|
||||
xserver-xorg-video-ivtv-1.1.2-1+b3_i386
|
||||
xserver-xorg-video-ivtv-dbg-1.1.2-1+b3_i386
|
||||
xtrs-4.9c-3.4_i386
|
||||
xvba-va-driver-0.8.0-5_i386
|
||||
ydpdict-1.0.0-2_i386
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
|
||||
Building download queue...
|
||||
Download queue: 94 items, 0.13 GiB size
|
||||
Downloading & parsing package files...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/dists/hardy/Release...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/dists/hardy/main/binary-amd64/Packages.bz2...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/dists/hardy/main/binary-amd64/Packages.gz...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/dists/hardy/main/binary-i386/Packages.bz2...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/dists/hardy/main/binary-i386/Packages.gz...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-driver/alsa-base_1.0.17.dfsg-2ubuntu1~hardy2_all.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-driver/alsa-source_1.0.17.dfsg-2ubuntu1~hardy2_all.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-driver/linux-sound-base_1.0.17.dfsg-2ubuntu1~hardy2_all.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-lib/lib32asound2-dev_1.0.17a-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-lib/lib32asound2_1.0.17a-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-lib/lib64asound2-dev_1.0.17a-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-lib/lib64asound2_1.0.17a-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-lib/libasound2-dev_1.0.17a-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-lib/libasound2-dev_1.0.17a-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-lib/libasound2-doc_1.0.17a-0ubuntu2~hardy1_all.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-lib/libasound2_1.0.17a-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-lib/libasound2_1.0.17a-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/alsa-firmware-loaders_1.0.17-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/alsa-firmware-loaders_1.0.17-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/alsa-tools-gui_1.0.17-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/alsa-tools-gui_1.0.17-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/alsa-tools_1.0.17-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/alsa-tools_1.0.17-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/ld10k1_1.0.17-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/ld10k1_1.0.17-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/liblo10k1-0_1.0.17-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/liblo10k1-0_1.0.17-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/liblo10k1-dev_1.0.17-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/liblo10k1-dev_1.0.17-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/qlo10k1_1.0.17-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-tools/qlo10k1_1.0.17-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-utils/alsa-utils_1.0.17-0ubuntu2~hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/a/alsa-utils/alsa-utils_1.0.17-0ubuntu2~hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-386_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-generic_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-generic_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-openvz_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-openvz_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-rt_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-rt_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-server_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-server_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-virtual_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-xen_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-19-xen_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-386_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-generic_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-generic_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-openvz_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-openvz_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-rt_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-rt_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-server_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-server_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-virtual_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-xen_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-headers-lum-2.6.24-21-xen_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-386_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-generic_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-generic_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-openvz_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-openvz_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-rt_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-rt_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-server_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-server_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-virtual_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-xen_2.6.24-19.28+hyper1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-19-xen_2.6.24-19.28+hyper1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-386_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-generic_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-generic_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-openvz_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-openvz_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-rt_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-rt_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-server_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-server_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-virtual_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-xen_2.6.24-21.32+hardy1_amd64.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/linux-ubuntu-modules-2.6.24-21-xen_2.6.24-21.32+hardy1_i386.deb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/nic-firmware-2.6.24-19-386-di_2.6.24-19.28+hyper1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/nic-firmware-2.6.24-19-generic-di_2.6.24-19.28+hyper1_amd64.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/nic-firmware-2.6.24-19-generic-di_2.6.24-19.28+hyper1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/nic-firmware-2.6.24-21-386-di_2.6.24-21.32+hardy1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/nic-firmware-2.6.24-21-generic-di_2.6.24-21.32+hardy1_amd64.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/nic-firmware-2.6.24-21-generic-di_2.6.24-21.32+hardy1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/scsi-firmware-2.6.24-19-386-di_2.6.24-19.28+hyper1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/scsi-firmware-2.6.24-19-generic-di_2.6.24-19.28+hyper1_amd64.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/scsi-firmware-2.6.24-19-generic-di_2.6.24-19.28+hyper1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/scsi-firmware-2.6.24-21-386-di_2.6.24-21.32+hardy1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/scsi-firmware-2.6.24-21-generic-di_2.6.24-21.32+hardy1_amd64.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/scsi-firmware-2.6.24-21-generic-di_2.6.24-21.32+hardy1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/ubuntu-modules-2.6.24-19-386-di_2.6.24-19.28+hyper1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/ubuntu-modules-2.6.24-19-generic-di_2.6.24-19.28+hyper1_amd64.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/ubuntu-modules-2.6.24-19-generic-di_2.6.24-19.28+hyper1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/ubuntu-modules-2.6.24-21-386-di_2.6.24-21.32+hardy1_i386.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/ubuntu-modules-2.6.24-21-generic-di_2.6.24-21.32+hardy1_amd64.udeb...
|
||||
Downloading http://ppa.launchpad.net/alsa-backports/ubuntu/pool/main/l/linux-ubuntu-modules-2.6.24/ubuntu-modules-2.6.24-21-generic-di_2.6.24-21.32+hardy1_i386.udeb...
|
||||
Mirror `alsa-ppa` has been successfully updated.
|
||||
Saving packages to database...
|
||||
@@ -0,0 +1 @@
|
||||
ERROR: unable to update: mirror with name mirror-xyz not found
|
||||
@@ -0,0 +1,6 @@
|
||||
Downloading ${url}dists/hardy/Release...
|
||||
Downloading & parsing package files...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages.bz2...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages.gz...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages...
|
||||
ERROR: unable to update: ${url}dists/hardy/main/binary-amd64/Packages: sha256 hash mismatch "494414ded24da13c451b13b424928821351c78fce49f93d9e1b55f102790c206" != "8a21688ae769f2b4ffcaa366409f679d"
|
||||
@@ -0,0 +1,7 @@
|
||||
Downloading ${url}dists/hardy/Release...
|
||||
Downloading & parsing package files...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages.bz2...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages.gz...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages...
|
||||
WARNING: ${url}dists/hardy/main/binary-amd64/Packages: sha256 hash mismatch "494414ded24da13c451b13b424928821351c78fce49f93d9e1b55f102790c206" != "8a21688ae769f2b4ffcaa366409f679d"
|
||||
ERROR: unable to update: malformed stanza syntax
|
||||
@@ -0,0 +1,12 @@
|
||||
Downloading ${url}dists/hardy/Release...
|
||||
Downloading & parsing package files...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages.bz2...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages.gz...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages...
|
||||
Saving packages to database...
|
||||
Building download queue...
|
||||
Download queue: 1 items, 0.00 GiB size
|
||||
Downloading ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb...
|
||||
ERROR: unable to update: download errors:
|
||||
${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb: sha1 hash mismatch "8d3a014000038725d6daf8771b42a0784253688f" != "66b27417d37e024c46526c2f6d358a754fc552f3"
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
Downloading ${url}dists/hardy/Release...
|
||||
Downloading & parsing package files...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages.bz2...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages.gz...
|
||||
Downloading ${url}dists/hardy/main/binary-amd64/Packages...
|
||||
Saving packages to database...
|
||||
Building download queue...
|
||||
Download queue: 1 items, 0.00 GiB size
|
||||
Downloading ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb...
|
||||
WARNING: ${url}pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb: sha1 hash mismatch "8d3a014000038725d6daf8771b42a0784253688f" != "66b27417d37e024c46526c2f6d358a754fc552f3"
|
||||
|
||||
Mirror `failure` has been successfully updated.
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
Building download queue...
|
||||
Download queue: 4 items, 0.00 GiB size
|
||||
Downloading & parsing package files...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/InRelease...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/Packages.bz2...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/Packages.gz...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/Release...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/Release.gpg...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/amd64/libiniparser-dev_3.1-1_amd64.deb...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/amd64/libiniparser_3.1-1_amd64.deb...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/i386/libiniparser-dev_3.1-1_i386.deb...
|
||||
Downloading http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/i386/libiniparser_3.1-1_i386.deb...
|
||||
Mirror `flat` has been successfully updated.
|
||||
Saving packages to database...
|
||||
gpgv: Good signature from "home:DeepDiver1975 OBS Project <home:DeepDiver1975@build.opensuse.org>"
|
||||
gpgv: Signature made Tue May 21 23:01:30 2013 MSK using DSA key ID 1048C1FF
|
||||
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
Testing mirror management
|
||||
"""
|
||||
|
||||
from .create import *
|
||||
from .show import *
|
||||
from .list import *
|
||||
from .update import *
|
||||
from .drop import *
|
||||
@@ -0,0 +1,170 @@
|
||||
import re
|
||||
|
||||
from lib import BaseTest
|
||||
|
||||
|
||||
class CreateMirror1Test(BaseTest):
|
||||
"""
|
||||
create mirror: all architectures + all components
|
||||
"""
|
||||
runCmd = "aptly mirror create --ignore-signatures mirror1 http://mirror.yandex.ru/debian/ wheezy"
|
||||
|
||||
def check(self):
|
||||
self.check_output()
|
||||
self.check_cmd_output("aptly mirror show mirror1", "mirror_show")
|
||||
|
||||
|
||||
class CreateMirror2Test(BaseTest):
|
||||
"""
|
||||
create mirror: all architectures and 1 component
|
||||
"""
|
||||
runCmd = "aptly mirror create --ignore-signatures mirror2 http://mirror.yandex.ru/debian/ wheezy main"
|
||||
|
||||
def check(self):
|
||||
self.check_output()
|
||||
self.check_cmd_output("aptly mirror show mirror2", "mirror_show")
|
||||
|
||||
|
||||
class CreateMirror3Test(BaseTest):
|
||||
"""
|
||||
create mirror: some architectures and 2 components
|
||||
"""
|
||||
runCmd = "aptly -architectures=i386,amd64 mirror create --ignore-signatures mirror3 http://mirror.yandex.ru/debian/ wheezy main contrib"
|
||||
|
||||
def check(self):
|
||||
self.check_output()
|
||||
self.check_cmd_output("aptly mirror show mirror3", "mirror_show")
|
||||
|
||||
|
||||
class CreateMirror4Test(BaseTest):
|
||||
"""
|
||||
create mirror: missing component
|
||||
"""
|
||||
expectedCode = 1
|
||||
|
||||
runCmd = "aptly -architectures=i386,amd64 mirror create --ignore-signatures mirror4 http://mirror.yandex.ru/debian/ wheezy life"
|
||||
|
||||
|
||||
class CreateMirror5Test(BaseTest):
|
||||
"""
|
||||
create mirror: missing architecture
|
||||
"""
|
||||
expectedCode = 1
|
||||
|
||||
runCmd = "aptly -architectures=i386,nano68 mirror create --ignore-signatures mirror5 http://mirror.yandex.ru/debian/ wheezy"
|
||||
|
||||
|
||||
class CreateMirror6Test(BaseTest):
|
||||
"""
|
||||
create mirror: missing release
|
||||
"""
|
||||
expectedCode = 1
|
||||
|
||||
runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror6 http://mirror.yandex.ru/debian/ suslik"
|
||||
|
||||
|
||||
class CreateMirror7Test(BaseTest):
|
||||
"""
|
||||
create mirror: architectures fixed via config file
|
||||
"""
|
||||
runCmd = "aptly mirror create --ignore-signatures mirror7 http://mirror.yandex.ru/debian/ wheezy main contrib"
|
||||
configOverride = {"architectures": ["i386", "amd64"]}
|
||||
|
||||
def check(self):
|
||||
self.check_output()
|
||||
self.check_cmd_output("aptly mirror show mirror7", "mirror_show")
|
||||
|
||||
|
||||
class CreateMirror8Test(BaseTest):
|
||||
"""
|
||||
create mirror: already exists
|
||||
"""
|
||||
fixtureCmds = [
|
||||
"aptly mirror create --ignore-signatures mirror8 http://mirror.yandex.ru/debian/ wheezy main contrib"
|
||||
]
|
||||
runCmd = "aptly mirror create --ignore-signatures mirror8 http://mirror.yandex.ru/debian/ wheezy main contrib"
|
||||
expectedCode = 1
|
||||
|
||||
|
||||
class CreateMirror9Test(BaseTest):
|
||||
"""
|
||||
create mirror: repo with InRelease verification
|
||||
"""
|
||||
runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror9 http://mirror.yandex.ru/debian-backports/ squeeze-backports"
|
||||
fixtureGpg = True
|
||||
outputMatchPrepare = lambda _, s: re.sub(r'Signature made .* using|Warning: using insecure memory!\n', '', s)
|
||||
|
||||
def check(self):
|
||||
def removeDates(s):
|
||||
return re.sub(r"(Date|Valid-Until): [,0-9:+A-Za-z -]+\n", "", s)
|
||||
|
||||
self.check_output()
|
||||
self.check_cmd_output("aptly mirror show mirror9", "mirror_show", match_prepare=removeDates)
|
||||
|
||||
|
||||
class CreateMirror10Test(BaseTest):
|
||||
"""
|
||||
create mirror: repo with InRelease verification, failure
|
||||
"""
|
||||
runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror10 http://mirror.yandex.ru/debian-backports/ squeeze-backports"
|
||||
fixtureGpg = False
|
||||
gold_processor = BaseTest.expand_environ
|
||||
outputMatchPrepare = lambda _, s: re.sub(r'Signature made .* using|gpgv: keyblock resource .*$|gpgv: Can\'t check signature: .*$', '', s, flags=re.MULTILINE)
|
||||
expectedCode = 1
|
||||
|
||||
|
||||
class CreateMirror11Test(BaseTest):
|
||||
"""
|
||||
create mirror: repo with Release + Release.gpg verification
|
||||
"""
|
||||
runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror11 http://mirror.yandex.ru/debian/ squeeze"
|
||||
fixtureGpg = True
|
||||
outputMatchPrepare = lambda _, s: re.sub(r'Signature made .* using', '', s)
|
||||
|
||||
def check(self):
|
||||
self.check_output()
|
||||
self.check_cmd_output("aptly mirror show mirror11", "mirror_show")
|
||||
|
||||
|
||||
class CreateMirror12Test(BaseTest):
|
||||
"""
|
||||
create mirror: repo with Release+Release.gpg verification, failure
|
||||
"""
|
||||
runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror12 http://mirror.yandex.ru/debian/ squeeze"
|
||||
fixtureGpg = False
|
||||
gold_processor = BaseTest.expand_environ
|
||||
outputMatchPrepare = lambda _, s: re.sub(r'Signature made .* using|gpgv: keyblock resource .*$|gpgv: Can\'t check signature: .*$', '', s, flags=re.MULTILINE)
|
||||
expectedCode = 1
|
||||
|
||||
|
||||
class CreateMirror13Test(BaseTest):
|
||||
"""
|
||||
create mirror: skip verification using config file
|
||||
"""
|
||||
runCmd = "aptly mirror create mirror13 http://mirror.yandex.ru/debian/ wheezy"
|
||||
configOverride = {"gpgDisableVerify": True}
|
||||
|
||||
def check(self):
|
||||
self.check_output()
|
||||
self.check_cmd_output("aptly mirror show mirror13", "mirror_show")
|
||||
|
||||
|
||||
class CreateMirror14Test(BaseTest):
|
||||
"""
|
||||
create mirror: flat repository
|
||||
"""
|
||||
runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror14 http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/ ./"
|
||||
fixtureGpg = True
|
||||
outputMatchPrepare = lambda _, s: re.sub(r'Signature made .* using', '', s)
|
||||
|
||||
def check(self):
|
||||
self.check_output()
|
||||
self.check_cmd_output("aptly mirror show mirror14", "mirror_show")
|
||||
|
||||
|
||||
class CreateMirror15Test(BaseTest):
|
||||
"""
|
||||
create mirror: flat repository + components
|
||||
"""
|
||||
runCmd = "aptly mirror create --keyring=aptlytest.gpg mirror14 http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/ ./ main"
|
||||
expectedCode = 1
|
||||
@@ -0,0 +1,46 @@
|
||||
from lib import BaseTest
|
||||
|
||||
|
||||
class DropMirror1Test(BaseTest):
|
||||
"""
|
||||
drop mirror: regular list
|
||||
"""
|
||||
fixtureCmds = [
|
||||
"aptly mirror create --ignore-signatures mirror1 http://mirror.yandex.ru/debian/ wheezy",
|
||||
]
|
||||
runCmd = "aptly mirror drop mirror1"
|
||||
|
||||
def check(self):
|
||||
self.check_output()
|
||||
self.check_cmd_output("aptly mirror show mirror1", "mirror_show", expected_code=1)
|
||||
|
||||
|
||||
class DropMirror2Test(BaseTest):
|
||||
"""
|
||||
drop mirror: in use by snapshots
|
||||
"""
|
||||
fixtureDB = True
|
||||
fixtureCmds = [
|
||||
"aptly snapshot create wheez from mirror wheezy-main"
|
||||
]
|
||||
runCmd = "aptly mirror drop wheezy-main"
|
||||
expectedCode = 1
|
||||
|
||||
|
||||
class DropMirror3Test(BaseTest):
|
||||
"""
|
||||
drop mirror: force
|
||||
"""
|
||||
fixtureDB = True
|
||||
fixtureCmds = [
|
||||
"aptly snapshot create wheez from mirror wheezy-main"
|
||||
]
|
||||
runCmd = "aptly mirror drop --force wheezy-main"
|
||||
|
||||
|
||||
class DropMirror4Test(BaseTest):
|
||||
"""
|
||||
drop mirror: no such mirror
|
||||
"""
|
||||
runCmd = "aptly mirror drop mirror1"
|
||||
expectedCode = 1
|
||||
@@ -0,0 +1,20 @@
|
||||
from lib import BaseTest
|
||||
|
||||
|
||||
class ListMirror1Test(BaseTest):
|
||||
"""
|
||||
list mirrors: regular list
|
||||
"""
|
||||
fixtureCmds = [
|
||||
"aptly mirror create --ignore-signatures mirror1 http://mirror.yandex.ru/debian/ wheezy",
|
||||
"aptly mirror create --ignore-signatures mirror2 http://mirror.yandex.ru/debian/ squeeze contrib",
|
||||
"aptly -architectures=i386 mirror create --ignore-signatures mirror3 http://mirror.yandex.ru/debian/ squeeze non-free",
|
||||
]
|
||||
runCmd = "aptly mirror list"
|
||||
|
||||
|
||||
class ListMirror2Test(BaseTest):
|
||||
"""
|
||||
list mirrors: empty list
|
||||
"""
|
||||
runCmd = "aptly mirror list"
|
||||
@@ -0,0 +1,27 @@
|
||||
from lib import BaseTest
|
||||
import re
|
||||
|
||||
|
||||
class ShowMirror1Test(BaseTest):
|
||||
"""
|
||||
show mirror: regular mirror
|
||||
"""
|
||||
fixtureCmds = ["aptly mirror create --ignore-signatures mirror1 http://mirror.yandex.ru/debian/ wheezy"]
|
||||
runCmd = "aptly mirror show mirror1"
|
||||
|
||||
|
||||
class ShowMirror2Test(BaseTest):
|
||||
"""
|
||||
show mirror: missing mirror
|
||||
"""
|
||||
runCmd = "aptly mirror show mirror-xx"
|
||||
expectedCode = 1
|
||||
|
||||
|
||||
class ShowMirror3Test(BaseTest):
|
||||
"""
|
||||
show mirror: regular mirror with packages
|
||||
"""
|
||||
fixtureDB = True
|
||||
runCmd = "aptly mirror show --with-packages wheezy-contrib"
|
||||
outputMatchPrepare = lambda _, s: re.sub(r"Last update: [0-9:+A-Za-z -]+\n", "", s)
|
||||
@@ -0,0 +1,15 @@
|
||||
Origin: test
|
||||
Label: failure
|
||||
Suite: test
|
||||
Version: 6.0.8
|
||||
Codename: hardy
|
||||
Date: Sat, 19 Oct 2013 13:54:21 UTC
|
||||
Architectures: amd64
|
||||
Components: main
|
||||
Description: Debian 6.0.8 Released 19 October 2013
|
||||
MD5Sum:
|
||||
2e3817293fc275dbee74bd71ce6eb056 4 main/binary-amd64/Packages
|
||||
SHA1:
|
||||
4d13fcc6eda389d4d679602171e11593eadae9b9 4 main/binary-amd64/Packages
|
||||
SHA256:
|
||||
8a21688ae769f2b4ffcaa366409f679d 4 main/binary-amd64/Packages
|
||||
@@ -0,0 +1 @@
|
||||
lala
|
||||
@@ -0,0 +1,11 @@
|
||||
Origin: test
|
||||
Label: failure
|
||||
Suite: test
|
||||
Version: 6.0.8
|
||||
Codename: hardy
|
||||
Date: Sat, 19 Oct 2013 13:54:21 UTC
|
||||
Architectures: amd64
|
||||
Components: main
|
||||
Description: Debian 6.0.8 Released 19 October 2013
|
||||
MD5Sum:
|
||||
846549680001f5c632b6ee8e0f183825 827 main/binary-amd64/Packages
|
||||
@@ -0,0 +1,19 @@
|
||||
Package: amanda-client
|
||||
Source: amanda
|
||||
Version: 1:3.3.1-3~bpo60+1
|
||||
Installed-Size: 880
|
||||
Maintainer: Bdale Garbee <bdale@gag.com>
|
||||
Architecture: amd64
|
||||
Replaces: amanda-common (<< 1:2.5.2p1-3)
|
||||
Depends: libc6 (>= 2.3), libcurl3 (>= 7.16.2-1), libglib2.0-0 (>= 2.12.0), libreadline6 (>= 6.0), libssl0.9.8 (>= 0.9.8m-1), amanda-common (= 1:3.3.1-3~bpo60+1)
|
||||
Suggests: gnuplot, dump, smbclient
|
||||
Conflicts: amanda, amanda-common (<< 1:2.5.2p1-3)
|
||||
Description: Advanced Maryland Automatic Network Disk Archiver (Client)
|
||||
Description-md5: 21af3684379a64cacc51c39152ab1062
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Filename: pool/main/a/amanda/amanda-client_3.3.1-3~bpo60+1_amd64.deb
|
||||
Size: 30
|
||||
MD5sum: 4f7223ebadee9fb57b6796570d60638f
|
||||
SHA1: 66b27417d37e024c46526c2f6d358a754fc552f3
|
||||
SHA256: 3608bca1e44ea6c4d268eb6db02260269892c0b42b86bbf1e77a6fa16c3c9282
|
||||
+1
@@ -0,0 +1 @@
|
||||
012345678901234567890123456789
|
||||
@@ -0,0 +1,99 @@
|
||||
import string
|
||||
import re
|
||||
from lib import BaseTest
|
||||
|
||||
|
||||
class UpdateMirror1Test(BaseTest):
|
||||
"""
|
||||
update mirrors: regular update
|
||||
"""
|
||||
longTest = True
|
||||
fixtureCmds = [
|
||||
"aptly -architectures=i386,amd64 mirror create --ignore-signatures alsa-ppa http://ppa.launchpad.net/alsa-backports/ubuntu/ hardy main",
|
||||
]
|
||||
runCmd = "aptly mirror update --ignore-signatures alsa-ppa"
|
||||
|
||||
def output_processor(self, output):
|
||||
return "\n".join(sorted(output.split("\n")))
|
||||
|
||||
|
||||
class UpdateMirror2Test(BaseTest):
|
||||
"""
|
||||
update mirrors: no such repo
|
||||
"""
|
||||
runCmd = "aptly mirror update mirror-xyz"
|
||||
expectedCode = 1
|
||||
|
||||
|
||||
class UpdateMirror3Test(BaseTest):
|
||||
"""
|
||||
update mirrors: wrong checksum in release file
|
||||
"""
|
||||
fixtureCmds = [
|
||||
"aptly mirror create --ignore-signatures failure ${url} hardy main",
|
||||
]
|
||||
fixtureWebServer = "test_release"
|
||||
runCmd = "aptly mirror update --ignore-signatures failure"
|
||||
expectedCode = 1
|
||||
|
||||
def gold_processor(self, gold):
|
||||
return string.Template(gold).substitute({'url': self.webServerUrl})
|
||||
|
||||
|
||||
class UpdateMirror4Test(BaseTest):
|
||||
"""
|
||||
update mirrors: wrong checksum in release file, but ignore
|
||||
"""
|
||||
fixtureCmds = [
|
||||
"aptly mirror create --ignore-signatures failure ${url} hardy main",
|
||||
]
|
||||
fixtureWebServer = "test_release"
|
||||
runCmd = "aptly mirror update -ignore-checksums --ignore-signatures failure"
|
||||
expectedCode = 1
|
||||
|
||||
def gold_processor(self, gold):
|
||||
return string.Template(gold).substitute({'url': self.webServerUrl})
|
||||
|
||||
|
||||
class UpdateMirror5Test(BaseTest):
|
||||
"""
|
||||
update mirrors: wrong checksum in package
|
||||
"""
|
||||
fixtureCmds = [
|
||||
"aptly mirror create --ignore-signatures failure ${url} hardy main",
|
||||
]
|
||||
fixtureWebServer = "test_release2"
|
||||
runCmd = "aptly mirror update --ignore-signatures failure"
|
||||
expectedCode = 1
|
||||
|
||||
def gold_processor(self, gold):
|
||||
return string.Template(gold).substitute({'url': self.webServerUrl})
|
||||
|
||||
|
||||
class UpdateMirror6Test(BaseTest):
|
||||
"""
|
||||
update mirrors: wrong checksum in package, but ignore
|
||||
"""
|
||||
fixtureCmds = [
|
||||
"aptly mirror create --ignore-signatures failure ${url} hardy main",
|
||||
]
|
||||
fixtureWebServer = "test_release2"
|
||||
runCmd = "aptly mirror update -ignore-checksums --ignore-signatures failure"
|
||||
|
||||
def gold_processor(self, gold):
|
||||
return string.Template(gold).substitute({'url': self.webServerUrl})
|
||||
|
||||
|
||||
class UpdateMirror7Test(BaseTest):
|
||||
"""
|
||||
update mirrors: flat repository
|
||||
"""
|
||||
fixtureGpg = True
|
||||
fixtureCmds = [
|
||||
"aptly mirror create --keyring=aptlytest.gpg flat http://download.opensuse.org/repositories/home:/DeepDiver1975/xUbuntu_10.04/ ./",
|
||||
]
|
||||
runCmd = "aptly mirror update --keyring=aptlytest.gpg flat"
|
||||
outputMatchPrepare = lambda _, s: re.sub(r'Signature made .* using', '', s)
|
||||
|
||||
def output_processor(self, output):
|
||||
return "\n".join(sorted(output.split("\n")))
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user