Compare commits

..

1 Commits

Author SHA1 Message Date
Andrey Smirnov a6541aac41 Fix temporary contents DB being left behind after publishing
NB: Go `defer` order execution is reverse to the order `defer` statements
are executed.

So before the change, `Drop()` was called before `Close()`, which was no-op.

Change that to explicit order in single func, print errors if they happen.
2017-04-11 00:32:21 +03:00
3385 changed files with 835149 additions and 1479250 deletions
+2 -3
View File
@@ -22,7 +22,8 @@ _testmain.go
*.exe *.exe
*.test *.test
coverage.txt coverage.html
coverage*.out
*.pyc *.pyc
@@ -33,5 +34,3 @@ man/aptly.1.html
man/aptly.1.ronn man/aptly.1.ronn
.goxc.local.json .goxc.local.json
system/env/
+4 -4
View File
@@ -10,17 +10,17 @@
"bintray" "bintray"
], ],
"TaskSettings": { "TaskSettings": {
"debs": { "deb": {
"metadata": { "metadata": {
"maintainer": "Andrey Smirnov", "maintainer": "Andrey Smirnov",
"maintainer-email": "me@smira.ru", "maintainerEmail": "me@smira.ru",
"description": "Debian repository management tool" "description": "Debian repository management tool"
}, },
"metadata-deb": { "metadata-deb": {
"License": "MIT", "License": "MIT",
"Homepage": "https://www.aptly.info/", "Homepage": "https://www.aptly.info/",
"Depends": "bzip2, xz-utils, gnupg, gpgv", "Recommends": "bzip2, graphviz, xz-utils",
"Suggests": "graphviz" "Depends": ""
}, },
"other-mapped-files": { "other-mapped-files": {
"/": "root/" "/": "root/"
+19 -28
View File
@@ -1,9 +1,12 @@
dist: trusty sudo: false
sudo: required
language: go language: go
go_import_path: github.com/aptly-dev/aptly go:
- 1.6
- 1.7
- 1.8
- tip
addons: addons:
apt: apt:
@@ -13,39 +16,27 @@ addons:
env: env:
global: global:
- secure: "EcCzJsqQ3HnIkprBPS1YHErsETcb7KQFBYEzVDE7RYDApWeapLq+r/twMtWMd/fkGeLzr3kWSg7nhSadeHMLYeMl9j+U7ncC5CWG5NMBOj/jowlb9cMCCDlmzMoZLAgR6jm1cJyrWCLsWVlv+D0ZiB0fx4xaBZP/gIr9g6nEwC8=" - secure: "YSwtFrMqh4oUvdSQTXBXMHHLWeQgyNEL23ChIZwU0nuDGIcQZ65kipu0PzefedtUbK4ieC065YCUi4UDDh6gPotB/Wu1pnYg3dyQ7rFvhaVYAAUEpajAdXZhlx+7+J8a4FZMeC/kqiahxoRgLbthF9019ouIqhGB9zHKI6/yZwc="
- secure: "V7OjWrfQ8UbktgT036jYQPb/7GJT3Ol9LObDr8FYlzsQ+F1uj2wLac6ePuxcOS4FwWOJinWGM1h+JiFkbxbyFqfRNJ0jj0O2p93QyDojxFVOn1mXqqvV66KFqAWR2Vzkny/gDvj8LTvdB1cgAIm2FNOkQc6E1BFnyWS2sN9ea5E="
- secure: "OxiVNmre2JzUszwPNNilKDgIqtfX2gnRSsVz6nuySB1uO2yQsOQmKWJ9cVYgH2IB5H8eWXKOhexcSE28kz6TPLRuEcU9fnqKY3uEkdwm7rJfz9lf+7C4bJEUdA1OIzJppjnWUiXxD7CEPL1DlnMZM24eDQYqa/4WKACAgkK53gE=" - secure: "OxiVNmre2JzUszwPNNilKDgIqtfX2gnRSsVz6nuySB1uO2yQsOQmKWJ9cVYgH2IB5H8eWXKOhexcSE28kz6TPLRuEcU9fnqKY3uEkdwm7rJfz9lf+7C4bJEUdA1OIzJppjnWUiXxD7CEPL1DlnMZM24eDQYqa/4WKACAgkK53gE="
- NO_FTP_ACCESS: "yes"
- BOTO_CONFIG: /dev/null
matrix:
allow_failures:
- go: master
env: RUN_LONG_TESTS=no
fast_finish: true
include:
- go: 1.8.x
env: RUN_LONG_TESTS=no
- go: 1.9.x
env: RUN_LONG_TESTS=yes
- go: 1.10.x
env: RUN_LONG_TESTS=yes
- go: master
env: RUN_LONG_TESTS=no
before_install: before_install:
- virtualenv system/env - virtualenv env
- . system/env/bin/activate - . env/bin/activate
- pip install six packaging appdirs - pip install six packaging appdirs
- pip install -U pip setuptools - pip install -U pip setuptools
- pip install -r system/requirements.txt - pip install boto requests requests-unixsocket python-swiftclient
- mkdir -p $GOPATH/src/github.com/smira
- ln -s $TRAVIS_BUILD_DIR $GOPATH/src/github.com/smira || true
- cd $GOPATH/src/github.com/smira/aptly
- make version - make version
install: install:
- make prepare - make prepare
after_success: script: make travis
- bash <(curl -s https://codecov.io/bash)
matrix:
allow_failures:
- go: tip
notifications: notifications:
webhooks: webhooks:
-7
View File
@@ -26,10 +26,3 @@ List of contributors, in chronological order:
* Harald Sitter (https://github.com/apachelogger) * Harald Sitter (https://github.com/apachelogger)
* Johannes Layher (https://github.com/jola5) * Johannes Layher (https://github.com/jola5)
* Charles Hsu (https://github.com/charz) * Charles Hsu (https://github.com/charz)
* Clemens Rabe (https://github.com/seeraven)
* TJ Merritt (https://github.com/tjmerritt)
* Matt Martyn (https://github.com/MMartyn)
* Ludovico Cavedon (https://github.com/cavedon)
* Petr Jediny (https://github.com/pjediny)
* Maximilian Stein (https://github.com/steinymity)
* Strajan Sebastian (https://github.com/strajansebastian)
-240
View File
@@ -1,240 +0,0 @@
# Contributing to aptly
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
The following is a set of guidelines for contributing to [aptly](https://github.com/smira/aplty) and related repositories, which are hosted in the [aptly-dev Organization](https://github.com/aptly-dev) on GitHub.
These are just guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
## What should I know before I get started?
### Code of Conduct
This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code.
Please report unacceptable behavior to [team@aptly.info](mailto:team@aptly.info).
### List of Repositories
* [aptly-dev/aptly](https://github.com/aptly-dev/aptly) - aptly source code, functional tests, man page
* [apty-dev/aptly-dev.github.io](https://github.com/aptly-dev/aptly-dev.github.io) - aptly website (https://www.aptly.info/)
* [aptly-dev/aptly-fixture-db](https://github.com/aptly-dev/aptly-fixture-db) & [aptly-dev/aptly-fixture-pool](https://github.com/aptly-dev/aptly-fixture-pool) provide
fixtures for aptly functional tests
## How Can I Contribute?
### Reporting Bugs
1. Please search for similar bug report in [issue tracker](https://github.com/aptly-dev/aptly/issues)
2. Please verify that bug is not fixed in latest aptly nightly ([download information](https://www.aptly.info/download/))
3. Steps to reproduce increases chances for bug to be fixed quickly. If possible, submit PR with new functional test which fails.
4. If bug is reproducible with specific package, please provide link to package file.
5. Open issue at [GitHub](https://github.com/aptly-dev/aptly/issues)
### Suggesting Enhancements
1. Please search [issue tracker](https://github.com/aptly-dev/aptly/issues) for similar feature requests.
2. Describe why enhancement is important to you.
3. Include any additional details or implementation details.
### Improving Documentation
There are two kinds of documentation:
* [aptly website](https://www.aptly/info)
* aptly `man` page
Core content is mostly the same, but website contains more information, tutorials, examples.
If you want to update `man` page, please open PR to [main aptly repo](https://github.com/aptly-dev/aptly),
details in [man page](#man-page) section.
If you want to update website, please follow steps below:
1. Install [hugo](http://gohugo.io/)
2. Fork [website source](https://github.com/aptly-dev/aptly-dev.github.io) and clone it
3. Launch hugo in development mode: `hugo -w server`
4. Navigate to `http://localhost:1313/`: you should see aptly website
5. Update documentation, most of the time editing Markdown is all you need.
6. Page in browser should reload automatically as you make changes to source files.
We're always looking for new contributions to [FAQ](https://www.aptly.info/doc/faq/), [tutorials](https://www.aptly.info/tutorial/),
general fixes, clarifications, misspellings, grammar mistakes!
### Your Fist Code Contribution
Please follow [next section](#development-setup) on development process. When change is ready, please submit PR
following [PR template](.github/PULL_REQUEST_TEMPLATE.md).
Make sure that purpose of your change is clear, all the tests and checks pass, and all new code is covered with tests
if that is possible.
## Development Setup
This section describes local setup to start contributing to aptly source.
### Go & Python
You would need `Go` (latest version is recommended) and `Python` 2.7.x (3.x is not supported yet).
If you're new to Go, follow [getting started guide](https://golang.org/doc/install) to install it and perform
initial setup. With Go 1.8+, default `$GOPATH` is `$HOME/go`, so rest of this document assumes that.
Usually `$GOPATH/bin` is appended to your `$PATH` to make it easier to run built binaries, but you might choose
to prepend it or to skip this test if you're security conscious.
### Forking and Cloning
As Go is using repository path in import paths, it's better to clone aptly repo (not your fork) at default location:
mkdir -p ~/go/src/github.com/smira
cd ~/go/src/github.com/smira
git clone git@github.com:aptly-dev/aptly.git
cd aptly
For main repo under your GitHub user and add it as another Git remote:
git remote add <user> git@github.com:<user>/aptly.git
That way you can continue to build project as is (you don't need to adjust import paths), but you would need
to specify your remote name when pushing branches:
git push <user> <your-branch>
### Dependencies
You would need some additional tools and Python virtual environment to run tests and checks, install them with:
make prepare dev system/env
This is usually one-time action.
### Building
If you want to build aptly binary from your current source tree, run:
make install
This would build `aptly` in `$GOPATH/bin`, so depending on your `$PATH`, you should be able to run it immediately with:
aptly
Or, if it's not on your path:
~/go/bin/aptly
### Unit-tests
aptly has two kinds of tests: unit-tests and functional (system) tests. Functional tests are preferred way to test any
feature, but some features are much easier to test with unit-tests (e.g. algorithms, failure scenarios, ...)
aptly is using standard Go unit-test infrastructure plus [gocheck](http://labix.org/gocheck). Run the unit-tests with:
make test
### Functional Tests
Functional tests are implemented in Python, and they use custom test runner which is similar to Python unit-test
runner. Most of the tests start with clean aptly state, run some aptly commands to prepare environment, and finally
run some aptly commands capturing output, exit code, checking any additional files being created and so on. API tests
are a bit different, as they re-use same aptly process serving API requests.
The easiest way to run functional tests is to use `make`:
make system-test
This would check all the dependencies and run all the tests. Some tests (S3, Swift) require access credentials to
be set up in the environment. For example, it needs AWS credentials to run S3 tests (they would be used to publish to S3).
If credentials are missing, tests would be skipped.
You can also run subset of tests manually:
system/run.py t04_mirror
This would run all the mirroring tests under `system/t04_mirror` folder.
Or you can run tests by test name mask:
system/run.py UpdateMirror*
Or, you can run specific test by name:
system/run.py UpdateMirror7Test
Test runner can update expected output instead of failing on mismatch (this is especially useful while
working on new tests):
system/run.py --capture <test>
Output for some tests might contain environment-specific things, e.g. your home directory. In that case
you can use `${HOME}` and similar variable expansion in expected output files.
Some tests depend on fixtures, for example pre-populated GPG trusted keys. There are also test fixtures
captured after mirror update which contain pre-build aptly database and pool contents. They're useful if you
don't want to waste time in the test on populating aptly database while you need some packages to work with.
There are some packages available under `system/files/` directory which are used to build contents of local repos.
*WARNING*: tests are running under current `$HOME` directory with aptly default settings, so they clear completely
`~/.aptly.conf` and `~/.aptly` subdirectory between the runs. So it's not wise to have non-dev aptly being used with
this default location. You can run aptly under different user or by using non-default config location with non-default
aptly root directory.
### Style Checks
Style checks could be run with:
make check
aptly is using [gometalinter](https://github.com/alecthomas/gometalinter) to run style checks on Go code. Configuration
for the linter could be found in [linter.json](linter.json) file. Running linters might take considerable amount of time
unfortunately, but usually warning reported by linters hint at real code issues.
Python code (system tests) are linted with [flake8 tool](https://pypi.python.org/pypi/flake8).
### Vendored Code
aptly is using Go vendoring for all the libraries aptly depends upon. `vendor/` directory is checked into the source
repository to avoid any problems if source repositories go away. Go build process will automatically prefer vendored
packages over packages in `$GOPATH`.
If you want to update vendored dependencies or to introduce new dependency, use [dep tool](https://github.com/golang/dep).
Usually all you need is `dep ensure` or `dep ensure -update`.
### man Page
aptly is using combination of [Go templates](http://godoc.org/text/template) and automatically generated text to build `aptly.1` man page. If either source
template [man/aptly.1.ronn.tmpl](man/aptly.1.ronn.tmpl) is changed or any command help is changed, run `make man` to regenerate
final rendered man page [man/aptly.1](man/aptly.1). In the end of the build, new man page is displayed for visual
verification.
Man page is built with small helper [\_man/gen.go](man/gen.go) which pulls in template, command-line help from [cmd/](cmd/) folder
and runs that through [forked copy](https://github.com/smira/ronn) of [ronn](https://github.com/rtomayko/ronn).
### Bash and Zsh Completion
Bash and Zsh completion for aptly reside in the same repo under in [completion.d/aptly](completion.d/aptly) and
[completion.d/\_aptly](completion.d/_aptly), respectively. It's all hand-crafted.
When new option or command is introduced, bash completion should be updated to reflect that change.
When aptly package is being built, it automatically pulls bash completion and man page into the package.
## Design
This section requires future work.
*TBD*
### Database
### Package Pool
### Package
### PackageList, PackageRefList
### LocalRepo, RemoteRepo, Snapshot
### PublishedRepository
### Context
### Collections, CollectionFactory
Generated
-290
View File
@@ -1,290 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/AlekSi/pointer"
packages = ["."]
revision = "08a25bac605b3fcb6cc27f3917b2c2c87451963d"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/DisposaBoy/JsonConfigReader"
packages = ["."]
revision = "33a99fdf1d5ee1f79b5077e9c06f955ad356d5f4"
[[projects]]
name = "github.com/awalterschulze/gographviz"
packages = [
".",
"ast",
"parser",
"scanner",
"token"
]
revision = "761fd5fbb34e4c2c138c280395b65b48e4ff5a53"
version = "v1.0"
[[projects]]
name = "github.com/aws/aws-sdk-go"
packages = [
"aws",
"aws/awserr",
"aws/awsutil",
"aws/client",
"aws/client/metadata",
"aws/corehandlers",
"aws/credentials",
"aws/credentials/ec2rolecreds",
"aws/credentials/endpointcreds",
"aws/credentials/stscreds",
"aws/defaults",
"aws/ec2metadata",
"aws/endpoints",
"aws/request",
"aws/session",
"aws/signer/v4",
"internal/sdkio",
"internal/sdkrand",
"internal/shareddefaults",
"private/protocol",
"private/protocol/query",
"private/protocol/query/queryutil",
"private/protocol/rest",
"private/protocol/restxml",
"private/protocol/xml/xmlutil",
"service/s3",
"service/sts"
]
revision = "a72204b9bf8d48230ee0fe8995613b394c66f2da"
version = "v1.13.31"
[[projects]]
name = "github.com/cheggaaa/pb"
packages = ["."]
revision = "cdf719fac0dd208251aa828e687c2d5802053b51"
version = "v1.0.10"
[[projects]]
branch = "master"
name = "github.com/gin-contrib/sse"
packages = ["."]
revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae"
[[projects]]
name = "github.com/gin-gonic/gin"
packages = [
".",
"binding",
"render"
]
revision = "d459835d2b077e44f7c9b453505ee29881d5d12d"
version = "v1.2"
[[projects]]
name = "github.com/go-ini/ini"
packages = ["."]
revision = "1730955e3146956d6a087861380f9b4667ed5071"
version = "v1.26.0"
[[projects]]
branch = "master"
name = "github.com/golang/protobuf"
packages = ["proto"]
revision = "130e6b02ab059e7b717a096f397c5b60111cae74"
[[projects]]
branch = "master"
name = "github.com/golang/snappy"
packages = ["."]
revision = "553a641470496b2327abcac10b36396bd98e45c9"
[[projects]]
name = "github.com/h2non/filetype"
packages = ["matchers"]
revision = "cc14fdc9ca0e4c2bafad7458f6ff79fd3947cfbb"
version = "v1.0.5"
[[projects]]
branch = "master"
name = "github.com/jlaffaye/ftp"
packages = ["."]
revision = "2403248fa8cc9f7909862627aa7337f13f8e0bf1"
[[projects]]
name = "github.com/jmespath/go-jmespath"
packages = ["."]
revision = "0b12d6b5"
[[projects]]
name = "github.com/mattn/go-isatty"
packages = ["."]
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
name = "github.com/mattn/go-runewidth"
packages = ["."]
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
version = "v0.0.2"
[[projects]]
name = "github.com/mattn/go-shellwords"
packages = ["."]
revision = "005a0944d84452842197c2108bd9168ced206f78"
version = "v1.0.2"
[[projects]]
branch = "master"
name = "github.com/mkrautz/goar"
packages = ["."]
revision = "282caa8bd9daba480b51f1d5a988714913b97aad"
[[projects]]
branch = "master"
name = "github.com/mxk/go-flowrate"
packages = ["flowrate"]
revision = "cca7078d478f8520f85629ad7c68962d31ed7682"
[[projects]]
branch = "master"
name = "github.com/ncw/swift"
packages = [
".",
"swifttest"
]
revision = "8e9b10220613abdbc2896808ee6b43e411a4fa6c"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
branch = "master"
name = "github.com/smira/commander"
packages = ["."]
revision = "f408b00e68d5d6e21b9f18bd310978dafc604e47"
[[projects]]
branch = "master"
name = "github.com/smira/flag"
packages = ["."]
revision = "695ea5e84e76dea7c8656e43c384e54b32aa1b2a"
[[projects]]
branch = "master"
name = "github.com/smira/go-aws-auth"
packages = ["."]
revision = "0070896e9d7f4f9f2d558532b2d896ce2239992a"
[[projects]]
branch = "master"
name = "github.com/smira/go-ftp-protocol"
packages = ["protocol"]
revision = "066b75c2b70dca7ae10b1b88b47534a3c31ccfaa"
[[projects]]
branch = "master"
name = "github.com/smira/go-uuid"
packages = ["uuid"]
revision = "ed3ca8a15a931b141440a7e98e4f716eec255f7d"
[[projects]]
branch = "master"
name = "github.com/smira/go-xz"
packages = ["."]
revision = "0c531f070014e218b21f3cfca801cc992d52726d"
[[projects]]
branch = "master"
name = "github.com/smira/lzma"
packages = ["."]
revision = "7f0af6269940baa2c938fabe73e0d7ba41205683"
[[projects]]
branch = "master"
name = "github.com/syndtr/goleveldb"
packages = [
"leveldb",
"leveldb/cache",
"leveldb/comparer",
"leveldb/errors",
"leveldb/filter",
"leveldb/iterator",
"leveldb/journal",
"leveldb/memdb",
"leveldb/opt",
"leveldb/storage",
"leveldb/table",
"leveldb/util"
]
revision = "714f901b98fdb3aa954b4193d8cbd64a28d80cad"
[[projects]]
name = "github.com/ugorji/go"
packages = ["codec"]
revision = "71c2886f5a673a35f909803f38ece5810165097b"
[[projects]]
branch = "master"
name = "github.com/wsxiaoys/terminal"
packages = ["color"]
revision = "0940f3fc43a0ed42d04916b1c04578462c650b09"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"cast5",
"openpgp",
"openpgp/armor",
"openpgp/clearsign",
"openpgp/elgamal",
"openpgp/errors",
"openpgp/packet",
"openpgp/s2k",
"ssh/terminal"
]
revision = "b2aa35443fbc700ab74c586ae79b81c171851023"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
]
revision = "1d206c9fa8975fb4cf00df1dc8bf3283dc24ba0e"
[[projects]]
branch = "v1"
name = "gopkg.in/check.v1"
packages = ["."]
revision = "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec"
[[projects]]
name = "gopkg.in/go-playground/validator.v8"
packages = ["."]
revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf"
version = "v8.18.2"
[[projects]]
name = "gopkg.in/h2non/filetype.v1"
packages = ["types"]
revision = "3093b8ebec6efb56ac813238b8beab4ed4eaac6a"
version = "v1.0.1"
[[projects]]
branch = "v2"
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "5ab2b384766e62be84d3941971a1d8e99c637f80a2cb1482b3d9704c668b549f"
solver-name = "gps-cdcl"
solver-version = 1
-28
View File
@@ -1,28 +0,0 @@
[[override]]
branch = "master"
name = "github.com/mkrautz/goar"
[[override]]
branch = "master"
name = "github.com/smira/go-uuid"
[[override]]
branch = "master"
name = "github.com/smira/go-xz"
[[override]]
name = "github.com/ugorji/go"
revision = "71c2886f5a673a35f909803f38ece5810165097b"
[[override]]
branch = "master"
name = "golang.org/x/crypto"
[[override]]
branch = "master"
name = "golang.org/x/sys"
[[override]]
branch = "v1"
name = "gopkg.in/check.v1"
+41 -31
View File
@@ -1,16 +1,22 @@
GOVERSION=$(shell go version | awk '{print $$3;}') GOVERSION=$(shell go version | awk '{print $$3;}')
VERSION=$(shell git describe --tags | sed 's@^v@@' | sed 's@-@+@g') VERSION=$(shell git describe --tags | sed 's@^v@@' | sed 's@-@+@g')
PACKAGES=context database deb files gpg http query swift s3 utils PACKAGES=context database deb files http query swift s3 utils
PYTHON?=python PYTHON?=python
TESTS?= TESTS?=
BINPATH?=$(GOPATH)/bin BINPATH?=$(GOPATH)/bin
RUN_LONG_TESTS?=yes
GO_1_10_AND_HIGHER=$(shell (printf '%s\n' go1.10 $(GOVERSION) | sort -cV >/dev/null 2>&1) && echo "yes") ifeq ($(GOVERSION), devel)
TRAVIS_TARGET=coveralls
else
TRAVIS_TARGET=test
endif
all: test check system-test all: test check system-test
prepare: prepare:
go get -u github.com/mattn/goveralls
go get -u github.com/axw/gocov/gocov
go get -u golang.org/x/tools/cmd/cover
go get -u github.com/alecthomas/gometalinter go get -u github.com/alecthomas/gometalinter
gometalinter --install gometalinter --install
@@ -18,50 +24,54 @@ dev:
go get -u github.com/golang/dep/... go get -u github.com/golang/dep/...
go get -u github.com/laher/goxc go get -u github.com/laher/goxc
check: system/env coverage.out:
ifeq ($(RUN_LONG_TESTS), yes) rm -f coverage.*.out
if [ -x travis_wait ]; then \ for i in $(PACKAGES); do go test -coverprofile=coverage.$$i.out -covermode=count ./$$i; done
travis_wait gometalinter --config=linter.json ./...; \ echo "mode: count" > coverage.out
else \ grep -v -h "mode: count" coverage.*.out >> coverage.out
gometalinter --config=linter.json ./...; \ rm -f coverage.*.out
fi
. system/env/bin/activate && flake8 --max-line-length=200 --exclude=system/env/ system/ coverage: coverage.out
endif go tool cover -html=coverage.out
rm -f coverage.out
check:
gometalinter --vendor --vendored-linters --config=linter.json ./...
install: install:
go install -v -ldflags "-X main.Version=$(VERSION)" go install -v -ldflags "-X main.Version=$(VERSION)"
system/env: system/requirements.txt system-test: install
ifeq ($(RUN_LONG_TESTS), yes)
rm -rf system/env
virtualenv system/env
system/env/bin/pip install -r system/requirements.txt
endif
system-test: install system/env
ifeq ($(RUN_LONG_TESTS), yes)
if [ ! -e ~/aptly-fixture-db ]; then git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; fi if [ ! -e ~/aptly-fixture-db ]; then git clone https://github.com/aptly-dev/aptly-fixture-db.git ~/aptly-fixture-db/; fi
if [ ! -e ~/aptly-fixture-pool ]; then git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/; fi if [ ! -e ~/aptly-fixture-pool ]; then git clone https://github.com/aptly-dev/aptly-fixture-pool.git ~/aptly-fixture-pool/; fi
PATH=$(BINPATH)/:$(PATH) && . system/env/bin/activate && APTLY_VERSION=$(VERSION) $(PYTHON) system/run.py --long $(TESTS) APTLY_VERSION=$(VERSION) PATH=$(BINPATH)/:$(PATH) $(PYTHON) system/run.py --long $(TESTS)
endif
travis: $(TRAVIS_TARGET) check system-test
test: test:
ifeq ($(GO_1_10_AND_HIGHER), yes)
go test -v ./... -gocheck.v=true -race -coverprofile=coverage.txt -covermode=atomic
else
go test -v `go list ./... | grep -v vendor/` -gocheck.v=true go test -v `go list ./... | grep -v vendor/` -gocheck.v=true
endif
coveralls: coverage.out
$(BINPATH)/goveralls -service travis-ci.org -coverprofile=coverage.out -repotoken=$(COVERALLS_TOKEN)
mem.png: mem.dat mem.gp mem.png: mem.dat mem.gp
gnuplot mem.gp gnuplot mem.gp
open mem.png open mem.png
src-package:
rm -rf aptly-$(VERSION)
mkdir -p aptly-$(VERSION)/src/github.com/smira/aptly/
cd aptly-$(VERSION)/src/github.com/smira/ && git clone https://github.com/smira/aptly && cd aptly && git checkout v$(VERSION)
mkdir -p aptly-$(VERSION)/bash_completion.d
(cd aptly-$(VERSION)/bash_completion.d && wget https://raw.github.com/aptly-dev/aptly-bash-completion/$(VERSION)/aptly)
tar cyf aptly-$(VERSION)-src.tar.bz2 aptly-$(VERSION)
rm -rf aptly-$(VERSION)
goxc: goxc:
rm -rf root/ rm -rf root/
mkdir -p root/usr/share/man/man1/ root/etc/bash_completion.d/ root/usr/share/zsh/vendor-completions/ mkdir -p root/usr/share/man/man1/ root/etc/bash_completion.d
cp man/aptly.1 root/usr/share/man/man1 cp man/aptly.1 root/usr/share/man/man1
cp completion.d/aptly root/etc/bash_completion.d/ (cd root/etc/bash_completion.d && wget https://raw.github.com/aptly-dev/aptly-bash-completion/master/aptly)
cp completion.d/_aptly root/usr/share/zsh/vendor-completions/
gzip root/usr/share/man/man1/aptly.1 gzip root/usr/share/man/man1/aptly.1
goxc -pv=$(VERSION) -max-processors=4 $(GOXC_OPTS) goxc -pv=$(VERSION) -max-processors=4 $(GOXC_OPTS)
@@ -71,4 +81,4 @@ man:
version: version:
@echo $(VERSION) @echo $(VERSION)
.PHONY: man version .PHONY: coverage.out man version
+14 -23
View File
@@ -2,24 +2,24 @@
aptly aptly
===== =====
.. image:: https://api.travis-ci.org/aptly-dev/aptly.svg?branch=master .. image:: https://travis-ci.org/smira/aptly.png?branch=master
:target: https://travis-ci.org/aptly-dev/aptly :target: https://travis-ci.org/smira/aptly
.. image:: https://codecov.io/gh/aptly-dev/aptly/branch/master/graph/badge.svg .. image:: https://coveralls.io/repos/smira/aptly/badge.png?branch=HEAD
:target: https://codecov.io/gh/aptly-dev/aptly :target: https://coveralls.io/r/smira/aptly?branch=HEAD
.. image:: https://badges.gitter.im/Join Chat.svg .. image:: https://badges.gitter.im/Join Chat.svg
:target: https://gitter.im/aptly-dev/aptly?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge :target: https://gitter.im/smira/aptly?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
.. image:: http://goreportcard.com/badge/aptly-dev/aptly .. image:: http://goreportcard.com/badge/smira/aptly
:target: http://goreportcard.com/report/aptly-dev/aptly :target: http://goreportcard.com/report/smira/aptly
Aptly is a swiss army knife for Debian repository management. Aptly is a swiss army knife for Debian repository management.
.. image:: http://www.aptly.info/img/aptly_logo.png .. image:: http://www.aptly.info/img/aptly_logo.png
:target: http://www.aptly.info/ :target: http://www.aptly.info/
Documentation is available at `http://www.aptly.info/ <http://www.aptly.info/>`_. For support please use 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>`_. mailing list `aptly-discuss <https://groups.google.com/forum/#!forum/aptly-discuss>`_.
Aptly features: ("+" means planned features) Aptly features: ("+" means planned features)
@@ -42,13 +42,13 @@ Current limitations:
Download Download
-------- --------
To install aptly on Debian/Ubuntu, add new repository to ``/etc/apt/sources.list``:: To install aptly on Debian/Ubuntu, add new repository to /etc/apt/sources.list::
deb http://repo.aptly.info/ squeeze main deb http://repo.aptly.info/ squeeze main
And import key that is used to sign the release:: And import key that is used to sign the release::
$ apt-key adv --keyserver pool.sks-keyservers.net --recv-keys ED75B5A4483DA07C $ apt-key adv --keyserver keys.gnupg.net --recv-keys 9E3E53F19C7DE460
After that you can install aptly as any other software package:: After that you can install aptly as any other software package::
@@ -64,20 +64,15 @@ If you would like to use nightly builds (unstable), please use following reposit
Binary executables (depends almost only on libc) are available for download from `Bintray <http://dl.bintray.com/smira/aptly/>`_. Binary executables (depends almost only on libc) are available for download from `Bintray <http://dl.bintray.com/smira/aptly/>`_.
If you have Go environment set up, you can build aptly from source by running (go 1.8+ required):: If you have Go environment set up, you can build aptly from source by running (go 1.6+ required)::
mkdir -p $GOPATH/src/github.com/aptly-dev/aptly mkdir -p $GOPATH/src/github.com/smira/aptly
git clone https://github.com/aptly-dev/aptly $GOPATH/src/github.com/aptly-dev/aptly git clone https://github.com/smira/aptly $GOPATH/src/github.com/smira/aptly
cd $GOPATH/src/github.com/aptly-dev/aptly cd $GOPATH/src/github.com/smira/aptly
make install make install
Binary would be installed to ```$GOPATH/bin/aptly``. Binary would be installed to ```$GOPATH/bin/aptly``.
Contributing
------------
Please follow detailed documentation in `CONTRIBUTING.md <CONTRIBUTING.md>`_.
Integrations Integrations
------------ ------------
@@ -109,10 +104,6 @@ CLI for aptly API:
- `Ruby aptly CLI/library <https://github.com/sepulworld/aptly_cli>`_ by Zane Williamson - `Ruby aptly CLI/library <https://github.com/sepulworld/aptly_cli>`_ by Zane Williamson
- `Python aptly CLI (good for CI) <https://github.com/TimSusa/aptly_api_cli>`_ by Tim Susa - `Python aptly CLI (good for CI) <https://github.com/TimSusa/aptly_api_cli>`_ by Tim Susa
GUI for aptly API:
- `Python aptly GUI (via pyqt5) <https://github.com/chnyda/python-aptly-gui>`_ by Cedric Hnyda
Scala sbt: Scala sbt:
- `sbt aptly plugin <https://github.com/amalakar/sbt-aptly>`_ by Arup Malakar - `sbt aptly plugin <https://github.com/amalakar/sbt-aptly>`_ by Arup Malakar
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/aptly-dev/aptly/cmd" "github.com/smira/aptly/cmd"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
+28 -33
View File
@@ -6,10 +6,10 @@ import (
"sort" "sort"
"time" "time"
"github.com/aptly-dev/aptly/aptly"
"github.com/aptly-dev/aptly/deb"
"github.com/aptly-dev/aptly/query"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/smira/aptly/aptly"
"github.com/smira/aptly/deb"
"github.com/smira/aptly/query"
) )
// Lock order acquisition (canonical): // Lock order acquisition (canonical):
@@ -23,18 +23,11 @@ func apiVersion(c *gin.Context) {
c.JSON(200, gin.H{"Version": aptly.Version}) c.JSON(200, gin.H{"Version": aptly.Version})
} }
type dbRequestKind int
const ( const (
acquiredb dbRequestKind = iota acquiredb = iota
releasedb releasedb
) )
type dbRequest struct {
kind dbRequestKind
err chan<- error
}
// Flushes all collections which cache in-memory objects // Flushes all collections which cache in-memory objects
func flushColections() { func flushColections() {
// lock everything to eliminate in-progress calls // lock everything to eliminate in-progress calls
@@ -59,48 +52,50 @@ func flushColections() {
} }
// Periodically flushes CollectionFactory to free up memory used by // Periodically flushes CollectionFactory to free up memory used by
// collections, flushing caches. // collections, flushing caches. If the two channels are provided,
// they are used to acquire and release the database.
// //
// Should be run in goroutine! // Should be run in goroutine!
func cacheFlusher() { func cacheFlusher(requests chan int, acks chan error) {
ticker := time.Tick(15 * time.Minute) ticker := time.Tick(15 * time.Minute)
for { for {
<-ticker <-ticker
// if aptly API runs in -no-lock mode,
// caches are flushed when DB is closed anyway, no need
// to flush them here
if requests == nil {
flushColections() flushColections()
} }
}
} }
// Acquire database lock and release it when not needed anymore. // Acquire database lock and release it when not needed anymore. Two
// channels must be provided. The first one is to receive requests to
// acquire/release the database and the second one is to send acks.
// //
// Should be run in a goroutine! // Should be run in a goroutine!
func acquireDatabase(requests <-chan dbRequest) { func acquireDatabase(requests chan int, acks chan error) {
clients := 0 clients := 0
for request := range requests { for {
var err error request := <-requests
switch request {
switch request.kind {
case acquiredb: case acquiredb:
if clients == 0 { if clients == 0 {
err = context.ReOpenDatabase() acks <- context.ReOpenDatabase()
} else {
acks <- nil
} }
request.err <- err
if err == nil {
clients++ clients++
}
case releasedb: case releasedb:
clients-- clients--
if clients == 0 { if clients == 0 {
flushColections() flushColections()
err = context.CloseDatabase() acks <- context.CloseDatabase()
} else { } else {
err = nil acks <- nil
} }
request.err <- err
} }
} }
} }
@@ -112,7 +107,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
list, err := deb.NewPackageListFromRefList(reflist, context.CollectionFactory().PackageCollection(), nil) list, err := deb.NewPackageListFromRefList(reflist, context.CollectionFactory().PackageCollection(), nil)
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
@@ -120,7 +115,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
if queryS != "" { if queryS != "" {
q, err := query.Parse(c.Request.URL.Query().Get("q")) q, err := query.Parse(c.Request.URL.Query().Get("q"))
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
@@ -137,7 +132,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
sort.Strings(architecturesList) sort.Strings(architecturesList)
if len(architecturesList) == 0 { if len(architecturesList) == 0 {
c.AbortWithError(400, fmt.Errorf("unable to determine list of architectures, please specify explicitly")) c.Fail(400, fmt.Errorf("unable to determine list of architectures, please specify explicitly"))
return return
} }
} }
@@ -147,7 +142,7 @@ func showPackages(c *gin.Context, reflist *deb.PackageRefList) {
list, err = list.Filter([]deb.PackageQuery{q}, withDeps, list, err = list.Filter([]deb.PackageQuery{q}, withDeps,
nil, context.DependencyOptions(), architecturesList) nil, context.DependencyOptions(), architecturesList)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to search: %s", err)) c.Fail(500, fmt.Errorf("unable to search: %s", err))
return return
} }
} }
+12 -12
View File
@@ -24,7 +24,7 @@ func verifyPath(path string) bool {
func verifyDir(c *gin.Context) bool { func verifyDir(c *gin.Context) bool {
if !verifyPath(c.Params.ByName("dir")) { if !verifyPath(c.Params.ByName("dir")) {
c.AbortWithError(400, fmt.Errorf("wrong dir")) c.Fail(400, fmt.Errorf("wrong dir"))
return false return false
} }
@@ -53,7 +53,7 @@ func apiFilesListDirs(c *gin.Context) {
}) })
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
@@ -70,13 +70,13 @@ func apiFilesUpload(c *gin.Context) {
err := os.MkdirAll(path, 0777) err := os.MkdirAll(path, 0777)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
err = c.Request.ParseMultipartForm(10 * 1024 * 1024) err = c.Request.ParseMultipartForm(10 * 1024 * 1024)
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
@@ -86,7 +86,7 @@ func apiFilesUpload(c *gin.Context) {
for _, file := range files { for _, file := range files {
src, err := file.Open() src, err := file.Open()
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
defer src.Close() defer src.Close()
@@ -94,14 +94,14 @@ func apiFilesUpload(c *gin.Context) {
destPath := filepath.Join(path, filepath.Base(file.Filename)) destPath := filepath.Join(path, filepath.Base(file.Filename))
dst, err := os.Create(destPath) dst, err := os.Create(destPath)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
defer dst.Close() defer dst.Close()
_, err = io.Copy(dst, src) _, err = io.Copy(dst, src)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -138,9 +138,9 @@ func apiFilesListFiles(c *gin.Context) {
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
c.AbortWithError(404, err) c.Fail(404, err)
} else { } else {
c.AbortWithError(500, err) c.Fail(500, err)
} }
return return
} }
@@ -156,7 +156,7 @@ func apiFilesDeleteDir(c *gin.Context) {
err := os.RemoveAll(filepath.Join(context.UploadPath(), c.Params.ByName("dir"))) err := os.RemoveAll(filepath.Join(context.UploadPath(), c.Params.ByName("dir")))
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -170,14 +170,14 @@ func apiFilesDeleteFile(c *gin.Context) {
} }
if !verifyPath(c.Params.ByName("name")) { if !verifyPath(c.Params.ByName("name")) {
c.AbortWithError(400, fmt.Errorf("wrong file")) c.Fail(400, fmt.Errorf("wrong file"))
return return
} }
err := os.Remove(filepath.Join(context.UploadPath(), c.Params.ByName("dir"), c.Params.ByName("name"))) err := os.Remove(filepath.Join(context.UploadPath(), c.Params.ByName("dir"), c.Params.ByName("name")))
if err != nil { if err != nil {
if err1, ok := err.(*os.PathError); !ok || !os.IsNotExist(err1.Err) { if err1, ok := err.(*os.PathError); !ok || !os.IsNotExist(err1.Err) {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
} }
+13 -13
View File
@@ -8,8 +8,8 @@ import (
"os" "os"
"os/exec" "os/exec"
"github.com/aptly-dev/aptly/deb"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/smira/aptly/deb"
) )
// GET /api/graph.:ext?layout=[vertical|horizontal(default)] // GET /api/graph.:ext?layout=[vertical|horizontal(default)]
@@ -24,14 +24,14 @@ func apiGraph(c *gin.Context) {
factory := context.CollectionFactory() factory := context.CollectionFactory()
factory.RemoteRepoCollection().Lock() factory.RemoteRepoCollection().RLock()
defer factory.RemoteRepoCollection().Unlock() defer factory.RemoteRepoCollection().RUnlock()
factory.LocalRepoCollection().Lock() factory.LocalRepoCollection().RLock()
defer factory.LocalRepoCollection().Unlock() defer factory.LocalRepoCollection().RUnlock()
factory.SnapshotCollection().Lock() factory.SnapshotCollection().RLock()
defer factory.SnapshotCollection().Unlock() defer factory.SnapshotCollection().RUnlock()
factory.PublishedRepoCollection().Lock() factory.PublishedRepoCollection().RLock()
defer factory.PublishedRepoCollection().Unlock() defer factory.PublishedRepoCollection().RUnlock()
graph, err := deb.BuildGraph(factory, layout) graph, err := deb.BuildGraph(factory, layout)
if err != nil { if err != nil {
@@ -53,25 +53,25 @@ func apiGraph(c *gin.Context) {
stdin, err := command.StdinPipe() stdin, err := command.StdinPipe()
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
_, err = io.Copy(stdin, buf) _, err = io.Copy(stdin, buf)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
err = stdin.Close() err = stdin.Close()
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
output, err = command.Output() output, err = command.Output()
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to execute dot: %s (is graphviz package installed?)", err)) c.Fail(500, fmt.Errorf("unable to execute dot: %s (is graphviz package installed?)", err))
return return
} }
+1 -1
View File
@@ -8,7 +8,7 @@ import (
func apiPackagesShow(c *gin.Context) { func apiPackagesShow(c *gin.Context) {
p, err := context.CollectionFactory().PackageCollection().ByKey([]byte(c.Params.ByName("key"))) p, err := context.CollectionFactory().PackageCollection().ByKey([]byte(c.Params.ByName("key")))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
+48 -73
View File
@@ -4,10 +4,9 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/aptly-dev/aptly/deb"
"github.com/aptly-dev/aptly/pgp"
"github.com/aptly-dev/aptly/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/smira/aptly/deb"
"github.com/smira/aptly/utils"
) )
// SigningOptions is a shared between publish API GPG options structure // SigningOptions is a shared between publish API GPG options structure
@@ -21,12 +20,12 @@ type SigningOptions struct {
PassphraseFile string PassphraseFile string
} }
func getSigner(options *SigningOptions) (pgp.Signer, error) { func getSigner(options *SigningOptions) (utils.Signer, error) {
if options.Skip { if options.Skip {
return nil, nil return nil, nil
} }
signer := context.GetSigner() signer := &utils.GpgSigner{}
signer.SetKey(options.GpgKey) signer.SetKey(options.GpgKey)
signer.SetKeyRing(options.Keyring, options.SecretKeyring) signer.SetKeyRing(options.Keyring, options.SecretKeyring)
signer.SetPassphrase(options.Passphrase, options.PassphraseFile) signer.SetPassphrase(options.Passphrase, options.PassphraseFile)
@@ -60,8 +59,8 @@ func apiPublishList(c *gin.Context) {
defer snapshotCollection.RUnlock() defer snapshotCollection.RUnlock()
collection := context.CollectionFactory().PublishedRepoCollection() collection := context.CollectionFactory().PublishedRepoCollection()
collection.Lock() collection.RLock()
defer collection.Unlock() defer collection.RUnlock()
result := make([]*deb.PublishedRepo, 0, collection.Len()) result := make([]*deb.PublishedRepo, 0, collection.Len())
@@ -77,7 +76,7 @@ func apiPublishList(c *gin.Context) {
}) })
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -98,27 +97,24 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
Distribution string Distribution string
Label string Label string
Origin string Origin string
NotAutomatic string
ButAutomaticUpgrades string
ForceOverwrite bool ForceOverwrite bool
SkipContents *bool SkipContents *bool
Architectures []string Architectures []string
Signing SigningOptions Signing SigningOptions
AcquireByHash *bool
} }
if c.Bind(&b) != nil { if !c.Bind(&b) {
return return
} }
signer, err := getSigner(&b.Signing) signer, err := getSigner(&b.Signing)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err)) c.Fail(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
return return
} }
if len(b.Sources) == 0 { if len(b.Sources) == 0 {
c.AbortWithError(400, fmt.Errorf("unable to publish: soures are empty")) c.Fail(400, fmt.Errorf("unable to publish: soures are empty"))
return return
} }
@@ -129,51 +125,51 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
var snapshot *deb.Snapshot var snapshot *deb.Snapshot
snapshotCollection := context.CollectionFactory().SnapshotCollection() snapshotCollection := context.CollectionFactory().SnapshotCollection()
snapshotCollection.Lock() snapshotCollection.RLock()
defer snapshotCollection.Unlock() defer snapshotCollection.RUnlock()
for _, source := range b.Sources { for _, source := range b.Sources {
components = append(components, source.Component) components = append(components, source.Component)
snapshot, err = snapshotCollection.ByName(source.Name) snapshot, err = snapshotCollection.ByName(source.Name)
if err != nil { if err != nil {
c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err)) c.Fail(404, fmt.Errorf("unable to publish: %s", err))
return return
} }
err = snapshotCollection.LoadComplete(snapshot) err = snapshotCollection.LoadComplete(snapshot)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err)) c.Fail(500, fmt.Errorf("unable to publish: %s", err))
return return
} }
sources = append(sources, snapshot) sources = append(sources, snapshot)
} }
} else if b.SourceKind == deb.SourceLocalRepo { } else if b.SourceKind == "local" {
var localRepo *deb.LocalRepo var localRepo *deb.LocalRepo
localCollection := context.CollectionFactory().LocalRepoCollection() localCollection := context.CollectionFactory().LocalRepoCollection()
localCollection.Lock() localCollection.RLock()
defer localCollection.Unlock() defer localCollection.RUnlock()
for _, source := range b.Sources { for _, source := range b.Sources {
components = append(components, source.Component) components = append(components, source.Component)
localRepo, err = localCollection.ByName(source.Name) localRepo, err = localCollection.ByName(source.Name)
if err != nil { if err != nil {
c.AbortWithError(404, fmt.Errorf("unable to publish: %s", err)) c.Fail(404, fmt.Errorf("unable to publish: %s", err))
return return
} }
err = localCollection.LoadComplete(localRepo) err = localCollection.LoadComplete(localRepo)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err)) c.Fail(500, fmt.Errorf("unable to publish: %s", err))
} }
sources = append(sources, localRepo) sources = append(sources, localRepo)
} }
} else { } else {
c.AbortWithError(400, fmt.Errorf("unknown SourceKind")) c.Fail(400, fmt.Errorf("unknown SourceKind"))
return return
} }
@@ -183,18 +179,10 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
published, err := deb.NewPublishedRepo(storage, prefix, b.Distribution, b.Architectures, components, sources, context.CollectionFactory()) published, err := deb.NewPublishedRepo(storage, prefix, b.Distribution, b.Architectures, components, sources, context.CollectionFactory())
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err)) c.Fail(500, fmt.Errorf("unable to publish: %s", err))
return return
} }
if b.Origin != "" {
published.Origin = b.Origin published.Origin = b.Origin
}
if b.NotAutomatic != "" {
published.NotAutomatic = b.NotAutomatic
}
if b.ButAutomaticUpgrades != "" {
published.ButAutomaticUpgrades = b.ButAutomaticUpgrades
}
published.Label = b.Label published.Label = b.Label
published.SkipContents = context.Config().SkipContentsPublishing published.SkipContents = context.Config().SkipContentsPublishing
@@ -202,26 +190,22 @@ func apiPublishRepoOrSnapshot(c *gin.Context) {
published.SkipContents = *b.SkipContents published.SkipContents = *b.SkipContents
} }
if b.AcquireByHash != nil {
published.AcquireByHash = *b.AcquireByHash
}
duplicate := collection.CheckDuplicate(published) duplicate := collection.CheckDuplicate(published)
if duplicate != nil { if duplicate != nil {
context.CollectionFactory().PublishedRepoCollection().LoadComplete(duplicate, context.CollectionFactory()) context.CollectionFactory().PublishedRepoCollection().LoadComplete(duplicate, context.CollectionFactory())
c.AbortWithError(400, fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)) c.Fail(400, fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate))
return return
} }
err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, nil, b.ForceOverwrite) err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, nil, b.ForceOverwrite)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to publish: %s", err)) c.Fail(500, fmt.Errorf("unable to publish: %s", err))
return return
} }
err = collection.Add(published) err = collection.Add(published)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to save to DB: %s", err)) c.Fail(500, fmt.Errorf("unable to save to DB: %s", err))
return return
} }
@@ -238,32 +222,30 @@ func apiPublishUpdateSwitch(c *gin.Context) {
ForceOverwrite bool ForceOverwrite bool
Signing SigningOptions Signing SigningOptions
SkipContents *bool SkipContents *bool
SkipCleanup *bool
Snapshots []struct { Snapshots []struct {
Component string `binding:"required"` Component string `binding:"required"`
Name string `binding:"required"` Name string `binding:"required"`
} }
AcquireByHash *bool
} }
if c.Bind(&b) != nil { if !c.Bind(&b) {
return return
} }
signer, err := getSigner(&b.Signing) signer, err := getSigner(&b.Signing)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to initialize GPG signer: %s", err)) c.Fail(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
return return
} }
// published.LoadComplete would touch local repo collection // published.LoadComplete would touch local repo collection
localRepoCollection := context.CollectionFactory().LocalRepoCollection() localRepoCollection := context.CollectionFactory().LocalRepoCollection()
localRepoCollection.Lock() localRepoCollection.RLock()
defer localRepoCollection.Unlock() defer localRepoCollection.RUnlock()
snapshotCollection := context.CollectionFactory().SnapshotCollection() snapshotCollection := context.CollectionFactory().SnapshotCollection()
snapshotCollection.Lock() snapshotCollection.RLock()
defer snapshotCollection.Unlock() defer snapshotCollection.RUnlock()
collection := context.CollectionFactory().PublishedRepoCollection() collection := context.CollectionFactory().PublishedRepoCollection()
collection.Lock() collection.Lock()
@@ -271,20 +253,20 @@ func apiPublishUpdateSwitch(c *gin.Context) {
published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution) published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
if err != nil { if err != nil {
c.AbortWithError(404, fmt.Errorf("unable to update: %s", err)) c.Fail(404, fmt.Errorf("unable to update: %s", err))
return return
} }
err = collection.LoadComplete(published, context.CollectionFactory()) err = collection.LoadComplete(published, context.CollectionFactory())
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to update: %s", err)) c.Fail(500, fmt.Errorf("unable to update: %s", err))
return return
} }
var updatedComponents []string var updatedComponents []string
if published.SourceKind == deb.SourceLocalRepo { if published.SourceKind == "local" {
if len(b.Snapshots) > 0 { if len(b.Snapshots) > 0 {
c.AbortWithError(400, fmt.Errorf("snapshots shouldn't be given when updating local repo")) c.Fail(400, fmt.Errorf("snapshots shouldn't be given when updating local repo"))
return return
} }
updatedComponents = published.Components() updatedComponents = published.Components()
@@ -295,19 +277,19 @@ func apiPublishUpdateSwitch(c *gin.Context) {
publishedComponents := published.Components() publishedComponents := published.Components()
for _, snapshotInfo := range b.Snapshots { for _, snapshotInfo := range b.Snapshots {
if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) { if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) {
c.AbortWithError(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component)) c.Fail(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component))
return return
} }
snapshot, err2 := snapshotCollection.ByName(snapshotInfo.Name) snapshot, err := snapshotCollection.ByName(snapshotInfo.Name)
if err != nil { if err != nil {
c.AbortWithError(404, err2) c.Fail(404, err)
return return
} }
err2 = snapshotCollection.LoadComplete(snapshot) err = snapshotCollection.LoadComplete(snapshot)
if err2 != nil { if err != nil {
c.AbortWithError(500, err2) c.Fail(500, err)
return return
} }
@@ -315,7 +297,7 @@ func apiPublishUpdateSwitch(c *gin.Context) {
updatedComponents = append(updatedComponents, snapshotInfo.Component) updatedComponents = append(updatedComponents, snapshotInfo.Component)
} }
} else { } else {
c.AbortWithError(500, fmt.Errorf("unknown published repository type")) c.Fail(500, fmt.Errorf("unknown published repository type"))
return return
} }
@@ -323,30 +305,24 @@ func apiPublishUpdateSwitch(c *gin.Context) {
published.SkipContents = *b.SkipContents published.SkipContents = *b.SkipContents
} }
if b.AcquireByHash != nil {
published.AcquireByHash = *b.AcquireByHash
}
err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, nil, b.ForceOverwrite) err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, nil, b.ForceOverwrite)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to update: %s", err)) c.Fail(500, fmt.Errorf("unable to update: %s", err))
return return
} }
err = collection.Update(published) err = collection.Update(published)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to save to DB: %s", err)) c.Fail(500, fmt.Errorf("unable to save to DB: %s", err))
return return
} }
if b.SkipCleanup == nil || !*b.SkipCleanup {
err = collection.CleanupPrefixComponentFiles(published.Prefix, updatedComponents, err = collection.CleanupPrefixComponentFiles(published.Prefix, updatedComponents,
context.GetPublishedStorage(storage), context.CollectionFactory(), nil) context.GetPublishedStorage(storage), context.CollectionFactory(), nil)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to update: %s", err)) c.Fail(500, fmt.Errorf("unable to update: %s", err))
return return
} }
}
c.JSON(200, published) c.JSON(200, published)
} }
@@ -354,7 +330,6 @@ func apiPublishUpdateSwitch(c *gin.Context) {
// DELETE /publish/:prefix/:distribution // DELETE /publish/:prefix/:distribution
func apiPublishDrop(c *gin.Context) { func apiPublishDrop(c *gin.Context) {
force := c.Request.URL.Query().Get("force") == "1" force := c.Request.URL.Query().Get("force") == "1"
skipCleanup := c.Request.URL.Query().Get("SkipCleanup") == "1"
param := parseEscapedPath(c.Params.ByName("prefix")) param := parseEscapedPath(c.Params.ByName("prefix"))
storage, prefix := deb.ParsePrefix(param) storage, prefix := deb.ParsePrefix(param)
@@ -362,17 +337,17 @@ func apiPublishDrop(c *gin.Context) {
// published.LoadComplete would touch local repo collection // published.LoadComplete would touch local repo collection
localRepoCollection := context.CollectionFactory().LocalRepoCollection() localRepoCollection := context.CollectionFactory().LocalRepoCollection()
localRepoCollection.Lock() localRepoCollection.RLock()
defer localRepoCollection.Unlock() defer localRepoCollection.RUnlock()
collection := context.CollectionFactory().PublishedRepoCollection() collection := context.CollectionFactory().PublishedRepoCollection()
collection.Lock() collection.Lock()
defer collection.Unlock() defer collection.Unlock()
err := collection.Remove(context, storage, prefix, distribution, err := collection.Remove(context, storage, prefix, distribution,
context.CollectionFactory(), context.Progress(), force, skipCleanup) context.CollectionFactory(), context.Progress(), force)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to drop: %s", err)) c.Fail(500, fmt.Errorf("unable to drop: %s", err))
return return
} }
+35 -38
View File
@@ -5,11 +5,11 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/aptly-dev/aptly/aptly"
"github.com/aptly-dev/aptly/database"
"github.com/aptly-dev/aptly/deb"
"github.com/aptly-dev/aptly/utils"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/smira/aptly/aptly"
"github.com/smira/aptly/database"
"github.com/smira/aptly/deb"
"github.com/smira/aptly/utils"
) )
// GET /api/repos // GET /api/repos
@@ -37,7 +37,7 @@ func apiReposCreate(c *gin.Context) {
DefaultComponent string DefaultComponent string
} }
if c.Bind(&b) != nil { if !c.Bind(&b) {
return return
} }
@@ -51,7 +51,7 @@ func apiReposCreate(c *gin.Context) {
err := context.CollectionFactory().LocalRepoCollection().Add(repo) err := context.CollectionFactory().LocalRepoCollection().Add(repo)
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
@@ -66,7 +66,7 @@ func apiReposEdit(c *gin.Context) {
DefaultComponent *string DefaultComponent *string
} }
if c.Bind(&b) != nil { if !c.Bind(&b) {
return return
} }
@@ -76,7 +76,7 @@ func apiReposEdit(c *gin.Context) {
repo, err := collection.ByName(c.Params.ByName("name")) repo, err := collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
@@ -92,7 +92,7 @@ func apiReposEdit(c *gin.Context) {
err = collection.Update(repo) err = collection.Update(repo)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -107,7 +107,7 @@ func apiReposShow(c *gin.Context) {
repo, err := collection.ByName(c.Params.ByName("name")) repo, err := collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
@@ -132,27 +132,27 @@ func apiReposDrop(c *gin.Context) {
repo, err := collection.ByName(c.Params.ByName("name")) repo, err := collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
published := publishedCollection.ByLocalRepo(repo) published := publishedCollection.ByLocalRepo(repo)
if len(published) > 0 { if len(published) > 0 {
c.AbortWithError(409, fmt.Errorf("unable to drop, local repo is published")) c.Fail(409, fmt.Errorf("unable to drop, local repo is published"))
return return
} }
if !force { if !force {
snapshots := snapshotCollection.ByLocalRepoSource(repo) snapshots := snapshotCollection.ByLocalRepoSource(repo)
if len(snapshots) > 0 { if len(snapshots) > 0 {
c.AbortWithError(409, fmt.Errorf("unable to drop, local repo has snapshots, use ?force=1 to override")) c.Fail(409, fmt.Errorf("unable to drop, local repo has snapshots, use ?force=1 to override"))
return return
} }
} }
err = collection.Drop(repo) err = collection.Drop(repo)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -162,18 +162,18 @@ func apiReposDrop(c *gin.Context) {
// GET /api/repos/:name/packages // GET /api/repos/:name/packages
func apiReposPackagesShow(c *gin.Context) { func apiReposPackagesShow(c *gin.Context) {
collection := context.CollectionFactory().LocalRepoCollection() collection := context.CollectionFactory().LocalRepoCollection()
collection.Lock() collection.RLock()
defer collection.Unlock() defer collection.RUnlock()
repo, err := collection.ByName(c.Params.ByName("name")) repo, err := collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
err = collection.LoadComplete(repo) err = collection.LoadComplete(repo)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -186,7 +186,7 @@ func apiReposPackagesAddDelete(c *gin.Context, cb func(list *deb.PackageList, p
PackageRefs []string PackageRefs []string
} }
if c.Bind(&b) != nil { if !c.Bind(&b) {
return return
} }
@@ -196,19 +196,19 @@ func apiReposPackagesAddDelete(c *gin.Context, cb func(list *deb.PackageList, p
repo, err := collection.ByName(c.Params.ByName("name")) repo, err := collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
err = collection.LoadComplete(repo) err = collection.LoadComplete(repo)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
list, err := deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), nil) list, err := deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), nil)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -219,15 +219,15 @@ func apiReposPackagesAddDelete(c *gin.Context, cb func(list *deb.PackageList, p
p, err = context.CollectionFactory().PackageCollection().ByKey([]byte(ref)) p, err = context.CollectionFactory().PackageCollection().ByKey([]byte(ref))
if err != nil { if err != nil {
if err == database.ErrNotFound { if err == database.ErrNotFound {
c.AbortWithError(404, fmt.Errorf("package %s: %s", ref, err)) c.Fail(404, fmt.Errorf("package %s: %s", ref, err))
} else { } else {
c.AbortWithError(500, err) c.Fail(500, err)
} }
return return
} }
err = cb(list, p) err = cb(list, p)
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
} }
@@ -236,7 +236,7 @@ func apiReposPackagesAddDelete(c *gin.Context, cb func(list *deb.PackageList, p
err = context.CollectionFactory().LocalRepoCollection().Update(repo) err = context.CollectionFactory().LocalRepoCollection().Update(repo)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to save: %s", err)) c.Fail(500, fmt.Errorf("unable to save: %s", err))
return return
} }
@@ -276,7 +276,7 @@ func apiReposPackageFromDir(c *gin.Context) {
fileParam := c.Params.ByName("file") fileParam := c.Params.ByName("file")
if fileParam != "" && !verifyPath(fileParam) { if fileParam != "" && !verifyPath(fileParam) {
c.AbortWithError(400, fmt.Errorf("wrong file")) c.Fail(400, fmt.Errorf("wrong file"))
return return
} }
@@ -286,22 +286,21 @@ func apiReposPackageFromDir(c *gin.Context) {
repo, err := collection.ByName(c.Params.ByName("name")) repo, err := collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
err = collection.LoadComplete(repo) err = collection.LoadComplete(repo)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
verifier := context.GetVerifier() verifier := &utils.GpgVerifier{}
var ( var (
sources []string sources []string
packageFiles, failedFiles []string packageFiles, failedFiles []string
otherFiles []string
processedFiles, failedFiles2 []string processedFiles, failedFiles2 []string
reporter = &aptly.RecordingResultReporter{ reporter = &aptly.RecordingResultReporter{
Warnings: []string{}, Warnings: []string{},
@@ -317,22 +316,20 @@ func apiReposPackageFromDir(c *gin.Context) {
sources = []string{filepath.Join(context.UploadPath(), c.Params.ByName("dir"), c.Params.ByName("file"))} sources = []string{filepath.Join(context.UploadPath(), c.Params.ByName("dir"), c.Params.ByName("file"))}
} }
packageFiles, otherFiles, failedFiles = deb.CollectPackageFiles(sources, reporter) packageFiles, failedFiles = deb.CollectPackageFiles(sources, reporter)
list, err = deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), nil) list, err = deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), nil)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to load packages: %s", err)) c.Fail(500, fmt.Errorf("unable to load packages: %s", err))
return return
} }
processedFiles, failedFiles2, err = deb.ImportPackageFiles(list, packageFiles, forceReplace, verifier, context.PackagePool(), processedFiles, failedFiles2, err = deb.ImportPackageFiles(list, packageFiles, forceReplace, verifier, context.PackagePool(),
context.CollectionFactory().PackageCollection(), reporter, nil, context.CollectionFactory().ChecksumCollection()) context.CollectionFactory().PackageCollection(), reporter, nil)
failedFiles = append(failedFiles, failedFiles2...) failedFiles = append(failedFiles, failedFiles2...)
processedFiles = append(processedFiles, otherFiles...)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to import package files: %s", err)) c.Fail(500, fmt.Errorf("unable to import package files: %s", err))
return return
} }
@@ -340,7 +337,7 @@ func apiReposPackageFromDir(c *gin.Context) {
err = context.CollectionFactory().LocalRepoCollection().Update(repo) err = context.CollectionFactory().LocalRepoCollection().Update(repo)
if err != nil { if err != nil {
c.AbortWithError(500, fmt.Errorf("unable to save: %s", err)) c.Fail(500, fmt.Errorf("unable to save: %s", err))
return return
} }
+13 -16
View File
@@ -3,8 +3,8 @@ package api
import ( import (
"net/http" "net/http"
ctx "github.com/aptly-dev/aptly/context"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
ctx "github.com/smira/aptly/context"
) )
var context *ctx.AptlyContext var context *ctx.AptlyContext
@@ -20,35 +20,32 @@ func Router(c *ctx.AptlyContext) http.Handler {
// We use a goroutine to count the number of // We use a goroutine to count the number of
// concurrent requests. When no more requests are // concurrent requests. When no more requests are
// running, we close the database to free the lock. // running, we close the database to free the lock.
requests := make(chan dbRequest) requests := make(chan int)
acks := make(chan error)
go acquireDatabase(requests) go acquireDatabase(requests, acks)
go cacheFlusher(requests, acks)
router.Use(func(c *gin.Context) { router.Use(func(c *gin.Context) {
var err error requests <- acquiredb
err := <-acks
errCh := make(chan error)
requests <- dbRequest{acquiredb, errCh}
err = <-errCh
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
defer func() { defer func() {
requests <- dbRequest{releasedb, errCh} requests <- releasedb
err = <-errCh err = <-acks
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return
} }
}() }()
c.Next() c.Next()
}) })
} else { } else {
go cacheFlusher() go cacheFlusher(nil, nil)
} }
root := router.Group("/api") root := router.Group("/api")
+47 -47
View File
@@ -3,9 +3,9 @@ package api
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/database"
"github.com/aptly-dev/aptly/deb"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/smira/aptly/database"
"github.com/smira/aptly/deb"
) )
// GET /api/snapshots // GET /api/snapshots
@@ -42,13 +42,13 @@ func apiSnapshotsCreateFromMirror(c *gin.Context) {
Description string Description string
} }
if c.Bind(&b) != nil { if !c.Bind(&b) {
return return
} }
collection := context.CollectionFactory().RemoteRepoCollection() collection := context.CollectionFactory().RemoteRepoCollection()
collection.Lock() collection.RLock()
defer collection.Unlock() defer collection.RUnlock()
snapshotCollection := context.CollectionFactory().SnapshotCollection() snapshotCollection := context.CollectionFactory().SnapshotCollection()
snapshotCollection.Lock() snapshotCollection.Lock()
@@ -56,25 +56,25 @@ func apiSnapshotsCreateFromMirror(c *gin.Context) {
repo, err = collection.ByName(c.Params.ByName("name")) repo, err = collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
err = repo.CheckLock() err = repo.CheckLock()
if err != nil { if err != nil {
c.AbortWithError(409, err) c.Fail(409, err)
return return
} }
err = collection.LoadComplete(repo) err = collection.LoadComplete(repo)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
snapshot, err = deb.NewSnapshotFromRepository(b.Name, repo) snapshot, err = deb.NewSnapshotFromRepository(b.Name, repo)
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
@@ -84,7 +84,7 @@ func apiSnapshotsCreateFromMirror(c *gin.Context) {
err = snapshotCollection.Add(snapshot) err = snapshotCollection.Add(snapshot)
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
@@ -105,7 +105,7 @@ func apiSnapshotsCreate(c *gin.Context) {
PackageRefs []string PackageRefs []string
} }
if c.Bind(&b) != nil { if !c.Bind(&b) {
return return
} }
@@ -124,13 +124,13 @@ func apiSnapshotsCreate(c *gin.Context) {
for i := range b.SourceSnapshots { for i := range b.SourceSnapshots {
sources[i], err = snapshotCollection.ByName(b.SourceSnapshots[i]) sources[i], err = snapshotCollection.ByName(b.SourceSnapshots[i])
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
err = snapshotCollection.LoadComplete(sources[i]) err = snapshotCollection.LoadComplete(sources[i])
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
} }
@@ -144,15 +144,15 @@ func apiSnapshotsCreate(c *gin.Context) {
p, err = context.CollectionFactory().PackageCollection().ByKey([]byte(ref)) p, err = context.CollectionFactory().PackageCollection().ByKey([]byte(ref))
if err != nil { if err != nil {
if err == database.ErrNotFound { if err == database.ErrNotFound {
c.AbortWithError(404, fmt.Errorf("package %s: %s", ref, err)) c.Fail(404, fmt.Errorf("package %s: %s", ref, err))
} else { } else {
c.AbortWithError(500, err) c.Fail(500, err)
} }
return return
} }
err = list.Add(p) err = list.Add(p)
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
} }
@@ -161,7 +161,7 @@ func apiSnapshotsCreate(c *gin.Context) {
err = snapshotCollection.Add(snapshot) err = snapshotCollection.Add(snapshot)
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
@@ -181,13 +181,13 @@ func apiSnapshotsCreateFromRepository(c *gin.Context) {
Description string Description string
} }
if c.Bind(&b) != nil { if !c.Bind(&b) {
return return
} }
collection := context.CollectionFactory().LocalRepoCollection() collection := context.CollectionFactory().LocalRepoCollection()
collection.Lock() collection.RLock()
defer collection.Unlock() defer collection.RUnlock()
snapshotCollection := context.CollectionFactory().SnapshotCollection() snapshotCollection := context.CollectionFactory().SnapshotCollection()
snapshotCollection.Lock() snapshotCollection.Lock()
@@ -195,19 +195,19 @@ func apiSnapshotsCreateFromRepository(c *gin.Context) {
repo, err = collection.ByName(c.Params.ByName("name")) repo, err = collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
err = collection.LoadComplete(repo) err = collection.LoadComplete(repo)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
snapshot, err = deb.NewSnapshotFromLocalRepo(b.Name, repo) snapshot, err = deb.NewSnapshotFromLocalRepo(b.Name, repo)
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
@@ -217,7 +217,7 @@ func apiSnapshotsCreateFromRepository(c *gin.Context) {
err = snapshotCollection.Add(snapshot) err = snapshotCollection.Add(snapshot)
if err != nil { if err != nil {
c.AbortWithError(400, err) c.Fail(400, err)
return return
} }
@@ -236,7 +236,7 @@ func apiSnapshotsUpdate(c *gin.Context) {
Description string Description string
} }
if c.Bind(&b) != nil { if !c.Bind(&b) {
return return
} }
@@ -246,13 +246,13 @@ func apiSnapshotsUpdate(c *gin.Context) {
snapshot, err = collection.ByName(c.Params.ByName("name")) snapshot, err = collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
_, err = collection.ByName(b.Name) _, err = collection.ByName(b.Name)
if err == nil { if err == nil {
c.AbortWithError(409, fmt.Errorf("unable to rename: snapshot %s already exists", b.Name)) c.Fail(409, fmt.Errorf("unable to rename: snapshot %s already exists", b.Name))
return return
} }
@@ -266,7 +266,7 @@ func apiSnapshotsUpdate(c *gin.Context) {
err = context.CollectionFactory().SnapshotCollection().Update(snapshot) err = context.CollectionFactory().SnapshotCollection().Update(snapshot)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -276,18 +276,18 @@ func apiSnapshotsUpdate(c *gin.Context) {
// GET /api/snapshots/:name // GET /api/snapshots/:name
func apiSnapshotsShow(c *gin.Context) { func apiSnapshotsShow(c *gin.Context) {
collection := context.CollectionFactory().SnapshotCollection() collection := context.CollectionFactory().SnapshotCollection()
collection.Lock() collection.RLock()
defer collection.Unlock() defer collection.RUnlock()
snapshot, err := collection.ByName(c.Params.ByName("name")) snapshot, err := collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
err = collection.LoadComplete(snapshot) err = collection.LoadComplete(snapshot)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -309,28 +309,28 @@ func apiSnapshotsDrop(c *gin.Context) {
snapshot, err := snapshotCollection.ByName(name) snapshot, err := snapshotCollection.ByName(name)
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
published := publishedCollection.BySnapshot(snapshot) published := publishedCollection.BySnapshot(snapshot)
if len(published) > 0 { if len(published) > 0 {
c.AbortWithError(409, fmt.Errorf("unable to drop: snapshot is published")) c.Fail(409, fmt.Errorf("unable to drop: snapshot is published"))
return return
} }
if !force { if !force {
snapshots := snapshotCollection.BySnapshotSource(snapshot) snapshots := snapshotCollection.BySnapshotSource(snapshot)
if len(snapshots) > 0 { if len(snapshots) > 0 {
c.AbortWithError(409, fmt.Errorf("won't delete snapshot that was used as source for other snapshots, use ?force=1 to override")) c.Fail(409, fmt.Errorf("won't delete snapshot that was used as source for other snapshots, use ?force=1 to override"))
return return
} }
} }
err = snapshotCollection.Drop(snapshot) err = snapshotCollection.Drop(snapshot)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -342,37 +342,37 @@ func apiSnapshotsDiff(c *gin.Context) {
onlyMatching := c.Request.URL.Query().Get("onlyMatching") == "1" onlyMatching := c.Request.URL.Query().Get("onlyMatching") == "1"
collection := context.CollectionFactory().SnapshotCollection() collection := context.CollectionFactory().SnapshotCollection()
collection.Lock() collection.RLock()
defer collection.Unlock() defer collection.RUnlock()
snapshotA, err := collection.ByName(c.Params.ByName("name")) snapshotA, err := collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
snapshotB, err := collection.ByName(c.Params.ByName("withSnapshot")) snapshotB, err := collection.ByName(c.Params.ByName("withSnapshot"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
err = collection.LoadComplete(snapshotA) err = collection.LoadComplete(snapshotA)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
err = collection.LoadComplete(snapshotB) err = collection.LoadComplete(snapshotB)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
// Calculate diff // Calculate diff
diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), context.CollectionFactory().PackageCollection()) diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), context.CollectionFactory().PackageCollection())
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
@@ -392,18 +392,18 @@ func apiSnapshotsDiff(c *gin.Context) {
// GET /api/snapshots/:name/packages // GET /api/snapshots/:name/packages
func apiSnapshotsSearchPackages(c *gin.Context) { func apiSnapshotsSearchPackages(c *gin.Context) {
collection := context.CollectionFactory().SnapshotCollection() collection := context.CollectionFactory().SnapshotCollection()
collection.Lock() collection.RLock()
defer collection.Unlock() defer collection.RUnlock()
snapshot, err := collection.ByName(c.Params.ByName("name")) snapshot, err := collection.ByName(c.Params.ByName("name"))
if err != nil { if err != nil {
c.AbortWithError(404, err) c.Fail(404, err)
return return
} }
err = collection.LoadComplete(snapshot) err = collection.LoadComplete(snapshot)
if err != nil { if err != nil {
c.AbortWithError(500, err) c.Fail(500, err)
return return
} }
-12
View File
@@ -1,12 +0,0 @@
[Unit]
Description=APT repository API
After=network.target
Documentation=man:aptly(1)
Documentation=https://www.aptly.info/doc/api/
[Service]
Type=simple
ExecStart=/usr/bin/aptly serve api -no-lock -listen=127.0.0.1:8081
[Install]
WantedBy=multi-user.target
-12
View File
@@ -1,12 +0,0 @@
[Unit]
Description=APT repository server
After=network.target
Documentation=man:aptly(1)
Documentation=https://www.aptly.info/doc/commands/
[Service]
Type=simple
ExecStart=/usr/bin/aptly serve -listen=127.0.0.1:8080
[Install]
WantedBy=multi-user.target
+21 -64
View File
@@ -3,59 +3,25 @@
package aptly package aptly
import ( import (
"context"
"io" "io"
"os"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
) )
// ReadSeekerCloser = ReadSeeker + Closer
type ReadSeekerCloser interface {
io.ReadSeeker
io.Closer
}
// PackagePool is asbtraction of package pool storage. // PackagePool is asbtraction of package pool storage.
// //
// PackagePool stores all the package files, deduplicating them. // PackagePool stores all the package files, deduplicating them.
type PackagePool interface { type PackagePool interface {
// Verify checks whether file exists in the pool and fills back checksum info // Path returns full path to package file in pool given any name and hash of file contents
// Path(filename string, hashMD5 string) (string, error)
// if poolPath is empty, poolPath is generated automatically based on checksum info (if available) // RelativePath returns path relative to pool's root for package files given MD5 and original filename
// in any case, if function returns true, it also fills back checksums with complete information about the file in the pool RelativePath(filename string, hashMD5 string) (string, error)
Verify(poolPath, basename string, checksums *utils.ChecksumInfo, checksumStorage ChecksumStorage) (string, bool, error)
// Import copies file into package pool
//
// - srcPath is full path to source file as it is now
// - basename is desired human-readable name (canonical filename)
// - checksums are used to calculate file placement
// - move indicates whether srcPath can be removed
Import(srcPath, basename string, checksums *utils.ChecksumInfo, move bool, storage ChecksumStorage) (path string, err error)
// LegacyPath returns legacy (pre 1.1) path to package file (relative to root)
LegacyPath(filename string, checksums *utils.ChecksumInfo) (string, error)
// Stat returns Unix stat(2) info
Stat(path string) (os.FileInfo, error)
// Open returns ReadSeekerCloser to access the file
Open(path string) (ReadSeekerCloser, error)
// FilepathList returns file paths of all the files in the pool // FilepathList returns file paths of all the files in the pool
FilepathList(progress Progress) ([]string, error) FilepathList(progress Progress) ([]string, error)
// Remove deletes file in package pool returns its size // Remove deletes file in package pool returns its size
Remove(path string) (size int64, err error) Remove(path string) (size int64, err error)
} // Import copies file into package pool
Import(path string, hashMD5 string) error
// LocalPackagePool is implemented by PackagePools residing on the same filesystem
type LocalPackagePool interface {
// GenerateTempPath generates temporary path for download (which is fast to import into package pool later on)
GenerateTempPath(filename string) (string, error)
// Link generates hardlink to destination path
Link(path, dstPath string) error
// Symlink generates symlink to destination path
Symlink(path, dstPath string) error
// FullPath generates full path to the file in pool
//
// Please use with care: it's not supposed to be used to access files
FullPath(path string) string
} }
// PublishedStorage is abstraction of filesystem storing all published repositories // PublishedStorage is abstraction of filesystem storing all published repositories
@@ -69,23 +35,15 @@ type PublishedStorage interface {
// Remove removes single file under public path // Remove removes single file under public path
Remove(path string) error Remove(path string) error
// LinkFromPool links package file from pool to dist's pool location // LinkFromPool links package file from pool to dist's pool location
LinkFromPool(publishedDirectory, baseName string, sourcePool PackagePool, sourcePath string, sourceChecksums utils.ChecksumInfo, force bool) error LinkFromPool(publishedDirectory string, sourcePool PackagePool, sourcePath, sourceMD5 string, force bool) error
// Filelist returns list of files under prefix // Filelist returns list of files under prefix
Filelist(prefix string) ([]string, error) Filelist(prefix string) ([]string, error)
// RenameFile renames (moves) file // RenameFile renames (moves) file
RenameFile(oldName, newName string) error RenameFile(oldName, newName string) error
// SymLink creates a symbolic link, which can be read with ReadLink
SymLink(src string, dst string) error
// HardLink creates a hardlink of a file
HardLink(src string, dst string) error
// FileExists returns true if path exists
FileExists(path string) (bool, error)
// ReadLink returns the symbolic link pointed to by path
ReadLink(path string) (string, error)
} }
// FileSystemPublishedStorage is published storage on filesystem // LocalPublishedStorage is published storage on local filesystem
type FileSystemPublishedStorage interface { type LocalPublishedStorage interface {
// PublicPath returns root of public part // PublicPath returns root of public part
PublicPath() string PublicPath() string
} }
@@ -118,24 +76,23 @@ type Progress interface {
Printf(msg string, a ...interface{}) Printf(msg string, a ...interface{})
// ColoredPrintf does printf in colored way + newline // ColoredPrintf does printf in colored way + newline
ColoredPrintf(msg string, a ...interface{}) ColoredPrintf(msg string, a ...interface{})
// PrintfStdErr does printf but in safe manner to stderr
PrintfStdErr(msg string, a ...interface{})
} }
// Downloader is parallel HTTP fetcher // Downloader is parallel HTTP fetcher
type Downloader interface { type Downloader interface {
// Download starts new download task // Download starts new download task
Download(ctx context.Context, url string, destination string) error Download(url string, destination string, result chan<- error)
// DownloadWithChecksum starts new download task with checksum verification // DownloadWithChecksum starts new download task with checksum verification
DownloadWithChecksum(ctx context.Context, url string, destination string, expected *utils.ChecksumInfo, ignoreMismatch bool, maxTries int) error DownloadWithChecksum(url string, destination string, result chan<- error, expected utils.ChecksumInfo, ignoreMismatch bool, maxTries int)
// Pause pauses task processing
Pause()
// Resume resumes task processing
Resume()
// Shutdown stops downloader after current tasks are finished,
// but doesn't process rest of queue
Shutdown()
// Abort stops downloader without waiting for shutdown
Abort()
// GetProgress returns Progress object // GetProgress returns Progress object
GetProgress() Progress GetProgress() Progress
} }
// ChecksumStorage is stores checksums in some (persistent) storage
type ChecksumStorage interface {
// Get finds checksums in DB by path
Get(path string) (*utils.ChecksumInfo, error)
// Update adds or updates information about checksum in DB
Update(path string, c *utils.ChecksumInfo) error
}
+4 -7
View File
@@ -7,9 +7,9 @@ import (
"net/url" "net/url"
"os" "os"
"github.com/aptly-dev/aptly/api" "github.com/smira/aptly/api"
"github.com/aptly-dev/aptly/systemd/activation" "github.com/smira/aptly/systemd/activation"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -59,14 +59,11 @@ func aptlyAPIServe(cmd *commander.Command, args []string) error {
if err == nil && listenURL.Scheme == "unix" { if err == nil && listenURL.Scheme == "unix" {
file := listenURL.Path file := listenURL.Path
os.Remove(file) os.Remove(file)
listener, err := net.Listen("unix", file)
var listener net.Listener
listener, err = net.Listen("unix", file)
if err != nil { if err != nil {
return fmt.Errorf("failed to listen on: %s\n%s", file, err) return fmt.Errorf("failed to listen on: %s\n%s", file, err)
} }
defer listener.Close() defer listener.Close()
err = http.Serve(listener, api.Router(context)) err = http.Serve(listener, api.Router(context))
if err != nil { if err != nil {
return fmt.Errorf("unable to serve: %s", err) return fmt.Errorf("unable to serve: %s", err)
+16 -21
View File
@@ -8,18 +8,12 @@ import (
"text/template" "text/template"
"time" "time"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
// Various command flags/UI things
const (
Yes = "yes"
No = "no"
)
// ListPackagesRefList shows list of packages in PackageRefList // ListPackagesRefList shows list of packages in PackageRefList
func ListPackagesRefList(reflist *deb.PackageRefList) (err error) { func ListPackagesRefList(reflist *deb.PackageRefList) (err error) {
fmt.Printf("Packages:\n") fmt.Printf("Packages:\n")
@@ -28,22 +22,26 @@ func ListPackagesRefList(reflist *deb.PackageRefList) (err error) {
return return
} }
list, err := deb.NewPackageListFromRefList(reflist, context.CollectionFactory().PackageCollection(), context.Progress()) err = reflist.ForEach(func(key []byte) error {
p, err2 := context.CollectionFactory().PackageCollection().ByKey(key)
if err2 != nil {
return err2
}
fmt.Printf(" %s\n", p)
return nil
})
if err != nil { if err != nil {
return fmt.Errorf("unable to load packages: %s", err) return fmt.Errorf("unable to load packages: %s", err)
} }
return PrintPackageList(list, "", " ") return
} }
// PrintPackageList shows package list with specified format or default representation // PrintPackageList shows package list with specified format or default representation
func PrintPackageList(result *deb.PackageList, format, prefix string) error { func PrintPackageList(result *deb.PackageList, format string) error {
result.PrepareIndex()
if format == "" { if format == "" {
return result.ForEachIndexed(func(p *deb.Package) error { return result.ForEach(func(p *deb.Package) error {
context.Progress().Printf(prefix+"%s\n", p) context.Progress().Printf("%s\n", p)
return nil return nil
}) })
} }
@@ -53,13 +51,13 @@ func PrintPackageList(result *deb.PackageList, format, prefix string) error {
return fmt.Errorf("error parsing -format template: %s", err) return fmt.Errorf("error parsing -format template: %s", err)
} }
return result.ForEachIndexed(func(p *deb.Package) error { return result.ForEach(func(p *deb.Package) error {
b := &bytes.Buffer{} b := &bytes.Buffer{}
err = formatTemplate.Execute(b, p.ExtendedStanza()) err = formatTemplate.Execute(b, p.ExtendedStanza())
if err != nil { if err != nil {
return fmt.Errorf("error applying template: %s", err) return fmt.Errorf("error applying template: %s", err)
} }
context.Progress().Printf(prefix+"%s\n", b.String()) context.Progress().Printf("%s\n", b.String())
return nil return nil
}) })
@@ -111,15 +109,12 @@ package environment to new version.`,
}, },
} }
cmd.Flag.Int("db-open-attempts", 10, "number of attempts to open DB if it's locked by other instance")
cmd.Flag.Bool("dep-follow-suggests", false, "when processing dependencies, follow Suggests") cmd.Flag.Bool("dep-follow-suggests", false, "when processing dependencies, follow Suggests")
cmd.Flag.Bool("dep-follow-source", false, "when processing dependencies, follow from binary to Source packages") cmd.Flag.Bool("dep-follow-source", false, "when processing dependencies, follow from binary to Source packages")
cmd.Flag.Bool("dep-follow-recommends", false, "when processing dependencies, follow Recommends") 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 dependency is 'a|b'") cmd.Flag.Bool("dep-follow-all-variants", false, "when processing dependencies, follow a & b if dependency is 'a|b'")
cmd.Flag.Bool("dep-verbose-resolve", false, "when processing dependencies, print detailed logs")
cmd.Flag.String("architectures", "", "list of architectures to consider during (comma-separated), default to all available") 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)") cmd.Flag.String("config", "", "location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)")
cmd.Flag.String("gpg-provider", "", "PGP implementation (\"gpg\" for external gpg or \"internal\" for Go internal implementation)")
if aptly.EnableDebug { if aptly.EnableDebug {
cmd.Flag.String("cpuprofile", "", "write cpu profile to file") cmd.Flag.String("cpuprofile", "", "write cpu profile to file")
+1 -6
View File
@@ -1,7 +1,7 @@
package cmd package cmd
import ( import (
ctx "github.com/aptly-dev/aptly/context" ctx "github.com/smira/aptly/context"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -29,8 +29,3 @@ func InitContext(flags *flag.FlagSet) error {
return err return err
} }
// GetContext gives access to the context
func GetContext() *ctx.AptlyContext {
return context
}
+15 -15
View File
@@ -5,8 +5,8 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
) )
@@ -37,9 +37,9 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
context.Progress().ColoredPrintf("- @{g}%s@|", repo.Name) context.Progress().ColoredPrintf("- @{g}%s@|", repo.Name)
} }
e := context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo) err := context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
if e != nil { if err != nil {
return e return err
} }
if repo.RefList() != nil { if repo.RefList() != nil {
existingPackageRefs = existingPackageRefs.Merge(repo.RefList(), false, true) existingPackageRefs = existingPackageRefs.Merge(repo.RefList(), false, true)
@@ -67,9 +67,9 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
context.Progress().ColoredPrintf("- @{g}%s@|", repo.Name) context.Progress().ColoredPrintf("- @{g}%s@|", repo.Name)
} }
e := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo) err := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if e != nil { if err != nil {
return e return err
} }
if repo.RefList() != nil { if repo.RefList() != nil {
@@ -98,9 +98,9 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
context.Progress().ColoredPrintf("- @{g}%s@|", snapshot.Name) context.Progress().ColoredPrintf("- @{g}%s@|", snapshot.Name)
} }
e := context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot) err := context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
if e != nil { if err != nil {
return e return err
} }
existingPackageRefs = existingPackageRefs.Merge(snapshot.RefList(), false, true) existingPackageRefs = existingPackageRefs.Merge(snapshot.RefList(), false, true)
@@ -125,12 +125,12 @@ func aptlyDbCleanup(cmd *commander.Command, args []string) error {
if verbose { if verbose {
context.Progress().ColoredPrintf("- @{g}%s:%s/%s{|}", published.Storage, published.Prefix, published.Distribution) context.Progress().ColoredPrintf("- @{g}%s:%s/%s{|}", published.Storage, published.Prefix, published.Distribution)
} }
if published.SourceKind != deb.SourceLocalRepo { if published.SourceKind != "local" {
return nil return nil
} }
e := context.CollectionFactory().PublishedRepoCollection().LoadComplete(published, context.CollectionFactory()) err := context.CollectionFactory().PublishedRepoCollection().LoadComplete(published, context.CollectionFactory())
if e != nil { if err != nil {
return e return err
} }
for _, component := range published.Components() { for _, component := range published.Components() {
+1 -1
View File
@@ -1,7 +1,7 @@
package cmd package cmd
import ( import (
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/database"
"github.com/smira/commander" "github.com/smira/commander"
) )
+2 -2
View File
@@ -12,8 +12,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
) )
+3 -3
View File
@@ -3,19 +3,19 @@ package cmd
import ( import (
"strings" "strings"
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
func getVerifier(flags *flag.FlagSet) (pgp.Verifier, error) { func getVerifier(flags *flag.FlagSet) (utils.Verifier, error) {
if LookupOption(context.Config().GpgDisableVerify, flags, "ignore-signatures") { if LookupOption(context.Config().GpgDisableVerify, flags, "ignore-signatures") {
return nil, nil return nil, nil
} }
keyRings := flags.Lookup("keyring").Value.Get().([]string) keyRings := flags.Lookup("keyring").Value.Get().([]string)
verifier := context.GetVerifier() verifier := &utils.GpgVerifier{}
for _, keyRing := range keyRings { for _, keyRing := range keyRings {
verifier.AddKeyring(keyRing) verifier.AddKeyring(keyRing)
} }
+2 -2
View File
@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/query" "github.com/smira/aptly/query"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
+2 -19
View File
@@ -3,8 +3,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/query"
"github.com/aptly-dev/aptly/query"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -26,7 +25,6 @@ func aptlyMirrorEdit(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to edit: %s", err) return fmt.Errorf("unable to edit: %s", err)
} }
fetchMirror := false
context.Flags().Visit(func(flag *flag.Flag) { context.Flags().Visit(func(flag *flag.Flag) {
switch flag.Name { switch flag.Name {
case "filter": case "filter":
@@ -37,9 +35,6 @@ func aptlyMirrorEdit(cmd *commander.Command, args []string) error {
repo.DownloadSources = flag.Value.Get().(bool) repo.DownloadSources = flag.Value.Get().(bool)
case "with-udebs": case "with-udebs":
repo.DownloadUdebs = flag.Value.Get().(bool) repo.DownloadUdebs = flag.Value.Get().(bool)
case "archive-url":
repo.SetArchiveRoot(flag.Value.String())
fetchMirror = true
} }
}) })
@@ -56,17 +51,8 @@ func aptlyMirrorEdit(cmd *commander.Command, args []string) error {
if context.GlobalFlags().Lookup("architectures").Value.String() != "" { if context.GlobalFlags().Lookup("architectures").Value.String() != "" {
repo.Architectures = context.ArchitecturesList() repo.Architectures = context.ArchitecturesList()
fetchMirror = true
}
if fetchMirror { err = repo.Fetch(context.Downloader(), nil)
var verifier pgp.Verifier
verifier, err = getVerifier(context.Flags())
if err != nil {
return fmt.Errorf("unable to initialize GPG verifier: %s", err)
}
err = repo.Fetch(context.Downloader(), verifier)
if err != nil { if err != nil {
return fmt.Errorf("unable to edit: %s", err) return fmt.Errorf("unable to edit: %s", err)
} }
@@ -97,13 +83,10 @@ Example:
Flag: *flag.NewFlagSet("aptly-mirror-edit", flag.ExitOnError), Flag: *flag.NewFlagSet("aptly-mirror-edit", flag.ExitOnError),
} }
cmd.Flag.String("archive-url", "", "archive url is the root of archive")
cmd.Flag.String("filter", "", "filter packages in mirror") cmd.Flag.String("filter", "", "filter packages in mirror")
cmd.Flag.Bool("filter-with-deps", false, "when filtering, include dependencies of matching packages as well") cmd.Flag.Bool("filter-with-deps", false, "when filtering, include dependencies of matching packages as well")
cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures")
cmd.Flag.Bool("with-sources", false, "download source packages in addition to binary packages") cmd.Flag.Bool("with-sources", false, "download source packages in addition to binary packages")
cmd.Flag.Bool("with-udebs", false, "download .udeb packages (Debian installer support)") cmd.Flag.Bool("with-udebs", false, "download .udeb packages (Debian installer support)")
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)")
return cmd return cmd
} }
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
+1 -1
View File
@@ -3,7 +3,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
+8 -8
View File
@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -37,21 +37,21 @@ func aptlyMirrorShow(cmd *commander.Command, args []string) error {
fmt.Printf("Distribution: %s\n", repo.Distribution) fmt.Printf("Distribution: %s\n", repo.Distribution)
fmt.Printf("Components: %s\n", strings.Join(repo.Components, ", ")) fmt.Printf("Components: %s\n", strings.Join(repo.Components, ", "))
fmt.Printf("Architectures: %s\n", strings.Join(repo.Architectures, ", ")) fmt.Printf("Architectures: %s\n", strings.Join(repo.Architectures, ", "))
downloadSources := No downloadSources := "no"
if repo.DownloadSources { if repo.DownloadSources {
downloadSources = Yes downloadSources = "yes"
} }
fmt.Printf("Download Sources: %s\n", downloadSources) fmt.Printf("Download Sources: %s\n", downloadSources)
downloadUdebs := No downloadUdebs := "no"
if repo.DownloadUdebs { if repo.DownloadUdebs {
downloadUdebs = Yes downloadUdebs = "yes"
} }
fmt.Printf("Download .udebs: %s\n", downloadUdebs) fmt.Printf("Download .udebs: %s\n", downloadUdebs)
if repo.Filter != "" { if repo.Filter != "" {
fmt.Printf("Filter: %s\n", repo.Filter) fmt.Printf("Filter: %s\n", repo.Filter)
filterWithDeps := No filterWithDeps := "no"
if repo.FilterWithDeps { if repo.FilterWithDeps {
filterWithDeps = Yes filterWithDeps = "yes"
} }
fmt.Printf("Filter With Deps: %s\n", filterWithDeps) fmt.Printf("Filter With Deps: %s\n", filterWithDeps)
} }
+38 -117
View File
@@ -2,13 +2,13 @@ package cmd
import ( import (
"fmt" "fmt"
"os"
"os/signal"
"strings" "strings"
"sync"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/query"
"github.com/aptly-dev/aptly/query" "github.com/smira/aptly/utils"
"github.com/aptly-dev/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -69,7 +69,7 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
} }
var oldLen, newLen int var oldLen, newLen int
oldLen, newLen, err = repo.ApplyFilter(context.DependencyOptions(), filterQuery, context.Progress()) oldLen, newLen, err = repo.ApplyFilter(context.DependencyOptions(), filterQuery)
if err != nil { if err != nil {
return fmt.Errorf("unable to update: %s", err) return fmt.Errorf("unable to update: %s", err)
} }
@@ -81,12 +81,8 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
queue []deb.PackageDownloadTask queue []deb.PackageDownloadTask
) )
skipExistingPackages := context.Flags().Lookup("skip-existing-packages").Value.Get().(bool)
context.Progress().Printf("Building download queue...\n") context.Progress().Printf("Building download queue...\n")
queue, downloadSize, err = repo.BuildDownloadQueue(context.PackagePool(), context.CollectionFactory().PackageCollection(), queue, downloadSize, err = repo.BuildDownloadQueue(context.PackagePool())
context.CollectionFactory().ChecksumCollection(), skipExistingPackages)
if err != nil { if err != nil {
return fmt.Errorf("unable to update: %s", err) return fmt.Errorf("unable to update: %s", err)
} }
@@ -111,7 +107,9 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to update: %s", err) return fmt.Errorf("unable to update: %s", err)
} }
context.GoContextHandleSignals() // Catch ^C
sigch := make(chan os.Signal)
signal.Notify(sigch, os.Interrupt)
count := len(queue) count := len(queue)
context.Progress().Printf("Download queue: %d items (%s)\n", count, utils.HumanBytes(downloadSize)) context.Progress().Printf("Download queue: %d items (%s)\n", count, utils.HumanBytes(downloadSize))
@@ -119,124 +117,48 @@ func aptlyMirrorUpdate(cmd *commander.Command, args []string) error {
// Download from the queue // Download from the queue
context.Progress().InitBar(downloadSize, true) context.Progress().InitBar(downloadSize, true)
downloadQueue := make(chan int) // Download all package files
ch := make(chan error, count)
var ( // In separate goroutine (to avoid blocking main), push queue to downloader
errors []string go func() {
errLock sync.Mutex for _, task := range queue {
) context.Downloader().DownloadWithChecksum(repo.PackageURL(task.RepoURI).String(), task.DestinationPath, ch, task.Checksums, ignoreMismatch, maxTries)
}
pushError := func(err error) { // We don't need queue after this point
errLock.Lock() queue = nil
}()
// Wait for all downloads to finish
var errors []string
for count > 0 {
select {
case <-sigch:
signal.Stop(sigch)
return fmt.Errorf("unable to update: interrupted")
case err = <-ch:
if err != nil {
errors = append(errors, err.Error()) errors = append(errors, err.Error())
errLock.Unlock()
} }
count--
go func() {
for idx := range queue {
select {
case downloadQueue <- idx:
case <-context.Done():
return
} }
} }
close(downloadQueue)
}()
var wg sync.WaitGroup
for i := 0; i < context.Config().DownloadConcurrency; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case idx, ok := <-downloadQueue:
if !ok {
return
}
task := &queue[idx]
var e error
// provision download location
task.TempDownPath, e = context.PackagePool().(aptly.LocalPackagePool).GenerateTempPath(task.File.Filename)
if e != nil {
pushError(e)
continue
}
// download file...
e = context.Downloader().DownloadWithChecksum(
context,
repo.PackageURL(task.File.DownloadURL()).String(),
task.TempDownPath,
&task.File.Checksums,
ignoreMismatch,
maxTries)
if e != nil {
pushError(e)
continue
}
task.Done = true
case <-context.Done():
return
}
}
}()
}
// Wait for all download goroutines to finish
wg.Wait()
context.Progress().ShutdownBar() context.Progress().ShutdownBar()
signal.Stop(sigch)
if len(errors) > 0 {
return fmt.Errorf("unable to update: download errors:\n %s", strings.Join(errors, "\n "))
}
err = context.ReOpenDatabase() err = context.ReOpenDatabase()
if err != nil { if err != nil {
return fmt.Errorf("unable to update: %s", err) return fmt.Errorf("unable to update: %s", err)
} }
// Import downloaded files repo.FinalizeDownload()
context.Progress().InitBar(int64(len(queue)), false)
for idx := range queue {
context.Progress().AddBar(1)
task := &queue[idx]
if !task.Done {
// download not finished yet
continue
}
// and import it back to the pool
task.File.PoolPath, err = context.PackagePool().Import(task.TempDownPath, task.File.Filename, &task.File.Checksums, true, context.CollectionFactory().ChecksumCollection())
if err != nil {
return fmt.Errorf("unable to import file: %s", err)
}
// update "attached" files if any
for _, additionalTask := range task.Additional {
additionalTask.File.PoolPath = task.File.PoolPath
additionalTask.File.Checksums = task.File.Checksums
}
}
context.Progress().ShutdownBar()
select {
case <-context.Done():
return fmt.Errorf("unable to update: interrupted")
default:
}
if len(errors) > 0 {
return fmt.Errorf("unable to update: download errors:\n %s", strings.Join(errors, "\n "))
}
repo.FinalizeDownload(context.CollectionFactory(), context.Progress())
err = context.CollectionFactory().RemoteRepoCollection().Update(repo) err = context.CollectionFactory().RemoteRepoCollection().Update(repo)
if err != nil { if err != nil {
return fmt.Errorf("unable to update: %s", err) return fmt.Errorf("unable to update: %s", err)
@@ -266,7 +188,6 @@ Example:
cmd.Flag.Bool("force", false, "force update mirror even if it is locked by another process") cmd.Flag.Bool("force", false, "force update mirror even if it is locked by another process")
cmd.Flag.Bool("ignore-checksums", false, "ignore checksum mismatches while downloading package files and metadata") cmd.Flag.Bool("ignore-checksums", false, "ignore checksum mismatches while downloading package files and metadata")
cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures") cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures")
cmd.Flag.Bool("skip-existing-packages", false, "do not check file existence for packages listed in the internal database of the mirror")
cmd.Flag.Int64("download-limit", 0, "limit download speed (kbytes/sec)") cmd.Flag.Int64("download-limit", 0, "limit download speed (kbytes/sec)")
cmd.Flag.Int("max-tries", 1, "max download tries till process fails with download error") cmd.Flag.Int("max-tries", 1, "max download tries till process fails with download error")
cmd.Flag.Var(&keyRingsFlag{}, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)") cmd.Flag.Var(&keyRingsFlag{}, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)")
+3 -3
View File
@@ -3,8 +3,8 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/query" "github.com/smira/aptly/query"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -35,7 +35,7 @@ func aptlyPackageSearch(cmd *commander.Command, args []string) error {
} }
format := context.Flags().Lookup("format").Value.String() format := context.Flags().Lookup("format").Value.String()
PrintPackageList(result, format, "") PrintPackageList(result, format)
return err return err
} }
+16 -21
View File
@@ -5,18 +5,17 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/query"
"github.com/aptly-dev/aptly/query"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
func printReferencesTo(p *deb.Package) (err error) { func printReferencesTo(p *deb.Package) (err error) {
err = context.CollectionFactory().RemoteRepoCollection().ForEach(func(repo *deb.RemoteRepo) error { err = context.CollectionFactory().RemoteRepoCollection().ForEach(func(repo *deb.RemoteRepo) error {
e := context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo) err := context.CollectionFactory().RemoteRepoCollection().LoadComplete(repo)
if e != nil { if err != nil {
return e return err
} }
if repo.RefList() != nil { if repo.RefList() != nil {
if repo.RefList().Has(p) { if repo.RefList().Has(p) {
@@ -30,9 +29,9 @@ func printReferencesTo(p *deb.Package) (err error) {
} }
err = context.CollectionFactory().LocalRepoCollection().ForEach(func(repo *deb.LocalRepo) error { err = context.CollectionFactory().LocalRepoCollection().ForEach(func(repo *deb.LocalRepo) error {
e := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo) err := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if e != nil { if err != nil {
return e return err
} }
if repo.RefList() != nil { if repo.RefList() != nil {
if repo.RefList().Has(p) { if repo.RefList().Has(p) {
@@ -46,17 +45,20 @@ func printReferencesTo(p *deb.Package) (err error) {
} }
err = context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error { err = context.CollectionFactory().SnapshotCollection().ForEach(func(snapshot *deb.Snapshot) error {
e := context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot) err := context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
if e != nil { if err != nil {
return e return err
} }
if snapshot.RefList().Has(p) { if snapshot.RefList().Has(p) {
fmt.Printf(" snapshot %s\n", snapshot) fmt.Printf(" snapshot %s\n", snapshot)
} }
return nil return nil
}) })
if err != nil {
return err return err
}
return nil
} }
func aptlyPackageShow(cmd *commander.Command, args []string) error { func aptlyPackageShow(cmd *commander.Command, args []string) error {
@@ -85,18 +87,11 @@ func aptlyPackageShow(cmd *commander.Command, args []string) error {
if withFiles { if withFiles {
fmt.Printf("Files in the pool:\n") fmt.Printf("Files in the pool:\n")
packagePool := context.PackagePool()
for _, f := range p.Files() { for _, f := range p.Files() {
var path string path, err := context.PackagePool().Path(f.Filename, f.Checksums.MD5)
path, err = f.GetPoolPath(packagePool)
if err != nil { if err != nil {
return err return err
} }
if pp, ok := packagePool.(aptly.LocalPackagePool); ok {
path = pp.FullPath(path)
}
fmt.Printf(" %s\n", path) fmt.Printf(" %s\n", path)
} }
fmt.Printf("\n") fmt.Printf("\n")
+3 -3
View File
@@ -1,17 +1,17 @@
package cmd package cmd
import ( import (
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
func getSigner(flags *flag.FlagSet) (pgp.Signer, error) { func getSigner(flags *flag.FlagSet) (utils.Signer, error) {
if LookupOption(context.Config().GpgDisableSign, flags, "skip-signing") { if LookupOption(context.Config().GpgDisableSign, flags, "skip-signing") {
return nil, nil return nil, nil
} }
signer := context.GetSigner() signer := &utils.GpgSigner{}
signer.SetKey(flags.Lookup("gpg-key").Value.String()) signer.SetKey(flags.Lookup("gpg-key").Value.String())
signer.SetKeyRing(flags.Lookup("keyring").Value.String(), flags.Lookup("secret-keyring").Value.String()) signer.SetKeyRing(flags.Lookup("keyring").Value.String(), flags.Lookup("secret-keyring").Value.String())
signer.SetPassphrase(flags.Lookup("passphrase").Value.String(), flags.Lookup("passphrase-file").Value.String()) signer.SetPassphrase(flags.Lookup("passphrase").Value.String(), flags.Lookup("passphrase-file").Value.String())
+2 -5
View File
@@ -3,7 +3,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
@@ -24,9 +24,7 @@ func aptlyPublishDrop(cmd *commander.Command, args []string) error {
storage, prefix := deb.ParsePrefix(param) storage, prefix := deb.ParsePrefix(param)
err = context.CollectionFactory().PublishedRepoCollection().Remove(context, storage, prefix, distribution, err = context.CollectionFactory().PublishedRepoCollection().Remove(context, storage, prefix, distribution,
context.CollectionFactory(), context.Progress(), context.CollectionFactory(), context.Progress(), context.Flags().Lookup("force-drop").Value.Get().(bool))
context.Flags().Lookup("force-drop").Value.Get().(bool),
context.Flags().Lookup("skip-cleanup").Value.Get().(bool))
if err != nil { if err != nil {
return fmt.Errorf("unable to remove: %s", err) return fmt.Errorf("unable to remove: %s", err)
} }
@@ -52,7 +50,6 @@ Example:
} }
cmd.Flag.Bool("force-drop", false, "remove published repository even if some files could not be cleaned up") cmd.Flag.Bool("force-drop", false, "remove published repository even if some files could not be cleaned up")
cmd.Flag.Bool("skip-cleanup", false, "don't remove unreferenced files in prefix/component")
return cmd return cmd
} }
+4 -4
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
@@ -20,9 +20,9 @@ func aptlyPublishList(cmd *commander.Command, args []string) error {
published := make([]string, 0, context.CollectionFactory().PublishedRepoCollection().Len()) published := make([]string, 0, context.CollectionFactory().PublishedRepoCollection().Len())
err = context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error { err = context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error {
e := context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory()) err := context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
if e != nil { if err != nil {
return e return err
} }
if raw { if raw {
-3
View File
@@ -43,11 +43,8 @@ Example:
cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG") cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG")
cmd.Flag.Bool("skip-contents", false, "don't generate Contents indexes") cmd.Flag.Bool("skip-contents", false, "don't generate Contents indexes")
cmd.Flag.String("origin", "", "origin name to publish") cmd.Flag.String("origin", "", "origin name to publish")
cmd.Flag.String("notautomatic", "", "set value for NotAutomatic field")
cmd.Flag.String("butautomaticupgrades", "", "set value for ButAutomaticUpgrades field")
cmd.Flag.String("label", "", "label to publish") cmd.Flag.String("label", "", "label to publish")
cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch") cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch")
cmd.Flag.Bool("acquire-by-hash", false, "provide index files by hash")
return cmd return cmd
} }
+7 -7
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
@@ -41,15 +41,15 @@ func aptlyPublishShow(cmd *commander.Command, args []string) error {
fmt.Printf("Sources:\n") fmt.Printf("Sources:\n")
for component, sourceID := range repo.Sources { for component, sourceID := range repo.Sources {
var name string var name string
if repo.SourceKind == deb.SourceSnapshot { if repo.SourceKind == "snapshot" {
source, e := context.CollectionFactory().SnapshotCollection().ByUUID(sourceID) source, err := context.CollectionFactory().SnapshotCollection().ByUUID(sourceID)
if e != nil { if err != nil {
continue continue
} }
name = source.Name name = source.Name
} else if repo.SourceKind == deb.SourceLocalRepo { } else if repo.SourceKind == "local" {
source, e := context.CollectionFactory().LocalRepoCollection().ByUUID(sourceID) source, err := context.CollectionFactory().LocalRepoCollection().ByUUID(sourceID)
if e != nil { if err != nil {
continue continue
} }
name = source.Name name = source.Name
+9 -27
View File
@@ -4,9 +4,9 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -35,7 +35,7 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
message string message string
) )
if cmd.Name() == "snapshot" { // nolint: goconst if cmd.Name() == "snapshot" {
var ( var (
snapshot *deb.Snapshot snapshot *deb.Snapshot
emptyWarning = false emptyWarning = false
@@ -71,7 +71,7 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
if emptyWarning { if emptyWarning {
context.Progress().Printf("Warning: publishing from empty source, architectures list should be complete, it can't be changed after publishing (use -architectures flag)\n") context.Progress().Printf("Warning: publishing from empty source, architectures list should be complete, it can't be changed after publishing (use -architectures flag)\n")
} }
} else if cmd.Name() == "repo" { // nolint: goconst } else if cmd.Name() == "repo" {
var ( var (
localRepo *deb.LocalRepo localRepo *deb.LocalRepo
emptyWarning = false emptyWarning = false
@@ -112,23 +112,12 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
} }
distribution := context.Flags().Lookup("distribution").Value.String() distribution := context.Flags().Lookup("distribution").Value.String()
origin := context.Flags().Lookup("origin").Value.String()
notAutomatic := context.Flags().Lookup("notautomatic").Value.String()
butAutomaticUpgrades := context.Flags().Lookup("butautomaticupgrades").Value.String()
published, err := deb.NewPublishedRepo(storage, prefix, distribution, context.ArchitecturesList(), components, sources, context.CollectionFactory()) published, err := deb.NewPublishedRepo(storage, prefix, distribution, context.ArchitecturesList(), components, sources, context.CollectionFactory())
if err != nil { if err != nil {
return fmt.Errorf("unable to publish: %s", err) return fmt.Errorf("unable to publish: %s", err)
} }
if origin != "" { published.Origin = context.Flags().Lookup("origin").Value.String()
published.Origin = origin
}
if notAutomatic != "" {
published.NotAutomatic = notAutomatic
}
if butAutomaticUpgrades != "" {
published.ButAutomaticUpgrades = butAutomaticUpgrades
}
published.Label = context.Flags().Lookup("label").Value.String() published.Label = context.Flags().Lookup("label").Value.String()
published.SkipContents = context.Config().SkipContentsPublishing published.SkipContents = context.Config().SkipContentsPublishing
@@ -137,10 +126,6 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
published.SkipContents = context.Flags().Lookup("skip-contents").Value.Get().(bool) published.SkipContents = context.Flags().Lookup("skip-contents").Value.Get().(bool)
} }
if context.Flags().IsSet("acquire-by-hash") {
published.AcquireByHash = context.Flags().Lookup("acquire-by-hash").Value.Get().(bool)
}
duplicate := context.CollectionFactory().PublishedRepoCollection().CheckDuplicate(published) duplicate := context.CollectionFactory().PublishedRepoCollection().CheckDuplicate(published)
if duplicate != nil { if duplicate != nil {
context.CollectionFactory().PublishedRepoCollection().LoadComplete(duplicate, context.CollectionFactory()) context.CollectionFactory().PublishedRepoCollection().LoadComplete(duplicate, context.CollectionFactory())
@@ -178,14 +163,14 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
context.Progress().Printf("\n%s been successfully published.\n", message) context.Progress().Printf("\n%s been successfully published.\n", message)
if localStorage, ok := context.GetPublishedStorage(storage).(aptly.FileSystemPublishedStorage); ok { if localStorage, ok := context.GetPublishedStorage(storage).(aptly.LocalPublishedStorage); ok {
context.Progress().Printf("Please setup your webserver to serve directory '%s' with autoindexing.\n", context.Progress().Printf("Please setup your webserver to serve directory '%s' with autoindexing.\n",
localStorage.PublicPath()) localStorage.PublicPath())
} }
context.Progress().Printf("Now you can add following line to apt sources:\n") context.Progress().Printf("Now you can add following line to apt sources:\n")
context.Progress().Printf(" deb http://your-server/%s %s %s\n", prefix, distribution, repoComponents) context.Progress().Printf(" deb http://your-server/%s %s %s\n", prefix, distribution, repoComponents)
if utils.StrSliceHasItem(published.Architectures, deb.ArchitectureSource) { if utils.StrSliceHasItem(published.Architectures, "source") {
context.Progress().Printf(" deb-src http://your-server/%s %s %s\n", prefix, distribution, repoComponents) context.Progress().Printf(" deb-src http://your-server/%s %s %s\n", prefix, distribution, repoComponents)
} }
context.Progress().Printf("Don't forget to add your GPG key to apt with apt-key.\n") context.Progress().Printf("Don't forget to add your GPG key to apt with apt-key.\n")
@@ -226,12 +211,9 @@ Example:
cmd.Flag.Bool("batch", false, "run GPG with detached tty") cmd.Flag.Bool("batch", false, "run GPG with detached tty")
cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG") cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG")
cmd.Flag.Bool("skip-contents", false, "don't generate Contents indexes") cmd.Flag.Bool("skip-contents", false, "don't generate Contents indexes")
cmd.Flag.String("origin", "", "overwrite origin name to publish") cmd.Flag.String("origin", "", "origin name to publish")
cmd.Flag.String("notautomatic", "", "overwrite value for NotAutomatic field")
cmd.Flag.String("butautomaticupgrades", "", "overwrite value for ButAutomaticUpgrades field")
cmd.Flag.String("label", "", "label to publish") cmd.Flag.String("label", "", "label to publish")
cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch") cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch")
cmd.Flag.Bool("acquire-by-hash", false, "provide index files by hash")
return cmd return cmd
} }
+3 -7
View File
@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -44,7 +44,7 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to update: %s", err) return fmt.Errorf("unable to update: %s", err)
} }
if published.SourceKind != deb.SourceSnapshot { if published.SourceKind != "snapshot" {
return fmt.Errorf("unable to update: not a snapshot publish") return fmt.Errorf("unable to update: not a snapshot publish")
} }
@@ -105,14 +105,11 @@ func aptlyPublishSwitch(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to save to DB: %s", err) return fmt.Errorf("unable to save to DB: %s", err)
} }
skipCleanup := context.Flags().Lookup("skip-cleanup").Value.Get().(bool)
if !skipCleanup {
err = context.CollectionFactory().PublishedRepoCollection().CleanupPrefixComponentFiles(published.Prefix, components, err = context.CollectionFactory().PublishedRepoCollection().CleanupPrefixComponentFiles(published.Prefix, components,
context.GetPublishedStorage(storage), context.CollectionFactory(), context.Progress()) context.GetPublishedStorage(storage), context.CollectionFactory(), context.Progress())
if err != nil { if err != nil {
return fmt.Errorf("unable to update: %s", err) return fmt.Errorf("unable to update: %s", err)
} }
}
context.Progress().Printf("\nPublish for snapshot %s has been successfully switched to new snapshot.\n", published.String()) context.Progress().Printf("\nPublish for snapshot %s has been successfully switched to new snapshot.\n", published.String())
@@ -154,7 +151,6 @@ This command would switch published repository (with one component) named ppa/wh
cmd.Flag.Bool("skip-contents", false, "don't generate Contents indexes") cmd.Flag.Bool("skip-contents", false, "don't generate Contents indexes")
cmd.Flag.String("component", "", "component names to update (for multi-component publishing, separate components with commas)") cmd.Flag.String("component", "", "component names to update (for multi-component publishing, separate components with commas)")
cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch") cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch")
cmd.Flag.Bool("skip-cleanup", false, "don't remove unreferenced files in prefix/component")
return cmd return cmd
} }
+2 -6
View File
@@ -3,7 +3,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -30,7 +30,7 @@ func aptlyPublishUpdate(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to update: %s", err) return fmt.Errorf("unable to update: %s", err)
} }
if published.SourceKind != deb.SourceLocalRepo { if published.SourceKind != "local" {
return fmt.Errorf("unable to update: not a local repository publish") return fmt.Errorf("unable to update: not a local repository publish")
} }
@@ -69,14 +69,11 @@ func aptlyPublishUpdate(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to save to DB: %s", err) return fmt.Errorf("unable to save to DB: %s", err)
} }
skipCleanup := context.Flags().Lookup("skip-cleanup").Value.Get().(bool)
if !skipCleanup {
err = context.CollectionFactory().PublishedRepoCollection().CleanupPrefixComponentFiles(published.Prefix, components, err = context.CollectionFactory().PublishedRepoCollection().CleanupPrefixComponentFiles(published.Prefix, components,
context.GetPublishedStorage(storage), context.CollectionFactory(), context.Progress()) context.GetPublishedStorage(storage), context.CollectionFactory(), context.Progress())
if err != nil { if err != nil {
return fmt.Errorf("unable to update: %s", err) return fmt.Errorf("unable to update: %s", err)
} }
}
context.Progress().Printf("\nPublish for local repo %s has been successfully updated.\n", published.String()) context.Progress().Printf("\nPublish for local repo %s has been successfully updated.\n", published.String())
@@ -112,7 +109,6 @@ Example:
cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG") cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG")
cmd.Flag.Bool("skip-contents", false, "don't generate Contents indexes") cmd.Flag.Bool("skip-contents", false, "don't generate Contents indexes")
cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch") cmd.Flag.Bool("force-overwrite", false, "overwrite files in package pool in case of mismatch")
cmd.Flag.Bool("skip-cleanup", false, "don't remove unreferenced files in prefix/component")
return cmd return cmd
} }
+8 -11
View File
@@ -4,9 +4,9 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -20,7 +20,7 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
name := args[0] name := args[0]
verifier := context.GetVerifier() verifier := &utils.GpgVerifier{}
repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name) repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
if err != nil { if err != nil {
@@ -41,22 +41,19 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
forceReplace := context.Flags().Lookup("force-replace").Value.Get().(bool) forceReplace := context.Flags().Lookup("force-replace").Value.Get().(bool)
var packageFiles, otherFiles, failedFiles []string var packageFiles, failedFiles []string
packageFiles, otherFiles, failedFiles = deb.CollectPackageFiles(args[1:], &aptly.ConsoleResultReporter{Progress: context.Progress()}) packageFiles, failedFiles = deb.CollectPackageFiles(args[1:], &aptly.ConsoleResultReporter{Progress: context.Progress()})
var processedFiles, failedFiles2 []string var processedFiles, failedFiles2 []string
processedFiles, failedFiles2, err = deb.ImportPackageFiles(list, packageFiles, forceReplace, verifier, context.PackagePool(), processedFiles, failedFiles2, err = deb.ImportPackageFiles(list, packageFiles, forceReplace, verifier, context.PackagePool(),
context.CollectionFactory().PackageCollection(), &aptly.ConsoleResultReporter{Progress: context.Progress()}, nil, context.CollectionFactory().PackageCollection(), &aptly.ConsoleResultReporter{Progress: context.Progress()}, nil)
context.CollectionFactory().ChecksumCollection())
failedFiles = append(failedFiles, failedFiles2...) failedFiles = append(failedFiles, failedFiles2...)
if err != nil { if err != nil {
return fmt.Errorf("unable to import package files: %s", err) return fmt.Errorf("unable to import package files: %s", err)
} }
processedFiles = append(processedFiles, otherFiles...)
repo.UpdateRefList(deb.NewPackageRefListFromPackageList(list)) repo.UpdateRefList(deb.NewPackageRefListFromPackageList(list))
err = context.CollectionFactory().LocalRepoCollection().Update(repo) err = context.CollectionFactory().LocalRepoCollection().Update(repo)
@@ -68,7 +65,7 @@ func aptlyRepoAdd(cmd *commander.Command, args []string) error {
processedFiles = utils.StrSliceDeduplicate(processedFiles) processedFiles = utils.StrSliceDeduplicate(processedFiles)
for _, file := range processedFiles { for _, file := range processedFiles {
err = os.Remove(file) err := os.Remove(file)
if err != nil { if err != nil {
return fmt.Errorf("unable to remove file: %s", err) return fmt.Errorf("unable to remove file: %s", err)
} }
+2 -2
View File
@@ -3,14 +3,14 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
func aptlyRepoCreate(cmd *commander.Command, args []string) error { func aptlyRepoCreate(cmd *commander.Command, args []string) error {
var err error var err error
if !(len(args) == 1 || (len(args) == 4 && args[1] == "from" && args[2] == "snapshot")) { // nolint: goconst if !(len(args) == 1 || (len(args) == 4 && args[1] == "from" && args[2] == "snapshot")) {
cmd.Usage() cmd.Usage()
return commander.ErrCommandError return commander.ErrCommandError
} }
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"github.com/AlekSi/pointer" "github.com/AlekSi/pointer"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
+10 -16
View File
@@ -7,10 +7,10 @@ import (
"path/filepath" "path/filepath"
"text/template" "text/template"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/query" "github.com/smira/aptly/query"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -28,7 +28,7 @@ func aptlyRepoInclude(cmd *commander.Command, args []string) error {
} }
if verifier == nil { if verifier == nil {
verifier = context.GetVerifier() verifier = &utils.GpgVerifier{}
} }
forceReplace := context.Flags().Lookup("force-replace").Value.Get().(bool) forceReplace := context.Flags().Lookup("force-replace").Value.Get().(bool)
@@ -97,8 +97,7 @@ func aptlyRepoInclude(cmd *commander.Command, args []string) error {
context.Progress().Printf("Loading repository %s for changes file %s...\n", repoName.String(), changes.ChangesName) context.Progress().Printf("Loading repository %s for changes file %s...\n", repoName.String(), changes.ChangesName)
var repo *deb.LocalRepo repo, err := context.CollectionFactory().LocalRepoCollection().ByName(repoName.String())
repo, err = context.CollectionFactory().LocalRepoCollection().ByName(repoName.String())
if err != nil { if err != nil {
failedFiles = append(failedFiles, path) failedFiles = append(failedFiles, path)
reporter.Warning("unable to process file %s: %s", changes.ChangesName, err) reporter.Warning("unable to process file %s: %s", changes.ChangesName, err)
@@ -132,13 +131,12 @@ func aptlyRepoInclude(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to load repo: %s", err) return fmt.Errorf("unable to load repo: %s", err)
} }
var list *deb.PackageList list, err := deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
list, err = deb.NewPackageListFromRefList(repo.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
if err != nil { if err != nil {
return fmt.Errorf("unable to load packages: %s", err) return fmt.Errorf("unable to load packages: %s", err)
} }
packageFiles, otherFiles, _ := deb.CollectPackageFiles([]string{changes.TempDir}, reporter) packageFiles, _ := deb.CollectPackageFiles([]string{changes.TempDir}, reporter)
var restriction deb.PackageQuery var restriction deb.PackageQuery
@@ -153,7 +151,7 @@ func aptlyRepoInclude(cmd *commander.Command, args []string) error {
var processedFiles2, failedFiles2 []string var processedFiles2, failedFiles2 []string
processedFiles2, failedFiles2, err = deb.ImportPackageFiles(list, packageFiles, forceReplace, verifier, context.PackagePool(), processedFiles2, failedFiles2, err = deb.ImportPackageFiles(list, packageFiles, forceReplace, verifier, context.PackagePool(),
context.CollectionFactory().PackageCollection(), reporter, restriction, context.CollectionFactory().ChecksumCollection()) context.CollectionFactory().PackageCollection(), reporter, restriction)
if err != nil { if err != nil {
return fmt.Errorf("unable to import package files: %s", err) return fmt.Errorf("unable to import package files: %s", err)
@@ -179,10 +177,6 @@ func aptlyRepoInclude(cmd *commander.Command, args []string) error {
processedFiles = append(processedFiles, filepath.Join(changes.BasePath, filepath.Base(file))) processedFiles = append(processedFiles, filepath.Join(changes.BasePath, filepath.Base(file)))
} }
for _, file := range otherFiles {
processedFiles = append(processedFiles, filepath.Join(changes.BasePath, filepath.Base(file)))
}
processedFiles = append(processedFiles, path) processedFiles = append(processedFiles, path)
} }
@@ -190,7 +184,7 @@ func aptlyRepoInclude(cmd *commander.Command, args []string) error {
processedFiles = utils.StrSliceDeduplicate(processedFiles) processedFiles = utils.StrSliceDeduplicate(processedFiles)
for _, file := range processedFiles { for _, file := range processedFiles {
err = os.Remove(file) err := os.Remove(file)
if err != nil { if err != nil {
return fmt.Errorf("unable to remove file: %s", err) return fmt.Errorf("unable to remove file: %s", err)
} }
+4 -4
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
@@ -23,9 +23,9 @@ func aptlyRepoList(cmd *commander.Command, args []string) error {
if raw { if raw {
repos[i] = repo.Name repos[i] = repo.Name
} else { } else {
e := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo) err := context.CollectionFactory().LocalRepoCollection().LoadComplete(repo)
if e != nil { if err != nil {
return e return err
} }
repos[i] = fmt.Sprintf(" * %s (packages: %d)", repo.String(), repo.NumPackages()) repos[i] = fmt.Sprintf(" * %s (packages: %d)", repo.String(), repo.NumPackages())
+10 -10
View File
@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/query" "github.com/smira/aptly/query"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -34,7 +34,7 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
srcRepo *deb.LocalRepo srcRepo *deb.LocalRepo
) )
if command == "copy" || command == "move" { // nolint: goconst if command == "copy" || command == "move" {
srcRepo, err = context.CollectionFactory().LocalRepoCollection().ByName(args[0]) srcRepo, err = context.CollectionFactory().LocalRepoCollection().ByName(args[0])
if err != nil { if err != nil {
return fmt.Errorf("unable to %s: %s", command, err) return fmt.Errorf("unable to %s: %s", command, err)
@@ -50,7 +50,7 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
} }
srcRefList = srcRepo.RefList() srcRefList = srcRepo.RefList()
} else if command == "import" { // nolint: goconst } else if command == "import" {
var srcRemoteRepo *deb.RemoteRepo var srcRemoteRepo *deb.RemoteRepo
srcRemoteRepo, err = context.CollectionFactory().RemoteRepoCollection().ByName(args[0]) srcRemoteRepo, err = context.CollectionFactory().RemoteRepoCollection().ByName(args[0])
@@ -115,18 +115,18 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
} }
} }
toProcess, err := srcList.FilterWithProgress(queries, withDeps, dstList, context.DependencyOptions(), architecturesList, context.Progress()) toProcess, err := srcList.Filter(queries, withDeps, dstList, context.DependencyOptions(), architecturesList)
if err != nil { if err != nil {
return fmt.Errorf("unable to %s: %s", command, err) return fmt.Errorf("unable to %s: %s", command, err)
} }
var verb string var verb string
if command == "move" { // nolint: goconst if command == "move" {
verb = "moved" verb = "moved"
} else if command == "copy" { // nolint: goconst } else if command == "copy" {
verb = "copied" verb = "copied"
} else if command == "import" { // nolint: goconst } else if command == "import" {
verb = "imported" verb = "imported"
} }
@@ -136,7 +136,7 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
return err return err
} }
if command == "move" { // nolint: goconst if command == "move" {
srcList.Remove(p) srcList.Remove(p)
} }
context.Progress().ColoredPrintf("@g[o]@| %s %s", p, verb) context.Progress().ColoredPrintf("@g[o]@| %s %s", p, verb)
@@ -156,7 +156,7 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
return fmt.Errorf("unable to save: %s", err) return fmt.Errorf("unable to save: %s", err)
} }
if command == "move" { // nolint: goconst if command == "move" {
srcRepo.UpdateRefList(deb.NewPackageRefListFromPackageList(srcList)) srcRepo.UpdateRefList(deb.NewPackageRefListFromPackageList(srcList))
err = context.CollectionFactory().LocalRepoCollection().Update(srcRepo) err = context.CollectionFactory().LocalRepoCollection().Update(srcRepo)
+2 -2
View File
@@ -3,8 +3,8 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/query" "github.com/smira/aptly/query"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
+1 -1
View File
@@ -3,7 +3,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
ctx "github.com/aptly-dev/aptly/context" ctx "github.com/smira/aptly/context"
"github.com/smira/commander" "github.com/smira/commander"
) )
+8 -8
View File
@@ -8,9 +8,9 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -60,9 +60,9 @@ func aptlyServe(cmd *commander.Command, args []string) error {
published := make(map[string]*deb.PublishedRepo, context.CollectionFactory().PublishedRepoCollection().Len()) published := make(map[string]*deb.PublishedRepo, context.CollectionFactory().PublishedRepoCollection().Len())
err = context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error { err = context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error {
e := context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory()) err := context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
if e != nil { if err != nil {
return e return err
} }
sources = append(sources, repo.String()) sources = append(sources, repo.String())
@@ -90,13 +90,13 @@ func aptlyServe(cmd *commander.Command, args []string) error {
fmt.Printf("# %s\ndeb http://%s:%s/%s %s %s\n", fmt.Printf("# %s\ndeb http://%s:%s/%s %s %s\n",
repo, listenHost, listenPort, prefix, repo.Distribution, strings.Join(repo.Components(), " ")) repo, listenHost, listenPort, prefix, repo.Distribution, strings.Join(repo.Components(), " "))
if utils.StrSliceHasItem(repo.Architectures, deb.ArchitectureSource) { if utils.StrSliceHasItem(repo.Architectures, "source") {
fmt.Printf("deb-src http://%s:%s/%s %s %s\n", fmt.Printf("deb-src http://%s:%s/%s %s %s\n",
listenHost, listenPort, prefix, repo.Distribution, strings.Join(repo.Components(), " ")) listenHost, listenPort, prefix, repo.Distribution, strings.Join(repo.Components(), " "))
} }
} }
publicPath := context.GetPublishedStorage("").(aptly.FileSystemPublishedStorage).PublicPath() publicPath := context.GetPublishedStorage("").(aptly.LocalPublishedStorage).PublicPath()
ShutdownContext() ShutdownContext()
fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen) fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen)
+3 -3
View File
@@ -3,7 +3,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
@@ -13,7 +13,7 @@ func aptlySnapshotCreate(cmd *commander.Command, args []string) error {
snapshot *deb.Snapshot snapshot *deb.Snapshot
) )
if len(args) == 4 && args[1] == "from" && args[2] == "mirror" { // nolint: goconst if len(args) == 4 && args[1] == "from" && args[2] == "mirror" {
// aptly snapshot create snap from mirror mirror // aptly snapshot create snap from mirror mirror
var repo *deb.RemoteRepo var repo *deb.RemoteRepo
@@ -38,7 +38,7 @@ func aptlySnapshotCreate(cmd *commander.Command, args []string) error {
if err != nil { if err != nil {
return fmt.Errorf("unable to create snapshot: %s", err) return fmt.Errorf("unable to create snapshot: %s", err)
} }
} else if len(args) == 4 && args[1] == "from" && args[2] == "repo" { // nolint: goconst } else if len(args) == 4 && args[1] == "from" && args[2] == "repo" {
// aptly snapshot create snap from repo repo // aptly snapshot create snap from repo repo
var repo *deb.LocalRepo var repo *deb.LocalRepo
+3 -3
View File
@@ -5,8 +5,8 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/query" "github.com/smira/aptly/query"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -66,7 +66,7 @@ func aptlySnapshotFilter(cmd *commander.Command, args []string) error {
} }
// Filter with dependencies as requested // Filter with dependencies as requested
result, err := packageList.FilterWithProgress(queries, withDeps, nil, context.DependencyOptions(), architecturesList, context.Progress()) result, err := packageList.Filter(queries, withDeps, nil, context.DependencyOptions(), architecturesList)
if err != nil { if err != nil {
return fmt.Errorf("unable to filter: %s", err) return fmt.Errorf("unable to filter: %s", err)
} }
+1 -1
View File
@@ -3,7 +3,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
+3 -3
View File
@@ -5,8 +5,8 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/query" "github.com/smira/aptly/query"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -96,7 +96,7 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
} }
// Filter with dependencies as requested // Filter with dependencies as requested
result, err := sourcePackageList.FilterWithProgress(queries, !noDeps, packageList, context.DependencyOptions(), architecturesList, context.Progress()) result, err := sourcePackageList.Filter(queries, !noDeps, packageList, context.DependencyOptions(), architecturesList)
if err != nil { if err != nil {
return fmt.Errorf("unable to pull: %s", err) return fmt.Errorf("unable to pull: %s", err)
} }
+1 -1
View File
@@ -3,7 +3,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
+10 -13
View File
@@ -4,8 +4,8 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/query" "github.com/smira/aptly/query"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -26,9 +26,8 @@ func aptlySnapshotMirrorRepoSearch(cmd *commander.Command, args []string) error
var reflist *deb.PackageRefList var reflist *deb.PackageRefList
if command == "snapshot" { // nolint: goconst if command == "snapshot" {
var snapshot *deb.Snapshot snapshot, err := context.CollectionFactory().SnapshotCollection().ByName(name)
snapshot, err = context.CollectionFactory().SnapshotCollection().ByName(name)
if err != nil { if err != nil {
return fmt.Errorf("unable to search: %s", err) return fmt.Errorf("unable to search: %s", err)
} }
@@ -40,8 +39,7 @@ func aptlySnapshotMirrorRepoSearch(cmd *commander.Command, args []string) error
reflist = snapshot.RefList() reflist = snapshot.RefList()
} else if command == "mirror" { } else if command == "mirror" {
var repo *deb.RemoteRepo repo, err := context.CollectionFactory().RemoteRepoCollection().ByName(name)
repo, err = context.CollectionFactory().RemoteRepoCollection().ByName(name)
if err != nil { if err != nil {
return fmt.Errorf("unable to search: %s", err) return fmt.Errorf("unable to search: %s", err)
} }
@@ -52,9 +50,8 @@ func aptlySnapshotMirrorRepoSearch(cmd *commander.Command, args []string) error
} }
reflist = repo.RefList() reflist = repo.RefList()
} else if command == "repo" { // nolint: goconst } else if command == "repo" {
var repo *deb.LocalRepo repo, err := context.CollectionFactory().LocalRepoCollection().ByName(name)
repo, err = context.CollectionFactory().LocalRepoCollection().ByName(name)
if err != nil { if err != nil {
return fmt.Errorf("unable to search: %s", err) return fmt.Errorf("unable to search: %s", err)
} }
@@ -102,8 +99,8 @@ func aptlySnapshotMirrorRepoSearch(cmd *commander.Command, args []string) error
} }
} }
result, err := list.FilterWithProgress([]deb.PackageQuery{q}, withDeps, result, err := list.Filter([]deb.PackageQuery{q}, withDeps,
nil, context.DependencyOptions(), architecturesList, context.Progress()) nil, context.DependencyOptions(), architecturesList)
if err != nil { if err != nil {
return fmt.Errorf("unable to search: %s", err) return fmt.Errorf("unable to search: %s", err)
} }
@@ -113,7 +110,7 @@ func aptlySnapshotMirrorRepoSearch(cmd *commander.Command, args []string) error
} }
format := context.Flags().Lookup("format").Value.String() format := context.Flags().Lookup("format").Value.String()
PrintPackageList(result, format, "") PrintPackageList(result, format)
return err return err
} }
+6 -10
View File
@@ -3,7 +3,6 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -35,23 +34,20 @@ func aptlySnapshotShow(cmd *commander.Command, args []string) error {
fmt.Printf("Sources:\n") fmt.Printf("Sources:\n")
for _, sourceID := range snapshot.SourceIDs { for _, sourceID := range snapshot.SourceIDs {
var name string var name string
if snapshot.SourceKind == deb.SourceSnapshot { if snapshot.SourceKind == "snapshot" {
var source *deb.Snapshot source, err := context.CollectionFactory().SnapshotCollection().ByUUID(sourceID)
source, err = context.CollectionFactory().SnapshotCollection().ByUUID(sourceID)
if err != nil { if err != nil {
continue continue
} }
name = source.Name name = source.Name
} else if snapshot.SourceKind == deb.SourceLocalRepo { } else if snapshot.SourceKind == "local" {
var source *deb.LocalRepo source, err := context.CollectionFactory().LocalRepoCollection().ByUUID(sourceID)
source, err = context.CollectionFactory().LocalRepoCollection().ByUUID(sourceID)
if err != nil { if err != nil {
continue continue
} }
name = source.Name name = source.Name
} else if snapshot.SourceKind == deb.SourceRemoteRepo { } else if snapshot.SourceKind == "repo" {
var source *deb.RemoteRepo source, err := context.CollectionFactory().RemoteRepoCollection().ByUUID(sourceID)
source, err = context.CollectionFactory().RemoteRepoCollection().ByUUID(sourceID)
if err != nil { if err != nil {
continue continue
} }
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/smira/commander" "github.com/smira/commander"
) )
+1 -1
View File
@@ -82,7 +82,7 @@ func aptlyTaskRun(cmd *commander.Command, args []string) error {
for i, command := range cmdList { for i, command := range cmdList {
if !commandErrored { if !commandErrored {
err = context.ReOpenDatabase() err := context.ReOpenDatabase()
if err != nil { if err != nil {
return fmt.Errorf("failed to reopen DB: %s", err) return fmt.Errorf("failed to reopen DB: %s", err)
} }
+1 -1
View File
@@ -3,7 +3,7 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/smira/commander" "github.com/smira/commander"
) )
-65
View File
@@ -1,65 +0,0 @@
# aptly-zsh
zsh completion for aptly
The zsh completion function and this README were imported from
[steinymity's repository](https://github.com/steinymity/aptly-zsh).
[Aptly](https://www.aptly.info/) is a great tool to setup Debian APT repositories
and mirrors. However, it's sometimes hard to remember all the command line
syntax and names of all options. Therefore I wrote this zsh completion modules
for aptly.
## License
This project is licensed under the terms of the MIT license. See file `LICENSE`
for details.
## Installation
Clone/copy the file `_aptly` to a place in your `$fpath` (show with
`echo $fpath`), or create a new directory and extend the fpath:
mkdir -p ~/.zsh/functions
fpath=(~/.zsh/functions $fpath)
editor ~/.zsh/functions/_aptly
To profit most from the provided help messages and completions, make sure that
your zsh is setup properly. I have tested with the grml-zsh configuration that
is [available on Github](https://github.com/grml/grml-etc-core/) and on the
[grml homepage](http://grml.org/zsh/).
## Compatibility
The command line completion was developed based on the manpage of aptly 1.2.0
(currently in Debian Testing). However, most completions will work on older
versions (e.g., 0.9.7 in Debian Stable), too.
The completion function completes most arguments and options that can be passed
to aptly, including mirror/repository/snapshot/publish names. However, not all
arguments are handled yet. See the next section for known limitations.
## Known Bugs and Limitation
* Boolean options are always completed with an explicit value `true` or
`false`, although omitting the value is implicitly interpreted as `true`.
* The source and destination names of copy and move operations must not be the
same. This is currently not enforced.
* The package query and display format strings are currently not completed.
* Endpoints are not completed.
* In `publish snapshot` there is no connection between the number of
components passed to `-component` and the number of given snapshots to
publish. Furthermore, the help text for `endpoint:prefix` disappears
after its first possible location.
* In `publish switch` the distribution can be set independently of the
`endpoint:prefix` (i.e., all published distributions can be combined with
all published `endpoint:prefix`).
* Neither `publish switch` nor `publish update` check if publish was created
from a snapshot or directly from a local repo.
* Task commands are not completed. There are no commas added.
* `help` won't complete after a sub command (i.e., `aptly mirror list help`).
* Probably more, feel free to open issues, and submit patches/merge requests.
--------------------------------------------------------------------------------
Maximilian Stein <m@steiny.biz>
2018-02-03
-617
View File
@@ -1,617 +0,0 @@
#compdef aptly
################################################################################
# Copyright (C) 2018 Maximilian Stein <m@steiny.biz>
# Acknowledgement: Many texts where copied from aptly(1)
#
# This project is licensed under the terms of the MIT license.
# See file LICENSE for details.
################################################################################
# zsh completion script for Aptly (http://aptly.info/)
################################################################################
# see https://man.cx/aptly
local curcontext="$curcontext" state line cmd subcmd ret=1
local arch_list=(amd64 arm64 armel armhf i386 mips mipsel mips64el ppc64el s390x)
local bool="bool:{_wanted -V values expl 'bool' compadd true false}"
local dists=({wheezy,jessie,stretch}{,-updates,-backports,-backports-sloopy} buster sid experimental)
local components=(main contrib non-free)
local aptly_query="aptly package query: "
local aptly_format="aptly package display format: "
local aptly_uploaders="-uploaders-file=[uploaders.json to be used when including .changes into this repository]:uploaders file:_files -g '*.json'"
local keyring="*-keyring=[gpg keyring to use when verifying Release file (could be specified multiple times)]:keyring file:_files -g '*.gpg'"
# complete command
(( $+functions[_aptly-cmd] )) ||
_aptly-cmd() {
_values "aptly command category" \
"mirror[manage, update mirrors of remote repositories]" \
"repo[manage local package repositories, add, remove, move, copy packages]" \
"snapshot[create, merge, manage snapshots]" \
"package[perform operation on the whole collection of packages]" \
"publish[publish snapshot or local repository]" \
"db[cleanup database and package pool, recover database after failure]" \
"task[multi-command tasks]" \
"serve[quickly serve published repositories via HTTP]" \
"config[configuration management]" \
"graph[generate dependency graph]" \
"api[REST API service]"
ret=0
}
# complete subcommand
(( $+functions[_aptly-subcmd] )) ||
_aptly-subcmd() {
local cmd=$1
case $cmd in
mirror)
_values "mirror commands" \
"create[create new mirror of remote repository]" \
"list[show full list of mirrors]" \
"show[show details about a mirror]" \
"drop[delete a mirror]" \
"update[update a mirror]" \
"rename[change name of a mirror]" \
"edit[change settings of a mirror]" \
"search[search mirror for packages matching query]"
ret=0 ;;
repo)
_values "repo commands" \
"add[add packages to local repository]" \
"copy[copy packages between local repositories]" \
"create[create local repository]" \
"drop[delete local repository]" \
"edit[edit properties of local repository]" \
"import[import packages from mirror to local repository]" \
"list[list local repositories]" \
"move[move packages between local repositories]" \
"remove[remove packages from local repository]" \
"show[show details about local repository]" \
"rename[renames local repository]" \
"search[search repo for packages matching query]" \
"include[add packages to local repositories based on .changes files]"
ret=0 ;;
snapshot)
_values "snapshot commands" \
"create[create snapshot of mirror or local repository]" \
"list[list snapshots]" \
"show[show details about snapshot]" \
"verify[verify dependencies in snapshot]" \
"pull[pull packages from another snapshot]" \
"diff[show difference between two snapshots]" \
"merge[merge snapshots]" \
"drop[delete snapshot]" \
"rename[rename snapshot]" \
"search[search snapshot for packages matching query]" \
"filter[filter packages in snapshot producing another snapshot]"
ret=0 ;;
publish)
_values "publish commands" \
"drop[remove published repository]" \
"list[list published repositories]" \
"repo[publish local repository]" \
"snapshot[publish snapshot]" \
"switch[update published repository by switching to new snapshot]" \
"update[update published local repository]" \
"show[shows details of published repository]"
ret=0 ;;
package)
_values "package commands" \
"search[search for packages matching query]" \
"show[show details about packages matching query]"
ret=0 ;;
db)
_values "db commands" \
"cleanup[cleanup db and package pool]" \
"recover[recover db after crash]"
ret=0 ;;
serve)
# no subcommand here
_arguments '1:: :' \
'-listen=[host:port for HTTP listening]:host\:port: '
ret=0 ;;
api)
_values "api commands" \
"serve[start api http service]"
ret=0 ;;
graph)
# no subcommand here
_arguments '*:' \
'-format=[render graph to specified format]:image format:(png svg pdf)' \
'-layout=[create a more vertical or more horizontal graph layout]:layout:(horizontal vertical)' \
'-output=[specify output filename, default is to open result in viewer]:output file:_files'
ret=0 ;;
config)
_values "config commands" \
"show[show current aptly config]"
ret=0 ;;
task)
_values "task commands" \
"run[run aptly tasks]"
ret=0 ;;
esac
}
# complete parameters
(( $+functions[_aptly-param] )) ||
_aptly-param() {
local cmd=$1 subcmd=$2
local config=$opt_args[-config]
[[ -n $config ]] && config="-config=$config"
# get list of mirrors, or ' ' if none
get_mirrors() {
# retrieve list of mirrors
local mirrors=($(aptly $config mirror list -raw=true 2>/dev/null))
# a single space causes just the help text to be shown
[[ -z $mirrors ]] && mirrors=" " || mirrors="($mirrors)"
echo $mirrors
}
# get lists of repos or ' ' if none
get_repos() {
# retrieve repo list
local repos=($(aptly $config repo list -raw=true 2>/dev/null))
[[ -z $repos ]] && repos=" " || repos="($repos)"
echo $repos
}
# get list of snapshots or ' ' if none
get_snapshots() {
local snapshots=($(aptly $config snapshot list -raw=true 2>/dev/null))
[[ -z $snapshots ]] && snapshots=" " || snapshots="($snapshots)"
echo $snapshots
}
# get list of gpg keys or ' ' if none
get_gpg_key_ids() {
local gpg_keys=($(gpg --quiet --batch --keyid-format long --list-secret-keys --with-colons 2>/dev/null | grep '^sec' | cut -d ':' -f 5))
[[ -z $gpg_keys ]] && gpg_keys=" " || gpg_keys="($gpg_keys)"
echo $gpg_keys
}
ret=0
case $cmd in
mirror)
local mirrors=$(get_mirrors)
case $subcmd in
create)
_arguments \
"-filter=[filter packages in mirror]:$aptly_query" \
"-filter-with-deps=[when filtering, include dependencies of matching packages as well]:$bool" \
"-force-architecture=[(only with architecture list) skip check that requested architectures are listed in Release file]:$bool" \
"-force-components=[(only with component list) skip check that requested components are listed in Release file]:$bool" \
"-ignore-signatures=[disable verification of Release file signatures]:$bool" \
$keyring \
"-with-sources=[download source packages in addition to binary packages]:$bool" \
"-with-udebs=[download .udeb packages (Debian installer support)]:$bool" \
"(-)2:new mirror name: " ":archive url:_urls" ":distribution:($dists)" "*:components:_values -s ' ' components $components"
;;
list)
_arguments '1:: :' \
"-raw=[display list in machine-readable format]:$bool"
;;
show)
_arguments \
"-with-packages=[show detailed list of packages and versions stored in the mirror]:$bool" \
"(-)2:mirror name:$mirrors"
;;
drop)
_arguments \
"-force=[force mirror deletion even if used by snapshots]:$bool" \
"(-)2:mirror name:$mirrors"
;;
update)
_arguments \
"-download-limit=[limit download speed (kB/s)]:kB/s: " \
"-force=[force update mirror even if it is locked by another process]:$bool" \
"-ignore-checksums=[ignore checksum mismatches while downloading package files and metadata]:$bool" \
"-ignore-signatures=[disable verification of Release file signatures]:$bool" \
$keyring \
"-max-tries=[max download tries till process fails with download error]:number: " \
"-skip-existing-packages=[do not check file existence for packages listed in the internal database of the mirror]:$bool" \
"(-)2:mirror name:$mirrors"
;;
rename)
_arguments \
"2:old mirror name:$mirrors" ":new mirror name: "
;;
edit)
_arguments \
"-filter=[filter packages in mirror]:$aptly_query" \
"-filter-with-deps=[when filtering, include dependencies of matching packages as well]:$bool" \
"-with-sources=[download source packages in addition to binary packages]:$bool" \
"-with-udebs=[download .udeb packages (Debian installer support)]:$bool" \
"(-)2:mirror name:$mirrors"
;;
search)
_arguments \
"-format=[custom format for result printing]:$aptly_format" \
"-with-deps=[include dependencies into search results]:$bool" \
"(-)2:mirror name:$mirrors" ":$aptly_query"
;;
esac
;;
repo)
local repos=$(get_repos)
local create_edit=("-comment=[any text that would be used to described local repository]:comment: "
"-component=[default component when publishing]:component:($components)"
"-distribution=[default distribution when publishing]:distribution:($dists)"
$aptly_uploaders
)
case $subcmd in
add)
_arguments \
"-force-replace=[when adding package that conflicts with existing package, remove existing package]:$bool" \
"-remove-files=[remove files that have been imported successfully into repository]:$bool" \
"(-)2:repo name:$repos" "*:package files:_files -g '*.{udeb,deb,dsc}'"
;;
copy)
_arguments \
"-dry-run=[dont copy, just show what would be copied]:$bool" \
"-with-deps=[follow dependencies when processing packagespec]:$$bool" \
"(-)2:src repo name:$repos" ":dest repo name:$repos" "*:$aptly_query"
;;
create)
local snapshots=$(get_snapshots)
_arguments \
${create_edit[@]} \
"(-)2:new repo name: " \
"3:::('from')" "4:::('snapshot')" "5::snapshot:$snapshots"
;;
drop)
_arguments \
"-force=[force local repo deletion even if used by snapshots]:$bool" \
"(-)2:repo name:$repos"
;;
edit)
_arguments \
${create_edit[@]} \
"(-)2:repo name:$repos"
;;
import)
local mirrors=$(get_mirrors)
_arguments \
"-dry-run=[dont import, just show what would be imported]:$bool" \
"-with-deps=[follow dependencies when processing packagespec]:$bool" \
"(-)2:src mirror name:$mirrors" ":dest repo name:$repos" "*:$aptly_query"
;;
list)
_arguments '1:: :' \
"-raw=[display list in machinereadable format]:$bool"
;;
move)
_arguments \
"-dry-run=[dont move, just show what would be moved]:$bool" \
"-with-deps=[follow dependencies when processing packagespec]:$bool" \
"(-)2:srv repo name:$repos" ":dest repo name:$repos" "*:$aptly_query"
;;
remove)
_arguments \
"-dry-run=[dont remove, just show what would be removed]:$bool" \
"(-)2:repo name:$repos" "*:$aptly_query"
;;
show)
_arguments \
"-with-packages=[show list of packages]:$bool" \
"(-)2:repo name:$repos"
;;
rename)
_arguments \
"2:old repo name:$repos" ":new repo name: "
;;
search)
_arguments \
"-format=[custom format for result printing]:$aptly_format" \
"-with-deps=[include dependencies into search results]:$bool" \
"(-)2:repo name:$repos" ":$aptly_query"
;;
include)
_arguments '1:: :' \
"-accept-unsigned=[accept unsigned .changes files]:$bool" \
"-force-replace=[when adding package that conflicts with existing package, remove existing package]:$bool" \
"-ignore-signatures=[disable verification of .changes file signature]:$bool" \
$keyring \
"-no-remove-files=[dont remove files that have been imported successfully into repository]:$bool" \
"-repo=[which repo should files go to, defaults to Distribution field of .changes file]:repo name:$repos" \
$aptly_uploaders \
"(-)*:changes files/directories:_files -g '*.changes'"
;;
esac
;;
snapshot)
local snapshots=$(get_snapshots)
case $subcmd in
create)
local mirrors=$(get_mirrors)
local repos=$(get_repos)
_arguments -C \
'(-)2:new snapshot name: ' \
'3: :->src1' \
'4:: :->src2' '5:: :->src3'
case $state in
src1)
_values 'snapshot src' 'from' 'empty' ;;
src2)
if [[ $line[3] == from ]]; then
_values 'snapshot src' 'mirror' 'repo'
fi
;;
src3)
if [[ $line[3] == from ]]; then
case $line[4] in
mirror)
_arguments "5:mirror name:$mirrors" ;;
repo)
_arguments "5:repo name:$repos" ;;
esac
fi
;;
esac
;;
list)
_arguments '1:: :' \
"-raw=[display list in machinereadable format]:$bool" \
"-sort=[display list in name or creation time order]:sort order:((name\:'alphabetical order' time\:'chronological order'))"
;;
show)
_arguments \
"-with-packages=[show list of packages]:$bool" \
"(-)2:snapshot name:$snapshots"
;;
verify)
_arguments '1:: :' \
"(-)2:snapshot name:$snapshots" "*::more snapshots:$snapshots"
;;
pull)
_arguments \
"-all-matches=[pull all the packages that satisfy the dependency version requirements]:$bool" \
"-dry-run=[dont create destination snapshot, just show what would be pulled]:$bool" \
"-no-deps=[dont process dependencies, just pull listed packages]:$bool" \
"-no-remove=[dont remove other package versions when pulling package]:$bool" \
"(-)2:to snapshot name:$snapshots" "3:src snapshot name:$snapshots" "4:new dest snapshot name: " \
"*:$aptly_query"
;;
diff)
_arguments \
"-only-matching=[display diff only for matching packages (dont display missing packages)]:$bool" \
"(-)2:snapshot name a:$snapshots" "3:snapshot name b:$snapshots"
;;
merge)
_arguments \
"-latest=[use only the latest version of each package]:$bool" \
"-no-remove=[dont remove duplicate arch/name packages]:$bool" \
"(-)2:new dest snapshot name: " "*:source snapshot name(s):$snapshots"
;;
drop)
_arguments \
"-force=[remove snapshot even if it was used as source for other snapshots]:$bool" \
"(-)2:snapshot name:$snapshots"
;;
rename)
_arguments '1:: :' \
"2:old snapshot name:$snapshots" "3:new snapshot name: "
;;
search)
_arguments \
"-format=[custom format for result printing]:$aptly_format" \
"-with-deps=[include dependencies into search results]:$bool" \
"(-)2:snapshot name:$snapshots" ":$aptly_query"
;;
filter)
_arguments \
"-with-deps=[include dependent packages as well]:$bool" \
"(-)2:src snapshot name:$snapshots" "3:new dest snapshot name: " "*:$aptly_query"
;;
esac
;;
publish)
# read lines of output into
# format of each item: <ep:prefix> <distribution>
local -a publish_prefixes
local -a publish_dists
for line in ${(@f)"$(aptly $config publish list -raw=true 2>/dev/null)"}
{
publish_prefixes+=($line[(ws: :)1])
publish_dists+=($line[(ws: :)2])
}
publish_prefixes_uniq=(${(@u)publish_prefixes})
publish_dists_uniq=(${(@u)publish_dists})
[[ -z $publish_prefixes_uniq ]] && publish_prefixes_uniq=" " || publish_prefixes_uniq="($publish_prefixes_uniq)"
[[ -z $publish_dists_uniq ]] && publish_dists_uniq=" " || publish_dists_uniq="($publish_dists_uniq)"
local gpg_keys=$(get_gpg_key_ids)
# common options for publishing
# TODO: is the keyring parameter correct?
local publish_update_options=(
"-batch=[run GPG with detached tty]:$bool"
"-force-overwrite=[overwrite files in package pool in case of mismatch]:$bool"
"-gpg-key=[GPG key ID to use when signing the release]:gpg key id:$gpg_keys"
"-keyring=[GPG keyring to use (instead of default)]:keyring file:_files -g '*.gpg'"
"-passphrase=[GPG passhprase for the key (warning: could be insecure)]:passphrase: "
"-passphrase-file=[GPG passhprasefile for the key (warning: could be insecure)]:passphrase file:_files"
"-secret-keyring=[GPG secret keyring to use (instead of default)]:secret-keyring:_files"
"-skip-contents=[dont generate Contents indexes]:$bool"
"-skip-signing=[dont sign Release files with GPG]:$bool"
)
local components_options=(
"-component=[component name to publish (for multicomponent publishing, separate components with commas)]:components:_values -s , components $components"
)
local publish_options=(
"-butautomaticupgrades=[set value for ButAutomaticUpgrades field]:$bool"
"-distribution=[distribution name to publish]:distribution:($dists)"
"-label=[label to publish]:label: "
"-notautomatic=[set value for NotAutomatic field]:notautomatic: "
"-origin=[origin name to publish]:origin: "
${components_options[@]}
)
local endpoint_prefix="[endpoint\:]prefix"
case $subcmd in
repo)
local repos=$(get_repos)
_arguments \
${publish_options[@]} \
${publish_update_options[@]} \
"(-)2:repo name:$repos" "3::$endpoint_prefix: "
;;
snapshot)
local snapshots=$(get_snapshots)
_arguments '1:: :' \
${publish_options[@]} \
${publish_update_options[@]} \
"(-)*:snapshot name:$snapshots" "3::$endpoint_prefix: "
;;
switch)
local snapshots=$(get_snapshots)
_arguments \
${publish_update_options[@]} \
${components_options[@]} \
"(-)2:distribution:$publish_dists_uniq" "3::$endpoint_prefix:$publish_prefixes_uniq" \
"*:new snapshot name:$snapshots"
;;
update)
_arguments \
${publish_update_options[@]} \
"(-)2:distribution:$publish_dists_uniq" "3::$endpoint_prefix:$publish_prefixes_uniq"
;;
show)
_arguments '1:: :' \
"(-)2:distribution:$publish_dists_uniq" "3::$endpoint_prefix:$publish_prefixes_uniq"
;;
esac
;;
package)
case $subcmd in
search)
_arguments \
"-format=[custom format for result printing]:$aptly_format" \
"(-)2:$aptly_query"
;;
show)
_arguments \
"-with-files=[display information about files from package pool]:$bool" \
"-with-references=[display information about mirrors, snapshots and local repos referencing this package]:$bool" \
"(-)2:$aptly_query"
;;
esac
;;
db)
case $subcmd in
cleanup)
_arguments '1:: :' \
"-dry-run=[dont delete anything]:$bool" \
"-verbose=[be verbose when loading objects/removing them]:$bool"
;;
recover)
# nothing to complete...
;;
esac
;;
serve)
# completed in _aptly-subcmd
;;
api)
case $subcmd in
serve)
_arguments '1:: :' \
"-listen=[host:port for HTTP listening or unix://path to listen on a Unix domain socket]:host\:port or unix\://path: " \
"-no-lock=[dont lock the database]:$bool"
;;
esac
;;
graph)
# completed in _aptly-subcmd
;;
config)
case $subcmd in
show)
# nothing to do
;;
esac
;;
task)
case $subcmd in
run)
_arguments '1:: :' \
"(2)-filename=[specifies the filename that contains the commands to run]:filename:_files" \
"(-filename)*::comma-separated command list: "
esac
;;
esac
}
# main completion
_arguments -C \
"-architectures=[list of architectures to consider (commaseparated), default to all available]:architectures:_values -s , architectures $arch_list" \
"-config=[location of configuration file]:file:_files -g '*.conf'" \
"-db-open-attempts=[number of attempts to open DB if its locked by other instance]:number:()" \
"-dep-follow-all-variants=[when processing dependencies, follow a & b if dependency is a|b]:$bool" \
"-dep-follow-recommends=[when processing dependencies, follow Recommends]:$bool" \
"-dep-follow-source=[when processing dependencies, follow from binary to Source packages]:$bool" \
"-dep-follow-suggests=[when processing dependencies, follow Suggests]:$bool" \
"-dep-verbose-resolve=[when processing dependencies, print detailed logs]:$bool" \
"-gpg-provider=[PGP implementation]:gpg provider:((gpg\:'external gpg' internal\:'Go internal implementation'))" \
'(-)1: :->cmds' \
'2: :->subcmd' \
'*:: :->args' && ret=0
cmd=$line[1]
subcmd=$line[2]
case $state in
cmds)
_aptly-cmd
_arguments '(-)1:: :((help\:integrated\ command\ help))'
;;
subcmd)
case $cmd in
help)
_aptly-cmd
;;
*)
_aptly-subcmd $cmd
_arguments '(-)2:: :((help\:integrated\ command\ help))'
;;
esac
;;
args)
# help anywhere in line?
if [[ ${line[(i)help]} -le ${#line} ]]; then
if [[ ${#line} -le 3 ]]; then
if [[ $line[1] == help ]]; then
_aptly-subcmd $subcmd
elif [[ $line[2] == help ]]; then
_aptly-subcmd $cmd
fi
fi
else
_aptly-param $cmd $subcmd
# this somehow destroys parameter completion, so disable it for now
#_arguments '(-)3:: :((help\:integrated\ command\ help))'
fi
ret=0
;;
esac
return ret
# mode: Shell-Script
# sh-indentation: 4
# indent-tabs-mode: nil
# sh-basic-offset: 4
# End:
# vim: ft=zsh sw=4 ts=4 et
-633
View File
@@ -1,633 +0,0 @@
#!/bin/bash
# (The MIT License)
#
# Copyright (c) 2014 Andrey Smirnov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the 'Software'), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in 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 IN THE
# SOFTWARE.
__aptly_mirror_list()
{
aptly mirror list -raw
}
__aptly_repo_list()
{
aptly repo list -raw
}
__aptly_snapshot_list()
{
aptly snapshot list -raw
}
__aptly_published_distributions()
{
aptly publish list -raw | cut -d ' ' -f 2 | sort | uniq
}
__aptly_published_prefixes()
{
aptly publish list -raw | cut -d ' ' -f 1 | sort | uniq
}
__aptly_prefixes_for_distribution()
{
aptly publish list -raw | awk -v dist="$1" '{ if (dist == $2) print $1 }' | sort | uniq
}
_aptly()
{
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
commands="api config db graph mirror package publish repo serve snapshot task version"
options="-architectures= -config= -db-open-attempts= -dep-follow-all-variants -dep-follow-recommends -dep-follow-source -dep-follow-suggests -dep-verbose-resolve -gpg-provider="
db_subcommands="cleanup recover"
mirror_subcommands="create drop edit show list rename search update"
publish_subcommands="drop list repo snapshot switch update"
snapshot_subcommands="create diff drop filter list merge pull rename search show verify"
repo_subcommands="add copy create drop edit import include list move remove rename search show"
package_subcommands="search show"
task_subcommands="run"
config_subcommands="show"
api_subcommands="serve"
local cmd subcmd numargs numoptions i
numargs=0
numoptions=0
for (( i=1; i < $COMP_CWORD; i++ )); do
if [[ -n "$cmd" ]]; then
if [[ ! -n "$subcmd" ]]; then
subcmd=${COMP_WORDS[i]}
numargs=$(( COMP_CWORD - i - 1 ))
else
if [[ "${COMP_WORDS[i]}" == -* ]]; then
numoptions=$(( numoptions + 1 ))
numargs=$(( numargs - 1 ))
fi
fi
else
if [[ ! "${COMP_WORDS[i]}" == -* ]]; then
cmd=${COMP_WORDS[i]}
fi
fi
done
if [[ ! -n "$cmd" ]];
then
case "$cur" in
-*)
COMPREPLY=($(compgen -W "${options}" -- ${cur}))
return 0
;;
*)
COMPREPLY=($(compgen -W "${commands}" -- ${cur}))
return 0
;;
esac
fi
if [[ ! -n "$subcmd" ]];
then
case "$prev" in
"db")
COMPREPLY=($(compgen -W "${db_subcommands}" -- ${cur}))
return 0
;;
"mirror")
COMPREPLY=($(compgen -W "${mirror_subcommands}" -- ${cur}))
return 0
;;
"repo")
COMPREPLY=($(compgen -W "${repo_subcommands}" -- ${cur}))
return 0
;;
"snapshot")
COMPREPLY=($(compgen -W "${snapshot_subcommands}" -- ${cur}))
return 0
;;
"publish")
COMPREPLY=($(compgen -W "${publish_subcommands}" -- ${cur}))
return 0
;;
"package")
COMPREPLY=($(compgen -W "${package_subcommands}" -- ${cur}))
return 0
;;
"task")
COMPREPLY=($(compgen -W "${task_subcommands}" -- ${cur}))
return 0
;;
"config")
COMPREPLY=($(compgen -W "${config_subcommands}" -- ${cur}))
return 0
;;
"api")
COMPREPLY=($(compgen -W "${api_subcommands}" -- ${cur}))
return 0
;;
*)
;;
esac
fi
case "$cmd" in
"mirror")
case "$subcmd" in
"create")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-filter= -filter-with-deps -force-components -ignore-signatures -keyring= -with-sources -with-udebs" -- ${cur}))
return 0
fi
fi
;;
"edit")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-archive-url= -filter= -filter-with-deps -ignore-signatures -keyring= -with-sources -with-udebs" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_mirror_list)" -- ${cur}))
fi
return 0
fi
;;
"show")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-with-packages" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_mirror_list)" -- ${cur}))
fi
return 0
fi
;;
"search")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-format= -with-deps" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_mirror_list)" -- ${cur}))
fi
return 0
fi
;;
"rename")
if [[ $numargs -eq 0 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_mirror_list)" -- ${cur}))
return 0
fi
;;
"drop")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-force" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_mirror_list)" -- ${cur}))
fi
return 0
fi
;;
"list")
if [[ $numargs -eq 0 ]]; then
COMPREPLY=($(compgen -W "-raw" -- ${cur}))
return 0
fi
;;
"update")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-force -download-limit= -ignore-checksums -ignore-signatures -keyring= -skip-existing-packages" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_mirror_list)" -- ${cur}))
fi
return 0
fi
;;
esac
;;
"repo")
case "$subcmd" in
"add")
case $numargs in
0)
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-force-replace -remove-files" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
fi
return 0
;;
1)
_filedir '@(deb|dsc|udeb)'
return 0
;;
esac
;;
"copy"|"move")
case $numargs in
0)
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-with-deps -dry-run" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
fi
return 0
;;
1)
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
return 0
;;
esac
;;
"create")
case $numargs in
0)
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-comment= -distribution= -component= -uploaders-file=" -- ${cur}))
return 0
fi
return 0
;;
1)
COMPREPLY=($(compgen -W "from" -- ${cur}))
return 0
;;
2)
COMPREPLY=($(compgen -W "snapshot" -- ${cur}))
return 0
;;
3)
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
return 0
;;
esac
;;
"drop")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-force" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
fi
return 0
fi
;;
"edit")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-comment= -distribution= -component= -uploaders-file=" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
fi
return 0
fi
;;
"search")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-format= -with-deps" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
fi
return 0
fi
;;
"list")
if [[ $numargs -eq 0 ]]; then
COMPREPLY=($(compgen -W "-raw" -- ${cur}))
return 0
fi
;;
"include")
case $numargs in
0)
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-accept-unsigned -force-replace -ignore-signatures -keyring= -no-remove-files -repo= -uploaders-file=" -- ${cur}))
else
comptopt -o filenames 2>/dev/null
COMPREPLY=($(compgen -f -- ${cur}))
return 0
fi
return 0
;;
esac
;;
"import")
case $numargs in
0)
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-with-deps -dry-run" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_mirror_list)" -- ${cur}))
fi
return 0
;;
1)
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
return 0
;;
esac
;;
"remove")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-dry-run" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
fi
return 0
fi
;;
"show")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-with-packages" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
fi
return 0
fi
;;
"rename")
if [[ $numargs -eq 0 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
return 0
fi
;;
esac
;;
"snapshot")
case "$subcmd" in
"create")
case $numargs in
1)
COMPREPLY=($(compgen -W "from empty" -- ${cur}))
return 0
;;
2)
if [[ "$prev" == "from" ]]; then
COMPREPLY=($(compgen -W "mirror repo" -- ${cur}))
return 0
fi
;;
3)
if [[ "$prev" == "mirror" ]]; then
COMPREPLY=($(compgen -W "$(__aptly_mirror_list)" -- ${cur}))
return 0
fi
if [[ "$prev" == "repo" ]]; then
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
return 0
fi
;;
esac
;;
"diff")
if [[ $numargs -eq 0 ]] && [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-only-matching" -- ${cur}))
return 0
fi
if [[ $numargs -lt 2 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
return 0
fi
;;
"drop")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-force" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
fi
return 0
fi
;;
"list")
if [[ $numargs -eq 0 ]]; then
COMPREPLY=($(compgen -W "-raw -sort=" -- ${cur}))
return 0
fi
;;
"merge")
if [[ $numargs -gt 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-latest" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
fi
return 0
fi
;;
"pull")
if [[ $numargs -eq 0 ]] && [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-all-matches -dry-run -no-deps -no-remove" -- ${cur}))
return 0
fi
if [[ $numargs -lt 2 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
return 0
fi
;;
"filter")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-with-deps" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
fi
return 0
fi
;;
"show")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-with-packages" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
fi
return 0
fi
;;
"search")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-format= -with-deps" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
fi
return 0
fi
;;
"rename")
if [[ $numargs -eq 0 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
return 0
fi
;;
"verify")
if [[ $numargs -eq 0 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
return 0
fi
;;
esac
;;
"publish")
case "$subcmd" in
"snapshot"|"repo")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-acquire-by-hash -batch -butautomaticupgrades= -component= -distribution= -force-overwrite -gpg-key= -keyring= -label= -notautomatic= -origin= -passphrase= -passphrase-file= -secret-keyring= -skip-contents -skip-signing" -- ${cur}))
else
if [[ "$subcmd" == "snapshot" ]]; then
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_repo_list)" -- ${cur}))
fi
fi
return 0
fi
if [[ $numargs -eq 1 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_published_prefixes)" -- ${cur}))
return 0
fi
;;
"list")
if [[ $numargs -eq 0 ]]; then
COMPREPLY=($(compgen -W "-raw" -- ${cur}))
return 0
fi
;;
"update")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-batch -force-overwrite -gpg-key= -keyring= -passphrase= -passphrase-file= -secret-keyring= -skip-cleanup -skip-contents -skip-signing" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_published_distributions)" -- ${cur}))
fi
return 0
fi
if [[ $numargs -eq 1 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_prefixes_for_distribution $prev)" -- ${cur}))
return 0
fi
;;
"switch")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-batch -force-overwrite -component= -gpg-key= -keyring= -passphrase= -passphrase-file= -secret-keyring= -skip-cleanup -skip-contents -skip-signing" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_published_distributions)" -- ${cur}))
fi
return 0
fi
if [[ $numargs -eq 1 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_prefixes_for_distribution $prev)" -- ${cur}))
return 0
fi
if [[ $numargs -ge 2 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_snapshot_list)" -- ${cur}))
return 0
fi
;;
"drop")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-force-drop -skip-cleanup" -- ${cur}))
else
COMPREPLY=($(compgen -W "$(__aptly_published_distributions)" -- ${cur}))
fi
return 0
fi
if [[ $numargs -eq 1 ]]; then
COMPREPLY=($(compgen -W "$(__aptly_prefixes_for_distribution $prev)" -- ${cur}))
return 0
fi
;;
esac
;;
"package")
case "$subcmd" in
"search")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-format=" -- ${cur}))
fi
return 0
fi
;;
"show")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-with-files -with-references" -- ${cur}))
fi
return 0
fi
;;
esac
;;
"serve")
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-listen=" -- ${cur}))
return 0
fi
;;
"graph")
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-format= -output=" -- ${cur}))
return 0
fi
;;
"api")
case "$subcmd" in
"serve")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-listen=" -- ${cur}))
fi
return 0
fi
;;
esac
;;
"db")
case "$subcmd" in
"cleanup")
if [[ $numargs -eq 0 ]]; then
if [[ "$cur" == -* ]]; then
COMPREPLY=($(compgen -W "-dry-run -verbose" -- ${cur}))
fi
return 0
fi
;;
esac
;;
esac
} && complete -F _aptly aptly
+2 -14
View File
@@ -2,17 +2,15 @@ package console
import ( import (
"fmt" "fmt"
"os"
"strings" "strings"
"github.com/aptly-dev/aptly/aptly"
"github.com/cheggaaa/pb" "github.com/cheggaaa/pb"
"github.com/smira/aptly/aptly"
"github.com/wsxiaoys/terminal/color" "github.com/wsxiaoys/terminal/color"
) )
const ( const (
codePrint = iota codePrint = iota
codePrintStdErr
codeProgress codeProgress
codeHideProgress codeHideProgress
codeStop codeStop
@@ -30,6 +28,7 @@ type printTask struct {
// Progress is a progress displaying subroutine, it allows to show download and other operations progress // Progress is a progress displaying subroutine, it allows to show download and other operations progress
// mixed with progress bar // mixed with progress bar
type Progress struct { type Progress struct {
stop chan bool
stopped chan bool stopped chan bool
queue chan printTask queue chan printTask
bar *pb.ProgressBar bar *pb.ProgressBar
@@ -129,11 +128,6 @@ func (p *Progress) Printf(msg string, a ...interface{}) {
p.queue <- printTask{code: codePrint, message: fmt.Sprintf(msg, a...)} p.queue <- printTask{code: codePrint, message: fmt.Sprintf(msg, a...)}
} }
// PrintfStdErr does printf but in safe manner to stderr
func (p *Progress) PrintfStdErr(msg string, a ...interface{}) {
p.queue <- printTask{code: codePrintStdErr, message: fmt.Sprintf(msg, a...)}
}
// ColoredPrintf does printf in colored way + newline // ColoredPrintf does printf in colored way + newline
func (p *Progress) ColoredPrintf(msg string, a ...interface{}) { func (p *Progress) ColoredPrintf(msg string, a ...interface{}) {
if RunningOnTerminal() { if RunningOnTerminal() {
@@ -189,12 +183,6 @@ func (p *Progress) worker() {
p.barShown = false p.barShown = false
} }
fmt.Print(task.message) fmt.Print(task.message)
case codePrintStdErr:
if p.barShown {
fmt.Print("\r\033[2K")
p.barShown = false
}
fmt.Fprint(os.Stderr, task.message)
case codeProgress: case codeProgress:
if hasBar { if hasBar {
fmt.Print("\r" + task.message) fmt.Print("\r" + task.message)
+36 -118
View File
@@ -2,11 +2,8 @@
package context package context
import ( import (
gocontext "context"
"fmt" "fmt"
"math/rand"
"os" "os"
"os/signal"
"path/filepath" "path/filepath"
"runtime" "runtime"
"runtime/pprof" "runtime/pprof"
@@ -14,16 +11,15 @@ import (
"sync" "sync"
"time" "time"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/console" "github.com/smira/aptly/console"
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/database"
"github.com/aptly-dev/aptly/deb" "github.com/smira/aptly/deb"
"github.com/aptly-dev/aptly/files" "github.com/smira/aptly/files"
"github.com/aptly-dev/aptly/http" "github.com/smira/aptly/http"
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/s3"
"github.com/aptly-dev/aptly/s3" "github.com/smira/aptly/swift"
"github.com/aptly-dev/aptly/swift" "github.com/smira/aptly/utils"
"github.com/aptly-dev/aptly/utils"
"github.com/smira/commander" "github.com/smira/commander"
"github.com/smira/flag" "github.com/smira/flag"
) )
@@ -32,8 +28,6 @@ import (
type AptlyContext struct { type AptlyContext struct {
sync.Mutex sync.Mutex
gocontext.Context
flags, globalFlags *flag.FlagSet flags, globalFlags *flag.FlagSet
configLoaded bool configLoaded bool
@@ -107,9 +101,6 @@ func (context *AptlyContext) config() *utils.ConfigStructure {
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Config file not found, creating default config at %s\n\n", configLocations[0]) fmt.Fprintf(os.Stderr, "Config file not found, creating default config at %s\n\n", configLocations[0])
// as this is fresh aptly installation, we don't need to support legacy pool locations
utils.Config.SkipLegacyPool = true
utils.SaveConfig(configLocations[0], &utils.Config) utils.SaveConfig(configLocations[0], &utils.Config)
} }
} }
@@ -158,9 +149,6 @@ func (context *AptlyContext) DependencyOptions() int {
if context.lookupOption(context.config().DepFollowSource, "dep-follow-source") { if context.lookupOption(context.config().DepFollowSource, "dep-follow-source") {
context.dependencyOptions |= deb.DepFollowSource context.dependencyOptions |= deb.DepFollowSource
} }
if context.lookupOption(context.config().DepVerboseResolve, "dep-verbose-resolve") {
context.dependencyOptions |= deb.DepVerboseResolve
}
} }
return context.dependencyOptions return context.dependencyOptions
@@ -213,7 +201,8 @@ func (context *AptlyContext) Downloader() aptly.Downloader {
if downloadLimit == 0 { if downloadLimit == 0 {
downloadLimit = context.config().DownloadLimit downloadLimit = context.config().DownloadLimit
} }
context.downloader = http.NewDownloader(downloadLimit*1024, context._progress()) context.downloader = http.NewDownloader(context.config().DownloadConcurrency,
downloadLimit*1024, context._progress())
} }
return context.downloader return context.downloader
@@ -244,34 +233,13 @@ func (context *AptlyContext) _database() (database.Storage, error) {
if context.database == nil { if context.database == nil {
var err error var err error
context.database, err = database.NewDB(context.dbPath()) context.database, err = database.OpenDB(context.dbPath())
if err != nil { if err != nil {
return nil, fmt.Errorf("can't instantiate database: %s", err) return nil, fmt.Errorf("can't open database: %s", err)
} }
} }
tries := context.flags.Lookup("db-open-attempts").Value.Get().(int) return context.database, nil
const BaseDelay = 10 * time.Second
const Jitter = 1 * time.Second
for ; tries >= 0; tries-- {
err := context.database.Open()
if err == nil || !strings.Contains(err.Error(), "resource temporarily unavailable") {
return context.database, err
}
if tries > 0 {
delay := time.Duration(rand.NormFloat64()*float64(Jitter) + float64(BaseDelay))
if delay < 0 {
delay = time.Second
}
context._progress().PrintfStdErr("Unable to open database, sleeping %s, attempts left %d...\n", delay, tries)
time.Sleep(delay)
}
}
return nil, fmt.Errorf("unable to reopen the DB, maximum number of retries reached")
} }
// CloseDatabase closes the db temporarily // CloseDatabase closes the db temporarily
@@ -288,9 +256,26 @@ func (context *AptlyContext) CloseDatabase() error {
// ReOpenDatabase reopens the db after close // ReOpenDatabase reopens the db after close
func (context *AptlyContext) ReOpenDatabase() error { func (context *AptlyContext) ReOpenDatabase() error {
_, err := context.Database() context.Lock()
defer context.Unlock()
if context.database == nil {
return nil
}
const MaxTries = 10
const Delay = 10 * time.Second
for try := 0; try < MaxTries; try++ {
err := context.database.ReOpen()
if err == nil || strings.Index(err.Error(), "resource temporarily unavailable") == -1 {
return err return err
}
context._progress().Printf("Unable to reopen database, sleeping %s\n", Delay)
<-time.After(Delay)
}
return fmt.Errorf("unable to reopen the DB, maximum number of retries reached")
} }
// CollectionFactory builds factory producing all kinds of collections // CollectionFactory builds factory producing all kinds of collections
@@ -315,7 +300,7 @@ func (context *AptlyContext) PackagePool() aptly.PackagePool {
defer context.Unlock() defer context.Unlock()
if context.packagePool == nil { if context.packagePool == nil {
context.packagePool = files.NewPackagePool(context.config().RootDir, !context.config().SkipLegacyPool) context.packagePool = files.NewPackagePool(context.config().RootDir)
} }
return context.packagePool return context.packagePool
@@ -329,14 +314,7 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto
publishedStorage, ok := context.publishedStorages[name] publishedStorage, ok := context.publishedStorages[name]
if !ok { if !ok {
if name == "" { if name == "" {
publishedStorage = files.NewPublishedStorage(filepath.Join(context.config().RootDir, "public"), "hardlink", "") publishedStorage = files.NewPublishedStorage(context.config().RootDir)
} else if strings.HasPrefix(name, "filesystem:") {
params, ok := context.config().FileSystemPublishRoots[name[11:]]
if !ok {
Fatal(fmt.Errorf("published local storage %v not configured", name[11:]))
}
publishedStorage = files.NewPublishedStorage(params.RootDir, params.LinkMethod, params.VerifyMethod)
} else if strings.HasPrefix(name, "s3:") { } else if strings.HasPrefix(name, "s3:") {
params, ok := context.config().S3PublishRoots[name[3:]] params, ok := context.config().S3PublishRoots[name[3:]]
if !ok { if !ok {
@@ -378,46 +356,6 @@ func (context *AptlyContext) UploadPath() string {
return filepath.Join(context.Config().RootDir, "upload") return filepath.Join(context.Config().RootDir, "upload")
} }
func (context *AptlyContext) pgpProvider() string {
var provider string
if context.globalFlags.IsSet("gpg-provider") {
provider = context.globalFlags.Lookup("gpg-provider").Value.String()
} else {
provider = context.config().GpgProvider
}
if !(provider == "gpg" || provider == "internal") { // nolint: goconst
Fatal(fmt.Errorf("unknown gpg provider: %v", provider))
}
return provider
}
// GetSigner returns Signer with respect to provider
func (context *AptlyContext) GetSigner() pgp.Signer {
context.Lock()
defer context.Unlock()
if context.pgpProvider() == "gpg" { // nolint: goconst
return pgp.NewGpgSigner()
}
return &pgp.GoSigner{}
}
// GetVerifier returns Verifier with respect to provider
func (context *AptlyContext) GetVerifier() pgp.Verifier {
context.Lock()
defer context.Unlock()
if context.pgpProvider() == "gpg" { // nolint: goconst
return pgp.NewGpgVerifier()
}
return &pgp.GoVerifier{}
}
// UpdateFlags sets internal copy of flags in the context // UpdateFlags sets internal copy of flags in the context
func (context *AptlyContext) UpdateFlags(flags *flag.FlagSet) { func (context *AptlyContext) UpdateFlags(flags *flag.FlagSet) {
context.Lock() context.Lock()
@@ -442,27 +380,6 @@ func (context *AptlyContext) GlobalFlags() *flag.FlagSet {
return context.globalFlags return context.globalFlags
} }
// GoContextHandleSignals upgrades context to handle ^C by aborting context
func (context *AptlyContext) GoContextHandleSignals() {
context.Lock()
defer context.Unlock()
// Catch ^C
sigch := make(chan os.Signal)
signal.Notify(sigch, os.Interrupt)
var cancel gocontext.CancelFunc
context.Context, cancel = gocontext.WithCancel(context.Context)
go func() {
<-sigch
signal.Stop(sigch)
context.Progress().PrintfStdErr("Aborting... press ^C once again to abort immediately\n")
cancel()
}()
}
// Shutdown shuts context down // Shutdown shuts context down
func (context *AptlyContext) Shutdown() { func (context *AptlyContext) Shutdown() {
context.Lock() context.Lock()
@@ -489,6 +406,7 @@ func (context *AptlyContext) Shutdown() {
context.database = nil context.database = nil
} }
if context.downloader != nil { if context.downloader != nil {
context.downloader.Abort()
context.downloader = nil context.downloader = nil
} }
if context.progress != nil { if context.progress != nil {
@@ -503,6 +421,7 @@ func (context *AptlyContext) Cleanup() {
defer context.Unlock() defer context.Unlock()
if context.downloader != nil { if context.downloader != nil {
context.downloader.Shutdown()
context.downloader = nil context.downloader = nil
} }
if context.progress != nil { if context.progress != nil {
@@ -519,7 +438,6 @@ func NewContext(flags *flag.FlagSet) (*AptlyContext, error) {
flags: flags, flags: flags,
globalFlags: flags, globalFlags: flags,
dependencyOptions: -1, dependencyOptions: -1,
Context: gocontext.TODO(),
publishedStorages: map[string]aptly.PublishedStorage{}, publishedStorages: map[string]aptly.PublishedStorage{},
} }
-86
View File
@@ -1,86 +0,0 @@
package context
import (
"reflect"
"testing"
"github.com/smira/flag"
. "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
type fatalErrorPanicChecker struct {
*CheckerInfo
}
var FatalErrorPanicMatches Checker = &fatalErrorPanicChecker{
&CheckerInfo{Name: "FatalErrorPanics", Params: []string{"function", "expected"}},
}
func (checker *fatalErrorPanicChecker) Check(params []interface{}, names []string) (result bool, errmsg string) {
f := reflect.ValueOf(params[0])
if f.Kind() != reflect.Func || f.Type().NumIn() != 0 {
return false, "Function must take zero arguments"
}
defer func() {
if errmsg != "" {
return
}
obtained := recover()
names[0] = "panic"
var ok bool
var e1 *FatalError
if e1, ok = obtained.(*FatalError); ok {
params[0] = e1
} else {
errmsg = "Panic value is not FatalError"
return
}
var e2 *FatalError
if e2, ok = params[1].(*FatalError); ok {
params[1] = e2
} else {
errmsg = "Expected value is not FatalError"
return
}
if *e1 == *e2 {
result = true
} else {
result = false
errmsg = "Not equal"
}
}()
f.Call(nil)
return false, "Function has not panicked"
}
type AptlyContextSuite struct {
context *AptlyContext
}
var _ = Suite(&AptlyContextSuite{})
func (s *AptlyContextSuite) SetUpTest(c *C) {
flags := flag.NewFlagSet("fakeFlags", flag.ContinueOnError)
flags.String("config", "", "")
context, err := NewContext(flags)
c.Assert(err, IsNil)
s.context = context
}
func (s *AptlyContextSuite) TestGetPublishedStorageBadFS(c *C) {
// https://github.com/aptly-dev/aptly/issues/711
// This will fail on account of us not having a config, so the
// storage never exists.
c.Assert(func() { s.context.GetPublishedStorage("filesystem:fuji") },
FatalErrorPanicMatches,
&FatalError{ReturnCode: 1, Message: "published local storage fuji not configured"})
}
+7 -13
View File
@@ -32,8 +32,8 @@ type Storage interface {
ProcessByPrefix(prefix []byte, proc StorageProcessor) error ProcessByPrefix(prefix []byte, proc StorageProcessor) error
KeysByPrefix(prefix []byte) [][]byte KeysByPrefix(prefix []byte) [][]byte
FetchByPrefix(prefix []byte) [][]byte FetchByPrefix(prefix []byte) [][]byte
Open() error
Close() error Close() error
ReOpen() error
StartBatch() StartBatch()
FinishBatch() error FinishBatch() error
CompactDB() error CompactDB() error
@@ -66,19 +66,13 @@ func internalOpen(path string, throttleCompaction bool) (*leveldb.DB, error) {
return leveldb.OpenFile(path, o) return leveldb.OpenFile(path, o)
} }
// NewDB creates new instance of DB, but doesn't open it (yet) // OpenDB opens (creates) LevelDB database
func NewDB(path string) (Storage, error) { func OpenDB(path string) (Storage, error) {
return &levelDB{path: path}, nil db, err := internalOpen(path, false)
}
// NewOpenDB creates new instance of DB and opens it
func NewOpenDB(path string) (Storage, error) {
db, err := NewDB(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &levelDB{db: db, path: path}, nil
return db, db.Open()
} }
// RecoverDB recovers LevelDB database from corruption // RecoverDB recovers LevelDB database from corruption
@@ -221,8 +215,8 @@ func (l *levelDB) Close() error {
return err return err
} }
// Reopen tries to open (re-open) the database // Reopen tries to re-open the database
func (l *levelDB) Open() error { func (l *levelDB) ReOpen() error {
if l.db != nil { if l.db != nil {
return nil return nil
} }
+3 -3
View File
@@ -22,7 +22,7 @@ func (s *LevelDBSuite) SetUpTest(c *C) {
var err error var err error
s.path = c.MkDir() s.path = c.MkDir()
s.db, err = NewOpenDB(s.path) s.db, err = OpenDB(s.path)
c.Assert(err, IsNil) c.Assert(err, IsNil)
} }
@@ -46,7 +46,7 @@ func (s *LevelDBSuite) TestRecoverDB(c *C) {
err = RecoverDB(s.path) err = RecoverDB(s.path)
c.Check(err, IsNil) c.Check(err, IsNil)
s.db, err = NewOpenDB(s.path) s.db, err = OpenDB(s.path)
c.Check(err, IsNil) c.Check(err, IsNil)
result, err := s.db.Get(key) result, err := s.db.Get(key)
@@ -223,7 +223,7 @@ func (s *LevelDBSuite) TestReOpen(c *C) {
err = s.db.Close() err = s.db.Close()
c.Assert(err, IsNil) c.Assert(err, IsNil)
err = s.db.Open() err = s.db.ReOpen()
c.Assert(err, IsNil) c.Assert(err, IsNil)
result, err := s.db.Get(key) result, err := s.db.Get(key)
+14 -12
View File
@@ -2,16 +2,14 @@ package deb
import ( import (
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/utils"
"github.com/aptly-dev/aptly/utils"
) )
// Changes is a result of .changes file parsing // Changes is a result of .changes file parsing
@@ -25,7 +23,7 @@ type Changes struct {
Binary []string Binary []string
Architectures []string Architectures []string
Stanza Stanza Stanza Stanza
SignatureKeys []pgp.Key SignatureKeys []utils.GpgKey
} }
// NewChanges moves .changes file into temporary directory and creates Changes structure // NewChanges moves .changes file into temporary directory and creates Changes structure
@@ -52,7 +50,7 @@ func NewChanges(path string) (*Changes, error) {
} }
// VerifyAndParse does optional signature verification and parses changes files // VerifyAndParse does optional signature verification and parses changes files
func (c *Changes) VerifyAndParse(acceptUnsigned, ignoreSignature bool, verifier pgp.Verifier) error { func (c *Changes) VerifyAndParse(acceptUnsigned, ignoreSignature bool, verifier utils.Verifier) error {
input, err := os.Open(filepath.Join(c.TempDir, c.ChangesName)) input, err := os.Open(filepath.Join(c.TempDir, c.ChangesName))
if err != nil { if err != nil {
return err return err
@@ -71,8 +69,7 @@ func (c *Changes) VerifyAndParse(acceptUnsigned, ignoreSignature bool, verifier
} }
if isClearSigned && !ignoreSignature { if isClearSigned && !ignoreSignature {
var keyInfo *pgp.KeyInfo keyInfo, err := verifier.VerifyClearsigned(input, false)
keyInfo, err = verifier.VerifyClearsigned(input, false)
if err != nil { if err != nil {
return err return err
} }
@@ -81,7 +78,7 @@ func (c *Changes) VerifyAndParse(acceptUnsigned, ignoreSignature bool, verifier
c.SignatureKeys = keyInfo.GoodKeys c.SignatureKeys = keyInfo.GoodKeys
} }
var text io.ReadCloser var text *os.File
if isClearSigned { if isClearSigned {
text, err = verifier.ExtractClearsigned(input) text, err = verifier.ExtractClearsigned(input)
@@ -106,7 +103,11 @@ func (c *Changes) VerifyAndParse(acceptUnsigned, ignoreSignature bool, verifier
c.Architectures = strings.Fields(c.Stanza["Architecture"]) c.Architectures = strings.Fields(c.Stanza["Architecture"])
c.Files, err = c.Files.ParseSumFields(c.Stanza) c.Files, err = c.Files.ParseSumFields(c.Stanza)
if err != nil {
return err return err
}
return nil
} }
// Prepare creates temporary directory, copies file there and verifies checksums // Prepare creates temporary directory, copies file there and verifies checksums
@@ -172,7 +173,7 @@ func (c *Changes) PackageQuery() (PackageQuery, error) {
// if c.Source is empty, this would never match // if c.Source is empty, this would never match
sourceQuery := &AndQuery{ sourceQuery := &AndQuery{
L: &FieldQuery{Field: "$PackageType", Relation: VersionEqual, Value: ArchitectureSource}, L: &FieldQuery{Field: "$PackageType", Relation: VersionEqual, Value: "source"},
R: &FieldQuery{Field: "Name", Relation: VersionEqual, Value: c.Source}, R: &FieldQuery{Field: "Name", Relation: VersionEqual, Value: c.Source},
} }
@@ -180,7 +181,8 @@ func (c *Changes) PackageQuery() (PackageQuery, error) {
if len(c.Binary) > 0 { if len(c.Binary) > 0 {
binaryQuery = &FieldQuery{Field: "Name", Relation: VersionEqual, Value: c.Binary[0]} binaryQuery = &FieldQuery{Field: "Name", Relation: VersionEqual, Value: c.Binary[0]}
// matching debug ddeb packages, they're not present in the Binary field // matching debug ddeb packages, they're not present in the Binary field
var ddebQuery PackageQuery = &FieldQuery{Field: "Name", Relation: VersionEqual, Value: fmt.Sprintf("%s-dbgsym", c.Binary[0])} var ddebQuery PackageQuery
ddebQuery = &FieldQuery{Field: "Name", Relation: VersionEqual, Value: fmt.Sprintf("%s-dbgsym", c.Binary[0])}
for _, binary := range c.Binary[1:] { for _, binary := range c.Binary[1:] {
binaryQuery = &OrQuery{ binaryQuery = &OrQuery{
@@ -204,7 +206,7 @@ func (c *Changes) PackageQuery() (PackageQuery, error) {
} }
binaryQuery = &AndQuery{ binaryQuery = &AndQuery{
L: &NotQuery{Q: &FieldQuery{Field: "$PackageType", Relation: VersionEqual, Value: ArchitectureSource}}, L: &NotQuery{Q: &FieldQuery{Field: "$PackageType", Relation: VersionEqual, Value: "source"}},
R: binaryQuery} R: binaryQuery}
} }
-67
View File
@@ -1,67 +0,0 @@
package deb
import (
"bytes"
"github.com/aptly-dev/aptly/aptly"
"github.com/aptly-dev/aptly/database"
"github.com/aptly-dev/aptly/utils"
"github.com/ugorji/go/codec"
)
// ChecksumCollection does management of ChecksumInfo in DB
type ChecksumCollection struct {
db database.Storage
codecHandle *codec.MsgpackHandle
}
// NewChecksumCollection creates new ChecksumCollection and binds it to database
func NewChecksumCollection(db database.Storage) *ChecksumCollection {
return &ChecksumCollection{
db: db,
codecHandle: &codec.MsgpackHandle{},
}
}
func (collection *ChecksumCollection) dbKey(path string) []byte {
return []byte("C" + path)
}
// Get finds checksums in DB by path
func (collection *ChecksumCollection) Get(path string) (*utils.ChecksumInfo, error) {
encoded, err := collection.db.Get(collection.dbKey(path))
if err != nil {
if err == database.ErrNotFound {
return nil, nil
}
return nil, err
}
c := &utils.ChecksumInfo{}
decoder := codec.NewDecoderBytes(encoded, collection.codecHandle)
err = decoder.Decode(c)
if err != nil {
return nil, err
}
return c, nil
}
// Update adds or updates information about checksum in DB
func (collection *ChecksumCollection) Update(path string, c *utils.ChecksumInfo) error {
var encodeBuffer bytes.Buffer
encoder := codec.NewEncoder(&encodeBuffer, collection.codecHandle)
err := encoder.Encode(c)
if err != nil {
return err
}
return collection.db.Put(collection.dbKey(path), encodeBuffer.Bytes())
}
// Check interface
var (
_ aptly.ChecksumStorage = &ChecksumCollection{}
)
-47
View File
@@ -1,47 +0,0 @@
package deb
import (
"github.com/aptly-dev/aptly/database"
"github.com/aptly-dev/aptly/utils"
. "gopkg.in/check.v1"
)
type ChecksumCollectionSuite struct {
collection *ChecksumCollection
c utils.ChecksumInfo
db database.Storage
}
var _ = Suite(&ChecksumCollectionSuite{})
func (s *ChecksumCollectionSuite) SetUpTest(c *C) {
s.c = utils.ChecksumInfo{
Size: 124,
MD5: "da39a3ee5e6b4b0d3255bfef95601890afd80709",
SHA1: "da39a3ee5e6b4b0d3255bfef95601890afd80709",
SHA256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
}
s.db, _ = database.NewOpenDB(c.MkDir())
s.collection = NewChecksumCollection(s.db)
}
func (s *ChecksumCollectionSuite) TearDownTest(c *C) {
s.db.Close()
}
func (s *ChecksumCollectionSuite) TestFlow(c *C) {
// checksum not stored
checksum, err := s.collection.Get("some/path")
c.Assert(err, IsNil)
c.Check(checksum, IsNil)
// store checksum
err = s.collection.Update("some/path", &s.c)
c.Assert(err, IsNil)
// load it back
checksum, err = s.collection.Get("some/path")
c.Assert(err, IsNil)
c.Check(*checksum, DeepEquals, s.c)
}
+1 -15
View File
@@ -3,7 +3,7 @@ package deb
import ( import (
"sync" "sync"
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/database"
) )
// CollectionFactory is a single place to generate all desired collections // CollectionFactory is a single place to generate all desired collections
@@ -15,7 +15,6 @@ type CollectionFactory struct {
snapshots *SnapshotCollection snapshots *SnapshotCollection
localRepos *LocalRepoCollection localRepos *LocalRepoCollection
publishedRepos *PublishedRepoCollection publishedRepos *PublishedRepoCollection
checksums *ChecksumCollection
} }
// NewCollectionFactory creates new factory // NewCollectionFactory creates new factory
@@ -90,18 +89,6 @@ func (factory *CollectionFactory) PublishedRepoCollection() *PublishedRepoCollec
return factory.publishedRepos return factory.publishedRepos
} }
// ChecksumCollection returns (or creates) new ChecksumCollection
func (factory *CollectionFactory) ChecksumCollection() *ChecksumCollection {
factory.Lock()
defer factory.Unlock()
if factory.checksums == nil {
factory.checksums = NewChecksumCollection(factory.db)
}
return factory.checksums
}
// Flush removes all references to collections, so that memory could be reclaimed // Flush removes all references to collections, so that memory could be reclaimed
func (factory *CollectionFactory) Flush() { func (factory *CollectionFactory) Flush() {
factory.Lock() factory.Lock()
@@ -112,5 +99,4 @@ func (factory *CollectionFactory) Flush() {
factory.remoteRepos = nil factory.remoteRepos = nil
factory.publishedRepos = nil factory.publishedRepos = nil
factory.packages = nil factory.packages = nil
factory.checksums = nil
} }
+6 -2
View File
@@ -6,7 +6,8 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/aptly"
"github.com/smira/aptly/database"
"github.com/smira/go-uuid/uuid" "github.com/smira/go-uuid/uuid"
) )
@@ -25,7 +26,10 @@ func NewContentsIndex(db database.Storage) *ContentsIndex {
} }
// Push adds package to contents index, calculating package contents as required // Push adds package to contents index, calculating package contents as required
func (index *ContentsIndex) Push(qualifiedName []byte, contents []string) error { func (index *ContentsIndex) Push(p *Package, packagePool aptly.PackagePool) error {
contents := p.Contents(packagePool)
qualifiedName := []byte(p.QualifiedName())
for _, path := range contents { for _, path := range contents {
// for performance reasons we only write to leveldb during push. // for performance reasons we only write to leveldb during push.
// merging of qualified names per path will be done in WriteTo // merging of qualified names per path will be done in WriteTo
+22 -47
View File
@@ -12,20 +12,12 @@ import (
"github.com/h2non/filetype/matchers" "github.com/h2non/filetype/matchers"
"github.com/mkrautz/goar" "github.com/mkrautz/goar"
"github.com/pkg/errors"
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/utils"
"github.com/smira/go-xz" "github.com/smira/go-xz"
"github.com/smira/lzma" "github.com/smira/lzma"
) )
// Source kinds
const (
SourceSnapshot = "snapshot"
SourceLocalRepo = "local"
SourceRemoteRepo = "repo"
)
// GetControlFileFromDeb reads control file from deb package // GetControlFileFromDeb reads control file from deb package
func GetControlFileFromDeb(packageFile string) (Stanza, error) { func GetControlFileFromDeb(packageFile string) (Stanza, error) {
file, err := os.Open(packageFile) file, err := os.Open(packageFile)
@@ -37,46 +29,21 @@ func GetControlFileFromDeb(packageFile string) (Stanza, error) {
library := ar.NewReader(file) library := ar.NewReader(file)
for { for {
header, err := library.Next() header, err := library.Next()
if err == io.EOF { if err == io.EOF {
return nil, fmt.Errorf("unable to find control.tar.* part in package %s", packageFile) return nil, fmt.Errorf("unable to find control.tar.gz part in package %s", packageFile)
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to read .deb archive %s: %s", packageFile, err) return nil, fmt.Errorf("unable to read .deb archive %s: %s", packageFile, err)
} }
// As per deb(5) version 1.19.0.4 the control file may be: if header.Name == "control.tar.gz" {
// - control.tar (since 1.17.6) ungzip, err := gzip.NewReader(library)
// - control.tar.gz
// - control.tar.xz (since 1.17.6)
// Look for all of the above and uncompress as necessary.
if strings.HasPrefix(header.Name, "control.tar") {
bufReader := bufio.NewReader(library)
var tarInput io.Reader
switch header.Name {
case "control.tar":
tarInput = bufReader
case "control.tar.gz":
ungzip, err := gzip.NewReader(bufReader)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "unable to ungzip %s from %s", header.Name, packageFile) return nil, fmt.Errorf("unable to ungzip control file from %s. Error: %s", packageFile, err)
} }
defer ungzip.Close() defer ungzip.Close()
tarInput = ungzip
case "control.tar.xz":
unxz, err := xz.NewReader(bufReader)
if err != nil {
return nil, errors.Wrapf(err, "unable to unxz %s from %s", header.Name, packageFile)
}
defer unxz.Close()
tarInput = unxz
default:
return nil, fmt.Errorf("unsupported tar compression in %s: %s", packageFile, header.Name)
}
untar := tar.NewReader(tarInput) untar := tar.NewReader(ungzip)
for { for {
tarHeader, err := untar.Next() tarHeader, err := untar.Next()
if err == io.EOF { if err == io.EOF {
@@ -101,7 +68,7 @@ func GetControlFileFromDeb(packageFile string) (Stanza, error) {
} }
// GetControlFileFromDsc reads control file from dsc package // GetControlFileFromDsc reads control file from dsc package
func GetControlFileFromDsc(dscFile string, verifier pgp.Verifier) (Stanza, error) { func GetControlFileFromDsc(dscFile string, verifier utils.Verifier) (Stanza, error) {
file, err := os.Open(dscFile) file, err := os.Open(dscFile)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -115,7 +82,7 @@ func GetControlFileFromDsc(dscFile string, verifier pgp.Verifier) (Stanza, error
return nil, err return nil, err
} }
var text io.ReadCloser var text *os.File
if isClearSigned { if isClearSigned {
text, err = verifier.ExtractClearsigned(file) text, err = verifier.ExtractClearsigned(file)
@@ -138,7 +105,13 @@ func GetControlFileFromDsc(dscFile string, verifier pgp.Verifier) (Stanza, error
} }
// GetContentsFromDeb returns list of files installed by .deb package // GetContentsFromDeb returns list of files installed by .deb package
func GetContentsFromDeb(file io.Reader, packageFile string) ([]string, error) { func GetContentsFromDeb(packageFile string) ([]string, error) {
file, err := os.Open(packageFile)
if err != nil {
return nil, err
}
defer file.Close()
library := ar.NewReader(file) library := ar.NewReader(file)
for { for {
header, err := library.Next() header, err := library.Next()
@@ -146,7 +119,7 @@ func GetContentsFromDeb(file io.Reader, packageFile string) ([]string, error) {
return nil, fmt.Errorf("unable to find data.tar.* part in %s", packageFile) return nil, fmt.Errorf("unable to find data.tar.* part in %s", packageFile)
} }
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "unable to read .deb archive from %s", packageFile) return nil, fmt.Errorf("unable to read .deb archive from %s: %s", packageFile, err)
} }
if strings.HasPrefix(header.Name, "data.tar") { if strings.HasPrefix(header.Name, "data.tar") {
@@ -169,7 +142,7 @@ func GetContentsFromDeb(file io.Reader, packageFile string) ([]string, error) {
} else { } else {
ungzip, err := gzip.NewReader(bufReader) ungzip, err := gzip.NewReader(bufReader)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "unable to ungzip data.tar.gz from %s", packageFile) return nil, fmt.Errorf("unable to ungzip data.tar.gz from %s: %s", packageFile, err)
} }
defer ungzip.Close() defer ungzip.Close()
tarInput = ungzip tarInput = ungzip
@@ -179,7 +152,7 @@ func GetContentsFromDeb(file io.Reader, packageFile string) ([]string, error) {
case "data.tar.xz": case "data.tar.xz":
unxz, err := xz.NewReader(bufReader) unxz, err := xz.NewReader(bufReader)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "unable to unxz data.tar.xz from %s", packageFile) return nil, fmt.Errorf("unable to unxz data.tar.xz from %s: %s", packageFile, err)
} }
defer unxz.Close() defer unxz.Close()
tarInput = unxz tarInput = unxz
@@ -199,14 +172,16 @@ func GetContentsFromDeb(file io.Reader, packageFile string) ([]string, error) {
return results, nil return results, nil
} }
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "unable to read .tar archive from %s", packageFile) return nil, fmt.Errorf("unable to read .tar archive from %s: %s", packageFile, err)
} }
if tarHeader.Typeflag == tar.TypeDir { if tarHeader.Typeflag == tar.TypeDir {
continue continue
} }
tarHeader.Name = strings.TrimPrefix(tarHeader.Name[2:], "./") if strings.HasPrefix(tarHeader.Name, "./") {
tarHeader.Name = tarHeader.Name[2:]
}
results = append(results, tarHeader.Name) results = append(results, tarHeader.Name)
} }
} }
+5 -21
View File
@@ -1,17 +1,16 @@
package deb package deb
import ( import (
"os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/utils"
. "gopkg.in/check.v1" . "gopkg.in/check.v1"
) )
type DebSuite struct { type DebSuite struct {
debFile, debFile2, debFileWithXzControl, dscFile, dscFileNoSign string debFile, debFile2, dscFile, dscFileNoSign string
} }
var _ = Suite(&DebSuite{}) var _ = Suite(&DebSuite{})
@@ -20,7 +19,6 @@ func (s *DebSuite) SetUpSuite(c *C) {
_, _File, _, _ := runtime.Caller(0) _, _File, _, _ := runtime.Caller(0)
s.debFile = filepath.Join(filepath.Dir(_File), "../system/files/libboost-program-options-dev_1.49.0.1_i386.deb") s.debFile = filepath.Join(filepath.Dir(_File), "../system/files/libboost-program-options-dev_1.49.0.1_i386.deb")
s.debFile2 = filepath.Join(filepath.Dir(_File), "../system/changes/hardlink_0.2.1_amd64.deb") s.debFile2 = filepath.Join(filepath.Dir(_File), "../system/changes/hardlink_0.2.1_amd64.deb")
s.debFileWithXzControl = filepath.Join(filepath.Dir(_File), "../system/changes/libqt5concurrent5-dbgsym_5.9.1+dfsg-2+18.04+bionic+build4_amd64.ddeb")
s.dscFile = filepath.Join(filepath.Dir(_File), "../system/files/pyspi_0.6.1-1.3.dsc") s.dscFile = filepath.Join(filepath.Dir(_File), "../system/files/pyspi_0.6.1-1.3.dsc")
s.dscFileNoSign = filepath.Join(filepath.Dir(_File), "../system/files/pyspi-0.6.1-1.3.stripped.dsc") s.dscFileNoSign = filepath.Join(filepath.Dir(_File), "../system/files/pyspi-0.6.1-1.3.stripped.dsc")
} }
@@ -39,16 +37,8 @@ func (s *DebSuite) TestGetControlFileFromDeb(c *C) {
c.Check(st["Package"], Equals, "libboost-program-options-dev") c.Check(st["Package"], Equals, "libboost-program-options-dev")
} }
func (s *DebSuite) TestGetControlFileFromDebWithXzControl(c *C) {
// Has control.tar.xz archive inside.
st, err := GetControlFileFromDeb(s.debFileWithXzControl)
c.Check(err, IsNil)
c.Check(st["Version"], Equals, "5.9.1+dfsg-2+18.04+bionic+build4")
c.Check(st["Package"], Equals, "libqt5concurrent5-dbgsym")
}
func (s *DebSuite) TestGetControlFileFromDsc(c *C) { func (s *DebSuite) TestGetControlFileFromDsc(c *C) {
verifier := &pgp.GoVerifier{} verifier := &utils.GpgVerifier{}
_, err := GetControlFileFromDsc("/no/such/file", verifier) _, err := GetControlFileFromDsc("/no/such/file", verifier)
c.Check(err, ErrorMatches, ".*no such file or directory") c.Check(err, ErrorMatches, ".*no such file or directory")
@@ -69,19 +59,13 @@ func (s *DebSuite) TestGetControlFileFromDsc(c *C) {
} }
func (s *DebSuite) TestGetContentsFromDeb(c *C) { func (s *DebSuite) TestGetContentsFromDeb(c *C) {
f, err := os.Open(s.debFile) contents, err := GetContentsFromDeb(s.debFile)
c.Assert(err, IsNil)
contents, err := GetContentsFromDeb(f, s.debFile)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(contents, DeepEquals, []string{"usr/share/doc/libboost-program-options-dev/changelog.gz", c.Check(contents, DeepEquals, []string{"usr/share/doc/libboost-program-options-dev/changelog.gz",
"usr/share/doc/libboost-program-options-dev/copyright"}) "usr/share/doc/libboost-program-options-dev/copyright"})
c.Assert(f.Close(), IsNil)
f, err = os.Open(s.debFile2) contents, err = GetContentsFromDeb(s.debFile2)
c.Assert(err, IsNil)
contents, err = GetContentsFromDeb(f, s.debFile2)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(contents, DeepEquals, []string{"usr/bin/hardlink", "usr/share/man/man1/hardlink.1.gz", c.Check(contents, DeepEquals, []string{"usr/bin/hardlink", "usr/share/man/man1/hardlink.1.gz",
"usr/share/doc/hardlink/changelog.gz", "usr/share/doc/hardlink/copyright", "usr/share/doc/hardlink/NEWS.Debian.gz"}) "usr/share/doc/hardlink/changelog.gz", "usr/share/doc/hardlink/copyright", "usr/share/doc/hardlink/NEWS.Debian.gz"})
c.Assert(f.Close(), IsNil)
} }
+1 -9
View File
@@ -11,9 +11,6 @@ import (
// Stanza or paragraph of Debian control file // Stanza or paragraph of Debian control file
type Stanza map[string]string type Stanza map[string]string
// MaxFieldSize is maximum stanza field size in bytes
const MaxFieldSize = 2 * 1024 * 1024
// Canonical order of fields in stanza // Canonical order of fields in stanza
// Taken from: http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/vivid/apt/vivid/view/head:/apt-pkg/tagfile.cc#L504 // Taken from: http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/vivid/apt/vivid/view/head:/apt-pkg/tagfile.cc#L504
var ( var (
@@ -25,8 +22,6 @@ var (
"Version", "Version",
"Codename", "Codename",
"Date", "Date",
"NotAutomatic",
"ButAutomaticUpgrades",
"Architectures", "Architectures",
"Architecture", "Architecture",
"Components", "Components",
@@ -217,10 +212,7 @@ type ControlFileReader struct {
// NewControlFileReader creates ControlFileReader, it wraps with buffering // NewControlFileReader creates ControlFileReader, it wraps with buffering
func NewControlFileReader(r io.Reader) *ControlFileReader { func NewControlFileReader(r io.Reader) *ControlFileReader {
scnr := bufio.NewScanner(bufio.NewReaderSize(r, 32768)) return &ControlFileReader{scanner: bufio.NewScanner(bufio.NewReaderSize(r, 32768))}
scnr.Buffer(nil, MaxFieldSize)
return &ControlFileReader{scanner: scnr}
} }
// ReadStanza reeads one stanza from control file // ReadStanza reeads one stanza from control file
-12
View File
@@ -3,7 +3,6 @@ package deb
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"os"
"strings" "strings"
. "gopkg.in/check.v1" . "gopkg.in/check.v1"
@@ -136,17 +135,6 @@ func (s *ControlFileSuite) TestCanonicalCase(c *C) {
c.Check(canonicalCase("packaGe-lIst"), Equals, "Package-List") c.Check(canonicalCase("packaGe-lIst"), Equals, "Package-List")
} }
func (s *ControlFileSuite) TestLongFields(c *C) {
f, err := os.Open("long.stanza")
c.Assert(err, IsNil)
defer f.Close()
r := NewControlFileReader(f)
stanza, e := r.ReadStanza(false)
c.Assert(e, IsNil)
c.Assert(len(stanza["Provides"]), Equals, 586929)
}
func (s *ControlFileSuite) BenchmarkReadStanza(c *C) { func (s *ControlFileSuite) BenchmarkReadStanza(c *C) {
for i := 0; i < c.N; i++ { for i := 0; i < c.N; i++ {
reader := bytes.NewBufferString(controlFile) reader := bytes.NewBufferString(controlFile)
+11 -11
View File
@@ -33,9 +33,9 @@ func BuildGraph(collectionFactory *CollectionFactory, layout string) (gographviz
existingNodes := map[string]bool{} existingNodes := map[string]bool{}
err = collectionFactory.RemoteRepoCollection().ForEach(func(repo *RemoteRepo) error { err = collectionFactory.RemoteRepoCollection().ForEach(func(repo *RemoteRepo) error {
e := collectionFactory.RemoteRepoCollection().LoadComplete(repo) err := collectionFactory.RemoteRepoCollection().LoadComplete(repo)
if e != nil { if err != nil {
return e return err
} }
graph.AddNode("aptly", repo.UUID, map[string]string{ graph.AddNode("aptly", repo.UUID, map[string]string{
@@ -55,9 +55,9 @@ func BuildGraph(collectionFactory *CollectionFactory, layout string) (gographviz
} }
err = collectionFactory.LocalRepoCollection().ForEach(func(repo *LocalRepo) error { err = collectionFactory.LocalRepoCollection().ForEach(func(repo *LocalRepo) error {
e := collectionFactory.LocalRepoCollection().LoadComplete(repo) err := collectionFactory.LocalRepoCollection().LoadComplete(repo)
if e != nil { if err != nil {
return e return err
} }
graph.AddNode("aptly", repo.UUID, map[string]string{ graph.AddNode("aptly", repo.UUID, map[string]string{
@@ -81,13 +81,13 @@ func BuildGraph(collectionFactory *CollectionFactory, layout string) (gographviz
}) })
err = collectionFactory.SnapshotCollection().ForEach(func(snapshot *Snapshot) error { err = collectionFactory.SnapshotCollection().ForEach(func(snapshot *Snapshot) error {
e := collectionFactory.SnapshotCollection().LoadComplete(snapshot) err := collectionFactory.SnapshotCollection().LoadComplete(snapshot)
if e != nil { if err != nil {
return e return err
} }
description := snapshot.Description description := snapshot.Description
if snapshot.SourceKind == SourceRemoteRepo { if snapshot.SourceKind == "repo" {
description = "Snapshot from repo" description = "Snapshot from repo"
} }
@@ -99,7 +99,7 @@ func BuildGraph(collectionFactory *CollectionFactory, layout string) (gographviz
snapshot.Name, description, snapshot.NumPackages(), labelEnd), snapshot.Name, description, snapshot.NumPackages(), labelEnd),
}) })
if snapshot.SourceKind == SourceRemoteRepo || snapshot.SourceKind == SourceLocalRepo || snapshot.SourceKind == SourceSnapshot { if snapshot.SourceKind == "repo" || snapshot.SourceKind == "local" || snapshot.SourceKind == "snapshot" {
for _, uuid := range snapshot.SourceIDs { for _, uuid := range snapshot.SourceIDs {
_, exists := existingNodes[uuid] _, exists := existingNodes[uuid]
if exists { if exists {
+18 -48
View File
@@ -6,13 +6,12 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/utils"
"github.com/aptly-dev/aptly/utils"
) )
// CollectPackageFiles walks filesystem collecting all candidates for package files // CollectPackageFiles walks filesystem collecting all candidates for package files
func CollectPackageFiles(locations []string, reporter aptly.ResultReporter) (packageFiles, otherFiles, failedFiles []string) { func CollectPackageFiles(locations []string, reporter aptly.ResultReporter) (packageFiles, failedFiles []string) {
for _, location := range locations { for _, location := range locations {
info, err2 := os.Stat(location) info, err2 := os.Stat(location)
if err2 != nil { if err2 != nil {
@@ -32,8 +31,6 @@ func CollectPackageFiles(locations []string, reporter aptly.ResultReporter) (pac
if strings.HasSuffix(info.Name(), ".deb") || strings.HasSuffix(info.Name(), ".udeb") || if strings.HasSuffix(info.Name(), ".deb") || strings.HasSuffix(info.Name(), ".udeb") ||
strings.HasSuffix(info.Name(), ".dsc") || strings.HasSuffix(info.Name(), ".ddeb") { strings.HasSuffix(info.Name(), ".dsc") || strings.HasSuffix(info.Name(), ".ddeb") {
packageFiles = append(packageFiles, path) packageFiles = append(packageFiles, path)
} else if strings.HasSuffix(info.Name(), ".buildinfo") {
otherFiles = append(otherFiles, path)
} }
return nil return nil
@@ -48,8 +45,6 @@ func CollectPackageFiles(locations []string, reporter aptly.ResultReporter) (pac
if strings.HasSuffix(info.Name(), ".deb") || strings.HasSuffix(info.Name(), ".udeb") || if strings.HasSuffix(info.Name(), ".deb") || strings.HasSuffix(info.Name(), ".udeb") ||
strings.HasSuffix(info.Name(), ".dsc") || strings.HasSuffix(info.Name(), ".ddeb") { strings.HasSuffix(info.Name(), ".dsc") || strings.HasSuffix(info.Name(), ".ddeb") {
packageFiles = append(packageFiles, location) packageFiles = append(packageFiles, location)
} else if strings.HasSuffix(info.Name(), ".buildinfo") {
otherFiles = append(otherFiles, location)
} else { } else {
reporter.Warning("Unknown file extension: %s", location) reporter.Warning("Unknown file extension: %s", location)
failedFiles = append(failedFiles, location) failedFiles = append(failedFiles, location)
@@ -64,9 +59,8 @@ func CollectPackageFiles(locations []string, reporter aptly.ResultReporter) (pac
} }
// ImportPackageFiles imports files into local repository // ImportPackageFiles imports files into local repository
func ImportPackageFiles(list *PackageList, packageFiles []string, forceReplace bool, verifier pgp.Verifier, func ImportPackageFiles(list *PackageList, packageFiles []string, forceReplace bool, verifier utils.Verifier,
pool aptly.PackagePool, collection *PackageCollection, reporter aptly.ResultReporter, restriction PackageQuery, pool aptly.PackagePool, collection *PackageCollection, reporter aptly.ResultReporter, restriction PackageQuery) (processedFiles []string, failedFiles []string, err error) {
checksumStorage aptly.ChecksumStorage) (processedFiles []string, failedFiles []string, err error) {
if forceReplace { if forceReplace {
list.PrepareIndex() list.PrepareIndex()
} }
@@ -122,24 +116,19 @@ func ImportPackageFiles(list *PackageList, packageFiles []string, forceReplace b
continue continue
} }
var files PackageFiles
if isSourcePackage {
files = p.Files()
}
var checksums utils.ChecksumInfo var checksums utils.ChecksumInfo
checksums, err = utils.ChecksumsForFile(file) checksums, err = utils.ChecksumsForFile(file)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
mainPackageFile := PackageFile{ if isSourcePackage {
Filename: filepath.Base(file), p.UpdateFiles(append(p.Files(), PackageFile{Filename: filepath.Base(file), Checksums: checksums}))
Checksums: checksums, } else {
p.UpdateFiles([]PackageFile{{Filename: filepath.Base(file), Checksums: checksums}})
} }
mainPackageFile.PoolPath, err = pool.Import(file, mainPackageFile.Filename, &mainPackageFile.Checksums, false, checksumStorage) err = pool.Import(file, checksums.MD5)
if err != nil { if err != nil {
reporter.Warning("Unable to import file %s into pool: %s", file, err) reporter.Warning("Unable to import file %s into pool: %s", file, err)
failedFiles = append(failedFiles, file) failedFiles = append(failedFiles, file)
@@ -148,45 +137,26 @@ func ImportPackageFiles(list *PackageList, packageFiles []string, forceReplace b
candidateProcessedFiles = append(candidateProcessedFiles, file) candidateProcessedFiles = append(candidateProcessedFiles, file)
// go over all the other files // go over all files, except for the last one (.dsc/.deb itself)
for i := range files { for _, f := range p.Files() {
sourceFile := filepath.Join(filepath.Dir(file), filepath.Base(files[i].Filename)) if filepath.Base(f.Filename) == filepath.Base(file) {
continue
_, err = os.Stat(sourceFile)
if err == nil {
files[i].PoolPath, err = pool.Import(sourceFile, files[i].Filename, &files[i].Checksums, false, checksumStorage)
if err == nil {
candidateProcessedFiles = append(candidateProcessedFiles, sourceFile)
} }
} else if os.IsNotExist(err) { sourceFile := filepath.Join(filepath.Dir(file), filepath.Base(f.Filename))
// if file is not present, try to find it in the pool err = pool.Import(sourceFile, f.Checksums.MD5)
var (
err2 error
found bool
)
files[i].PoolPath, found, err2 = pool.Verify("", files[i].Filename, &files[i].Checksums, checksumStorage)
if err2 != nil {
err = err2
} else if found {
// clear error, file is already in the package pool
err = nil
}
}
if err != nil { if err != nil {
reporter.Warning("Unable to import file %s into pool: %s", sourceFile, err) reporter.Warning("Unable to import file %s into pool: %s", sourceFile, err)
failedFiles = append(failedFiles, file) failedFiles = append(failedFiles, file)
break break
} }
candidateProcessedFiles = append(candidateProcessedFiles, sourceFile)
} }
if err != nil { if err != nil {
// some files haven't been imported // some files haven't been imported
continue continue
} }
p.UpdateFiles(append(files, mainPackageFile))
if restriction != nil && !restriction.Matches(p) { if restriction != nil && !restriction.Matches(p) {
reporter.Warning("%s has been ignored as it doesn't match restriction", p) reporter.Warning("%s has been ignored as it doesn't match restriction", p)
failedFiles = append(failedFiles, file) failedFiles = append(failedFiles, file)
+10 -120
View File
@@ -4,13 +4,11 @@ import (
"bufio" "bufio"
"fmt" "fmt"
"os" "os"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/utils"
"github.com/aptly-dev/aptly/utils"
) )
type indexFiles struct { type indexFiles struct {
@@ -21,7 +19,6 @@ type indexFiles struct {
tempDir string tempDir string
suffix string suffix string
indexes map[string]*indexFile indexes map[string]*indexFile
acquireByHash bool
} }
type indexFile struct { type indexFile struct {
@@ -30,7 +27,6 @@ type indexFile struct {
compressable bool compressable bool
onlyGzip bool onlyGzip bool
signable bool signable bool
acquireByHash bool
relativePath string relativePath string
tempFilename string tempFilename string
tempFile *os.File tempFile *os.File
@@ -52,7 +48,7 @@ func (file *indexFile) BufWriter() (*bufio.Writer, error) {
return file.w, nil return file.w, nil
} }
func (file *indexFile) Finalize(signer pgp.Signer) error { func (file *indexFile) Finalize(signer utils.Signer) error {
if file.w == nil { if file.w == nil {
if file.discardable { if file.discardable {
return nil return nil
@@ -94,22 +90,11 @@ func (file *indexFile) Finalize(signer pgp.Signer) error {
file.parent.generatedFiles[file.relativePath+ext] = checksumInfo file.parent.generatedFiles[file.relativePath+ext] = checksumInfo
} }
filedir := filepath.Dir(filepath.Join(file.parent.basePath, file.relativePath)) err = file.parent.publishedStorage.MkDir(filepath.Dir(filepath.Join(file.parent.basePath, file.relativePath)))
err = file.parent.publishedStorage.MkDir(filedir)
if err != nil { if err != nil {
return fmt.Errorf("unable to create dir: %s", err) return fmt.Errorf("unable to create dir: %s", err)
} }
if file.acquireByHash {
for _, hash := range []string{"MD5Sum", "SHA1", "SHA256", "SHA512"} {
err = file.parent.publishedStorage.MkDir(filepath.Join(filedir, "by-hash", hash))
if err != nil {
return fmt.Errorf("unable to create dir: %s", err)
}
}
}
for _, ext := range exts { for _, ext := range exts {
err = file.parent.publishedStorage.PutFile(filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+ext), err = file.parent.publishedStorage.PutFile(filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+ext),
file.tempFilename+ext) file.tempFilename+ext)
@@ -121,16 +106,6 @@ func (file *indexFile) Finalize(signer pgp.Signer) error {
file.parent.renameMap[filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+ext)] = file.parent.renameMap[filepath.Join(file.parent.basePath, file.relativePath+file.parent.suffix+ext)] =
filepath.Join(file.parent.basePath, file.relativePath+ext) filepath.Join(file.parent.basePath, file.relativePath+ext)
} }
if file.acquireByHash {
sums := file.parent.generatedFiles[file.relativePath+ext]
for hash, sum := range map[string]string{"SHA512": sums.SHA512, "SHA256": sums.SHA256, "SHA1": sums.SHA1, "MD5Sum": sums.MD5} {
err = packageIndexByHash(file, ext, hash, sum)
if err != nil {
return fmt.Errorf("unable to build hash file: %s", err)
}
}
}
} }
if file.signable && signer != nil { if file.signable && signer != nil {
@@ -167,57 +142,7 @@ func (file *indexFile) Finalize(signer pgp.Signer) error {
return nil return nil
} }
func packageIndexByHash(file *indexFile, ext string, hash string, sum string) error { func newIndexFiles(publishedStorage aptly.PublishedStorage, basePath, tempDir, suffix string) *indexFiles {
src := filepath.Join(file.parent.basePath, file.relativePath)
indexfile := path.Base(src + ext)
src = src + file.parent.suffix + ext
filedir := filepath.Dir(filepath.Join(file.parent.basePath, file.relativePath))
dst := filepath.Join(filedir, "by-hash", hash)
sumfilePath := filepath.Join(dst, sum)
// link already exists? do nothing
exists, err := file.parent.publishedStorage.FileExists(sumfilePath)
if err != nil {
return fmt.Errorf("Acquire-By-Hash: error checking exists of file %s: %s", sumfilePath, err)
}
if exists {
return nil
}
// create the link
err = file.parent.publishedStorage.HardLink(src, sumfilePath)
if err != nil {
return fmt.Errorf("Acquire-By-Hash: error creating hardlink %s: %s", sumfilePath, err)
}
// if a previous index file already exists exists, backup symlink
indexPath := filepath.Join(dst, indexfile)
oldIndexPath := filepath.Join(dst, indexfile+".old")
if exists, _ = file.parent.publishedStorage.FileExists(indexPath); exists {
// if exists, remove old symlink
if exists, _ = file.parent.publishedStorage.FileExists(oldIndexPath); exists {
var linkTarget string
linkTarget, err = file.parent.publishedStorage.ReadLink(oldIndexPath)
if err == nil {
// If we managed to resolve the link target: delete it. This is the
// oldest physical index file we no longer need. Once we drop our
// old symlink we'll essentially forget about it existing at all.
file.parent.publishedStorage.Remove(linkTarget)
}
file.parent.publishedStorage.Remove(oldIndexPath)
}
file.parent.publishedStorage.RenameFile(indexPath, oldIndexPath)
}
// create symlink
err = file.parent.publishedStorage.SymLink(filepath.Join(dst, sum), filepath.Join(dst, indexfile))
if err != nil {
return fmt.Errorf("Acquire-By-Hash: error creating symlink %s: %s", filepath.Join(dst, indexfile), err)
}
return nil
}
func newIndexFiles(publishedStorage aptly.PublishedStorage, basePath, tempDir, suffix string, acquireByHash bool) *indexFiles {
return &indexFiles{ return &indexFiles{
publishedStorage: publishedStorage, publishedStorage: publishedStorage,
basePath: basePath, basePath: basePath,
@@ -226,12 +151,11 @@ func newIndexFiles(publishedStorage aptly.PublishedStorage, basePath, tempDir, s
tempDir: tempDir, tempDir: tempDir,
suffix: suffix, suffix: suffix,
indexes: make(map[string]*indexFile), indexes: make(map[string]*indexFile),
acquireByHash: acquireByHash,
} }
} }
func (files *indexFiles) PackageIndex(component, arch string, udeb bool) *indexFile { func (files *indexFiles) PackageIndex(component, arch string, udeb bool) *indexFile {
if arch == ArchitectureSource { if arch == "source" {
udeb = false udeb = false
} }
key := fmt.Sprintf("pi-%s-%s-%v", component, arch, udeb) key := fmt.Sprintf("pi-%s-%s-%v", component, arch, udeb)
@@ -239,7 +163,7 @@ func (files *indexFiles) PackageIndex(component, arch string, udeb bool) *indexF
if !ok { if !ok {
var relativePath string var relativePath string
if arch == ArchitectureSource { if arch == "source" {
relativePath = filepath.Join(component, "source", "Sources") relativePath = filepath.Join(component, "source", "Sources")
} else { } else {
if udeb { if udeb {
@@ -254,7 +178,6 @@ func (files *indexFiles) PackageIndex(component, arch string, udeb bool) *indexF
discardable: false, discardable: false,
compressable: true, compressable: true,
signable: false, signable: false,
acquireByHash: files.acquireByHash,
relativePath: relativePath, relativePath: relativePath,
} }
@@ -265,7 +188,7 @@ func (files *indexFiles) PackageIndex(component, arch string, udeb bool) *indexF
} }
func (files *indexFiles) ReleaseIndex(component, arch string, udeb bool) *indexFile { func (files *indexFiles) ReleaseIndex(component, arch string, udeb bool) *indexFile {
if arch == ArchitectureSource { if arch == "source" {
udeb = false udeb = false
} }
key := fmt.Sprintf("ri-%s-%s-%v", component, arch, udeb) key := fmt.Sprintf("ri-%s-%s-%v", component, arch, udeb)
@@ -273,7 +196,7 @@ func (files *indexFiles) ReleaseIndex(component, arch string, udeb bool) *indexF
if !ok { if !ok {
var relativePath string var relativePath string
if arch == ArchitectureSource { if arch == "source" {
relativePath = filepath.Join(component, "source", "Release") relativePath = filepath.Join(component, "source", "Release")
} else { } else {
if udeb { if udeb {
@@ -288,7 +211,6 @@ func (files *indexFiles) ReleaseIndex(component, arch string, udeb bool) *indexF
discardable: udeb, discardable: udeb,
compressable: false, compressable: false,
signable: false, signable: false,
acquireByHash: files.acquireByHash,
relativePath: relativePath, relativePath: relativePath,
} }
@@ -299,7 +221,7 @@ func (files *indexFiles) ReleaseIndex(component, arch string, udeb bool) *indexF
} }
func (files *indexFiles) ContentsIndex(component, arch string, udeb bool) *indexFile { func (files *indexFiles) ContentsIndex(component, arch string, udeb bool) *indexFile {
if arch == ArchitectureSource { if arch == "source" {
udeb = false udeb = false
} }
key := fmt.Sprintf("ci-%s-%s-%v", component, arch, udeb) key := fmt.Sprintf("ci-%s-%s-%v", component, arch, udeb)
@@ -319,38 +241,6 @@ func (files *indexFiles) ContentsIndex(component, arch string, udeb bool) *index
compressable: true, compressable: true,
onlyGzip: true, onlyGzip: true,
signable: false, signable: false,
acquireByHash: files.acquireByHash,
relativePath: relativePath,
}
files.indexes[key] = file
}
return file
}
func (files *indexFiles) LegacyContentsIndex(arch string, udeb bool) *indexFile {
if arch == ArchitectureSource {
udeb = false
}
key := fmt.Sprintf("lci-%s-%v", arch, udeb)
file, ok := files.indexes[key]
if !ok {
var relativePath string
if udeb {
relativePath = fmt.Sprintf("Contents-udeb-%s", arch)
} else {
relativePath = fmt.Sprintf("Contents-%s", arch)
}
file = &indexFile{
parent: files,
discardable: true,
compressable: true,
onlyGzip: true,
signable: false,
acquireByHash: files.acquireByHash,
relativePath: relativePath, relativePath: relativePath,
} }
+20 -64
View File
@@ -3,10 +3,9 @@ package deb
import ( import (
"fmt" "fmt"
"sort" "sort"
"strings"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
) )
// Dependency options // Dependency options
@@ -21,8 +20,6 @@ const (
DepFollowAllVariants DepFollowAllVariants
// DepFollowBuild pulls build dependencies // DepFollowBuild pulls build dependencies
DepFollowBuild DepFollowBuild
// DepVerboseResolve emits additional logs while dependencies are being resolved
DepVerboseResolve
) )
// PackageList is list of unique (by key) packages // PackageList is list of unique (by key) packages
@@ -34,6 +31,8 @@ const (
type PackageList struct { type PackageList struct {
// Straight list of packages as map // Straight list of packages as map
packages map[string]*Package packages map[string]*Package
// Has index been prepared?
indexed bool
// Indexed list of packages, sorted by name internally // Indexed list of packages, sorted by name internally
packagesIndex []*Package packagesIndex []*Package
// Map of packages for each virtual package (provides) // Map of packages for each virtual package (provides)
@@ -42,8 +41,6 @@ type PackageList struct {
keyFunc func(p *Package) string keyFunc func(p *Package) string
// Allow duplicates? // Allow duplicates?
duplicatesAllowed bool duplicatesAllowed bool
// Has index been prepared?
indexed bool
} }
// PackageConflictError means that package can't be added to the list due to error // PackageConflictError means that package can't be added to the list due to error
@@ -124,14 +121,6 @@ func NewPackageListFromRefList(reflist *PackageRefList, collection *PackageColle
return result, nil return result, nil
} }
// Has checks whether package is already in the list
func (l *PackageList) Has(p *Package) bool {
key := l.keyFunc(p)
_, ok := l.packages[key]
return ok
}
// Add appends package to package list, additionally checking for uniqueness // Add appends package to package list, additionally checking for uniqueness
func (l *PackageList) Add(p *Package) error { func (l *PackageList) Add(p *Package) error {
key := l.keyFunc(p) key := l.keyFunc(p)
@@ -246,7 +235,7 @@ func (l *PackageList) Remove(p *Package) {
func (l *PackageList) Architectures(includeSource bool) (result []string) { func (l *PackageList) Architectures(includeSource bool) (result []string) {
result = make([]string, 0, 10) result = make([]string, 0, 10)
for _, pkg := range l.packages { for _, pkg := range l.packages {
if pkg.Architecture != ArchitectureAll && (pkg.Architecture != ArchitectureSource || includeSource) && !utils.StrSliceHasItem(result, pkg.Architecture) { if pkg.Architecture != "all" && (pkg.Architecture != "source" || includeSource) && !utils.StrSliceHasItem(result, pkg.Architecture) {
result = append(result, pkg.Architecture) result = append(result, pkg.Architecture)
} }
} }
@@ -357,14 +346,6 @@ func (l *PackageList) VerifyDependencies(options int, architectures []string, so
progress.ShutdownBar() progress.ShutdownBar()
} }
if options&DepVerboseResolve == DepVerboseResolve && progress != nil {
missingStr := make([]string, len(missing))
for i := range missing {
missingStr[i] = missing[i].String()
}
progress.ColoredPrintf("@{y}Missing dependencies:@| %s", strings.Join(missingStr, ", "))
}
return missing, nil return missing, nil
} }
@@ -449,6 +430,18 @@ func (l *PackageList) Search(dep Dependency, allMatches bool) (searchResults []*
panic("list not indexed, can't search") panic("list not indexed, can't search")
} }
if dep.Relation == VersionDontCare {
for _, p := range l.providesIndex[dep.Pkg] {
if dep.Architecture == "" || p.MatchesArchitecture(dep.Architecture) {
searchResults = append(searchResults, p)
if !allMatches {
break
}
}
}
}
i := sort.Search(len(l.packagesIndex), func(j int) bool { return l.packagesIndex[j].Name >= dep.Pkg }) 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 { for i < len(l.packagesIndex) && l.packagesIndex[i].Name == dep.Pkg {
@@ -464,28 +457,11 @@ func (l *PackageList) Search(dep Dependency, allMatches bool) (searchResults []*
i++ i++
} }
if dep.Relation == VersionDontCare {
for _, p := range l.providesIndex[dep.Pkg] {
if dep.Architecture == "" || p.MatchesArchitecture(dep.Architecture) {
searchResults = append(searchResults, p)
if !allMatches {
break
}
}
}
}
return return
} }
// Filter filters package index by specified queries (ORed together), possibly pulling dependencies // Filter filters package index by specified queries (ORed together), possibly pulling dependencies
func (l *PackageList) Filter(queries []PackageQuery, withDependencies bool, source *PackageList, dependencyOptions int, architecturesList []string) (*PackageList, error) { func (l *PackageList) Filter(queries []PackageQuery, withDependencies bool, source *PackageList, dependencyOptions int, architecturesList []string) (*PackageList, error) {
return l.FilterWithProgress(queries, withDependencies, source, dependencyOptions, architecturesList, nil)
}
// FilterWithProgress filters package index by specified queries (ORed together), possibly pulling dependencies and displays progress
func (l *PackageList) FilterWithProgress(queries []PackageQuery, withDependencies bool, source *PackageList, dependencyOptions int, architecturesList []string, progress aptly.Progress) (*PackageList, error) {
if !l.indexed { if !l.indexed {
panic("list not indexed, can't filter") panic("list not indexed, can't filter")
} }
@@ -512,37 +488,22 @@ func (l *PackageList) FilterWithProgress(queries []PackageQuery, withDependencie
added = 0 added = 0
// find missing dependencies // find missing dependencies
missing, err := result.VerifyDependencies(dependencyOptions, architecturesList, dependencySource, progress) missing, err := result.VerifyDependencies(dependencyOptions, architecturesList, dependencySource, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// try to satisfy dependencies // try to satisfy dependencies
for _, dep := range missing { for _, dep := range missing {
if dependencyOptions&DepFollowAllVariants == 0 {
// dependency might have already been satisfied // dependency might have already been satisfied
// with packages already been added // with packages already been added
//
// when follow-all-variants is enabled, we need to try to expand anyway,
// as even if dependency is satisfied now, there might be other ways to satisfy dependency
if result.Search(dep, false) != nil { if result.Search(dep, false) != nil {
if dependencyOptions&DepVerboseResolve == DepVerboseResolve && progress != nil {
progress.ColoredPrintf("@{y}Already satisfied dependency@|: %s with %s", &dep, result.Search(dep, true))
}
continue continue
} }
}
searchResults := l.Search(dep, true) searchResults := l.Search(dep, false)
if len(searchResults) > 0 { if searchResults != nil {
for _, p := range searchResults { for _, p := range searchResults {
if result.Has(p) {
continue
}
if dependencyOptions&DepVerboseResolve == DepVerboseResolve && progress != nil {
progress.ColoredPrintf("@{g}Injecting package@|: %s", p)
}
result.Add(p) result.Add(p)
dependencySource.Add(p) dependencySource.Add(p)
added++ added++
@@ -550,11 +511,6 @@ func (l *PackageList) FilterWithProgress(queries []PackageQuery, withDependencie
break break
} }
} }
} else {
if dependencyOptions&DepVerboseResolve == DepVerboseResolve && progress != nil {
progress.ColoredPrintf("@{r}Unsatisfied dependency@|: %s", dep.String())
}
} }
} }
} }
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"log" "log"
"sync" "sync"
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/database"
"github.com/smira/go-uuid/uuid" "github.com/smira/go-uuid/uuid"
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
) )
+7 -7
View File
@@ -3,7 +3,7 @@ package deb
import ( import (
"errors" "errors"
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/database"
. "gopkg.in/check.v1" . "gopkg.in/check.v1"
) )
@@ -18,7 +18,7 @@ type LocalRepoSuite struct {
var _ = Suite(&LocalRepoSuite{}) var _ = Suite(&LocalRepoSuite{})
func (s *LocalRepoSuite) SetUpTest(c *C) { func (s *LocalRepoSuite) SetUpTest(c *C) {
s.db, _ = database.NewOpenDB(c.MkDir()) s.db, _ = database.OpenDB(c.MkDir())
s.list = NewPackageList() s.list = NewPackageList()
s.list.Add(&Package{Name: "lib", Version: "1.7", Architecture: "i386"}) s.list.Add(&Package{Name: "lib", Version: "1.7", Architecture: "i386"})
s.list.Add(&Package{Name: "app", Version: "1.9", Architecture: "amd64"}) s.list.Add(&Package{Name: "app", Version: "1.9", Architecture: "amd64"})
@@ -83,7 +83,7 @@ type LocalRepoCollectionSuite struct {
var _ = Suite(&LocalRepoCollectionSuite{}) var _ = Suite(&LocalRepoCollectionSuite{})
func (s *LocalRepoCollectionSuite) SetUpTest(c *C) { func (s *LocalRepoCollectionSuite) SetUpTest(c *C) {
s.db, _ = database.NewOpenDB(c.MkDir()) s.db, _ = database.OpenDB(c.MkDir())
s.collection = NewLocalRepoCollection(s.db) s.collection = NewLocalRepoCollection(s.db)
s.list = NewPackageList() s.list = NewPackageList()
@@ -98,14 +98,14 @@ func (s *LocalRepoCollectionSuite) TearDownTest(c *C) {
} }
func (s *LocalRepoCollectionSuite) TestAddByName(c *C) { func (s *LocalRepoCollectionSuite) TestAddByName(c *C) {
_, err := s.collection.ByName("local1") r, err := s.collection.ByName("local1")
c.Assert(err, ErrorMatches, "*.not found") c.Assert(err, ErrorMatches, "*.not found")
repo := NewLocalRepo("local1", "Comment 1") repo := NewLocalRepo("local1", "Comment 1")
c.Assert(s.collection.Add(repo), IsNil) c.Assert(s.collection.Add(repo), IsNil)
c.Assert(s.collection.Add(repo), ErrorMatches, ".*already exists") c.Assert(s.collection.Add(repo), ErrorMatches, ".*already exists")
r, err := s.collection.ByName("local1") r, err = s.collection.ByName("local1")
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Assert(r.String(), Equals, repo.String()) c.Assert(r.String(), Equals, repo.String())
@@ -116,13 +116,13 @@ func (s *LocalRepoCollectionSuite) TestAddByName(c *C) {
} }
func (s *LocalRepoCollectionSuite) TestByUUID(c *C) { func (s *LocalRepoCollectionSuite) TestByUUID(c *C) {
_, err := s.collection.ByUUID("some-uuid") r, err := s.collection.ByUUID("some-uuid")
c.Assert(err, ErrorMatches, "*.not found") c.Assert(err, ErrorMatches, "*.not found")
repo := NewLocalRepo("local1", "Comment 1") repo := NewLocalRepo("local1", "Comment 1")
c.Assert(s.collection.Add(repo), IsNil) c.Assert(s.collection.Add(repo), IsNil)
r, err := s.collection.ByUUID(repo.UUID) r, err = s.collection.ByUUID(repo.UUID)
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Assert(r.String(), Equals, repo.String()) c.Assert(r.String(), Equals, repo.String())
} }
-12
View File
File diff suppressed because one or more lines are too long
+35 -61
View File
@@ -7,8 +7,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
) )
// Package is single instance of Debian package // Package is single instance of Debian package
@@ -24,12 +24,12 @@ type Package struct {
Source string Source string
// List of virtual packages this package provides // List of virtual packages this package provides
Provides []string Provides []string
// Hash of files section
FilesHash uint64
// Is this source package // Is this source package
IsSource bool IsSource bool
// Is this udeb package // Is this udeb package
IsUdeb bool IsUdeb bool
// Hash of files section
FilesHash uint64
// Is this >= 0.6 package? // Is this >= 0.6 package?
V06Plus bool V06Plus bool
// Offload fields // Offload fields
@@ -41,20 +41,6 @@ type Package struct {
collection *PackageCollection collection *PackageCollection
} }
// Package types
const (
PackageTypeBinary = "deb"
PackageTypeUdeb = "udeb"
PackageTypeSource = "source"
)
// Special arhictectures
const (
ArchitectureAll = "all"
ArhictectureAny = "any"
ArchitectureSource = "source"
)
// Check interface // Check interface
var ( var (
_ json.Marshaler = &Package{} _ json.Marshaler = &Package{}
@@ -232,12 +218,12 @@ func (p *Package) GetField(name string) string {
return p.Architecture return p.Architecture
case "$PackageType": case "$PackageType":
if p.IsSource { if p.IsSource {
return PackageTypeSource return "source"
} }
if p.IsUdeb { if p.IsUdeb {
return PackageTypeUdeb return "udeb"
} }
return PackageTypeBinary return "deb"
case "Name": case "Name":
return p.Name return p.Name
case "Version": case "Version":
@@ -270,7 +256,7 @@ func (p *Package) GetField(name string) string {
// MatchesArchitecture checks whether packages matches specified architecture // MatchesArchitecture checks whether packages matches specified architecture
func (p *Package) MatchesArchitecture(arch string) bool { func (p *Package) MatchesArchitecture(arch string) bool {
if p.Architecture == ArchitectureAll && arch != ArchitectureSource { if p.Architecture == "all" && arch != "source" {
return true return true
} }
@@ -358,7 +344,7 @@ func (p *Package) GetDependencies(options int) (dependencies []string) {
if source == "" { if source == "" {
source = p.Name source = p.Name
} }
if strings.Contains(source, ")") { if strings.Index(source, ")") != -1 {
dependencies = append(dependencies, fmt.Sprintf("%s {source}", source)) dependencies = append(dependencies, fmt.Sprintf("%s {source}", source))
} else { } else {
dependencies = append(dependencies, fmt.Sprintf("%s (= %s) {source}", source, p.Version)) dependencies = append(dependencies, fmt.Sprintf("%s (= %s) {source}", source, p.Version))
@@ -417,47 +403,32 @@ func (p *Package) Files() PackageFiles {
} }
// Contents returns cached package contents // Contents returns cached package contents
func (p *Package) Contents(packagePool aptly.PackagePool, progress aptly.Progress) []string { func (p *Package) Contents(packagePool aptly.PackagePool) []string {
if p.IsSource { if p.IsSource {
return nil return nil
} }
return p.collection.loadContents(p, packagePool, progress) return p.collection.loadContents(p, packagePool)
} }
// CalculateContents looks up contents in package file // CalculateContents looks up contents in package file
func (p *Package) CalculateContents(packagePool aptly.PackagePool, progress aptly.Progress) ([]string, error) { func (p *Package) CalculateContents(packagePool aptly.PackagePool) []string {
if p.IsSource { if p.IsSource {
return nil, nil return nil
} }
file := p.Files()[0] file := p.Files()[0]
poolPath, err := file.GetPoolPath(packagePool) path, err := packagePool.Path(file.Filename, file.Checksums.MD5)
if err != nil { if err != nil {
if progress != nil { panic(err)
progress.ColoredPrintf("@y[!]@| @!Failed to build pool path: @| %s", err)
}
return nil, err
} }
reader, err := packagePool.Open(poolPath) contents, err := GetContentsFromDeb(path)
if err != nil { if err != nil {
if progress != nil { panic(err)
progress.ColoredPrintf("@y[!]@| @!Failed to open package in pool: @| %s", err)
}
return nil, err
}
defer reader.Close()
contents, err := GetContentsFromDeb(reader, file.Filename)
if err != nil {
if progress != nil {
progress.ColoredPrintf("@y[!]@| @!Failed to generate package contents: @| %s", err)
}
return nil, err
} }
return contents, nil return contents
} }
// UpdateFiles saves new state of files // UpdateFiles saves new state of files
@@ -570,7 +541,7 @@ func (p *Package) LinkFromPool(publishedStorage aptly.PublishedStorage, packageP
} }
for i, f := range p.Files() { for i, f := range p.Files() {
sourcePoolPath, err := f.GetPoolPath(packagePool) sourcePath, err := packagePool.Path(f.Filename, f.Checksums.MD5)
if err != nil { if err != nil {
return err return err
} }
@@ -578,7 +549,7 @@ func (p *Package) LinkFromPool(publishedStorage aptly.PublishedStorage, packageP
relPath := filepath.Join("pool", component, poolDir) relPath := filepath.Join("pool", component, poolDir)
publishedDirectory := filepath.Join(prefix, relPath) publishedDirectory := filepath.Join(prefix, relPath)
err = publishedStorage.LinkFromPool(publishedDirectory, f.Filename, packagePool, sourcePoolPath, f.Checksums, force) err = publishedStorage.LinkFromPool(publishedDirectory, packagePool, sourcePath, f.Checksums.MD5, force)
if err != nil { if err != nil {
return err return err
} }
@@ -619,26 +590,29 @@ func (p *Package) PoolDirectory() (string, error) {
// PackageDownloadTask is a element of download queue for the package // PackageDownloadTask is a element of download queue for the package
type PackageDownloadTask struct { type PackageDownloadTask struct {
File *PackageFile RepoURI string
Additional []PackageDownloadTask DestinationPath string
TempDownPath string Checksums utils.ChecksumInfo
Done bool
} }
// DownloadList returns list of missing package files for download in format // DownloadList returns list of missing package files for download in format
// [[srcpath, dstpath]] // [[srcpath, dstpath]]
func (p *Package) DownloadList(packagePool aptly.PackagePool, checksumStorage aptly.ChecksumStorage) (result []PackageDownloadTask, err error) { func (p *Package) DownloadList(packagePool aptly.PackagePool) (result []PackageDownloadTask, err error) {
result = make([]PackageDownloadTask, 0, 1) result = make([]PackageDownloadTask, 0, 1)
files := p.Files() for _, f := range p.Files() {
for idx := range files { poolPath, err := packagePool.Path(f.Filename, f.Checksums.MD5)
verified, err := files[idx].Verify(packagePool, checksumStorage) if err != nil {
return nil, err
}
verified, err := f.Verify(packagePool)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !verified { if !verified {
result = append(result, PackageDownloadTask{File: &files[idx]}) result = append(result, PackageDownloadTask{RepoURI: f.DownloadURL(), DestinationPath: poolPath, Checksums: f.Checksums})
} }
} }
@@ -646,11 +620,11 @@ func (p *Package) DownloadList(packagePool aptly.PackagePool, checksumStorage ap
} }
// VerifyFiles verifies that all package files have neen correctly downloaded // VerifyFiles verifies that all package files have neen correctly downloaded
func (p *Package) VerifyFiles(packagePool aptly.PackagePool, checksumStorage aptly.ChecksumStorage) (result bool, err error) { func (p *Package) VerifyFiles(packagePool aptly.PackagePool) (result bool, err error) {
result = true result = true
for _, f := range p.Files() { for _, f := range p.Files() {
result, err = f.Verify(packagePool, checksumStorage) result, err = f.Verify(packagePool)
if err != nil || !result { if err != nil || !result {
return return
} }
@@ -665,7 +639,7 @@ func (p *Package) FilepathList(packagePool aptly.PackagePool) ([]string, error)
result := make([]string, len(p.Files())) result := make([]string, len(p.Files()))
for i, f := range p.Files() { for i, f := range p.Files() {
result[i], err = f.GetPoolPath(packagePool) result[i], err = packagePool.RelativePath(f.Filename, f.Checksums.MD5)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+5 -9
View File
@@ -5,8 +5,8 @@ import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/database"
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
) )
@@ -163,7 +163,7 @@ func (collection *PackageCollection) loadFiles(p *Package) *PackageFiles {
} }
// loadContents loads or calculates and saves package contents // loadContents loads or calculates and saves package contents
func (collection *PackageCollection) loadContents(p *Package, packagePool aptly.PackagePool, progress aptly.Progress) []string { func (collection *PackageCollection) loadContents(p *Package, packagePool aptly.PackagePool) []string {
encoded, err := collection.db.Get(p.Key("xC")) encoded, err := collection.db.Get(p.Key("xC"))
if err == nil { if err == nil {
contents := []string{} contents := []string{}
@@ -181,11 +181,7 @@ func (collection *PackageCollection) loadContents(p *Package, packagePool aptly.
panic("unable to load contents") panic("unable to load contents")
} }
contents, err := p.CalculateContents(packagePool, progress) contents := p.CalculateContents(packagePool)
if err != nil {
// failed to acquire contents, don't persist it
return contents
}
var buf bytes.Buffer var buf bytes.Buffer
err = codec.NewEncoder(&buf, collection.codecHandle).Encode(contents) err = codec.NewEncoder(&buf, collection.codecHandle).Encode(contents)
@@ -315,7 +311,7 @@ func (collection *PackageCollection) SearchSupported() bool {
// SearchByKey finds package by exact key // SearchByKey finds package by exact key
func (collection *PackageCollection) SearchByKey(arch, name, version string) (result *PackageList) { func (collection *PackageCollection) SearchByKey(arch, name, version string) (result *PackageList) {
result = NewPackageListWithDuplicates(true, 0) result = NewPackageList()
for _, key := range collection.db.KeysByPrefix([]byte(fmt.Sprintf("P%s %s %s", arch, name, version))) { for _, key := range collection.db.KeysByPrefix([]byte(fmt.Sprintf("P%s %s %s", arch, name, version))) {
pkg, err := collection.ByKey(key) pkg, err := collection.ByKey(key)
+3 -3
View File
@@ -1,8 +1,8 @@
package deb package deb
import ( import (
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/database"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
. "gopkg.in/check.v1" . "gopkg.in/check.v1"
) )
@@ -17,7 +17,7 @@ var _ = Suite(&PackageCollectionSuite{})
func (s *PackageCollectionSuite) SetUpTest(c *C) { func (s *PackageCollectionSuite) SetUpTest(c *C) {
s.p = NewPackageFromControlFile(packageStanza.Copy()) s.p = NewPackageFromControlFile(packageStanza.Copy())
s.db, _ = database.NewOpenDB(c.MkDir()) s.db, _ = database.OpenDB(c.MkDir())
s.collection = NewPackageCollection(s.db) s.collection = NewPackageCollection(s.db)
} }
+13 -20
View File
@@ -4,13 +4,14 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"hash/fnv" "hash/fnv"
"os"
"path/filepath" "path/filepath"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
) )
// PackageFile is a single file entry in package // PackageFile is a single file entry in package
@@ -19,33 +20,25 @@ type PackageFile struct {
Filename string Filename string
// Hashes for the file // Hashes for the file
Checksums utils.ChecksumInfo Checksums utils.ChecksumInfo
// PoolPath persists relative path to file in the package pool
PoolPath string
// Temporary field used while downloading, stored relative path on the mirror // Temporary field used while downloading, stored relative path on the mirror
downloadPath string downloadPath string
} }
// Verify that package file is present and correct // Verify that package file is present and correct
func (f *PackageFile) Verify(packagePool aptly.PackagePool, checksumStorage aptly.ChecksumStorage) (bool, error) { func (f *PackageFile) Verify(packagePool aptly.PackagePool) (bool, error) {
generatedPoolPath, exists, err := packagePool.Verify(f.PoolPath, f.Filename, &f.Checksums, checksumStorage) poolPath, err := packagePool.Path(f.Filename, f.Checksums.MD5)
if exists && err == nil { if err != nil {
f.PoolPath = generatedPoolPath return false, err
} }
return exists, err st, err := os.Stat(poolPath)
} if err != nil {
return false, nil
// GetPoolPath returns path to the file in the pool
//
// For legacy packages which do not have PoolPath field set, that calculates LegacyPath via pool
func (f *PackageFile) GetPoolPath(packagePool aptly.PackagePool) (string, error) {
var err error
if f.PoolPath == "" {
f.PoolPath, err = packagePool.LegacyPath(f.Filename, &f.Checksums)
} }
return f.PoolPath, err // verify size
// TODO: verify checksum if configured
return st.Size() == f.Checksums.Size, nil
} }
// DownloadURL return relative URL to package download location // DownloadURL return relative URL to package download location
+14 -14
View File
@@ -1,25 +1,22 @@
package deb package deb
import ( import (
"io/ioutil" "os"
"path/filepath" "path/filepath"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/files"
"github.com/aptly-dev/aptly/files" "github.com/smira/aptly/utils"
"github.com/aptly-dev/aptly/utils"
. "gopkg.in/check.v1" . "gopkg.in/check.v1"
) )
type PackageFilesSuite struct { type PackageFilesSuite struct {
files PackageFiles files PackageFiles
cs aptly.ChecksumStorage
} }
var _ = Suite(&PackageFilesSuite{}) var _ = Suite(&PackageFilesSuite{})
func (s *PackageFilesSuite) SetUpTest(c *C) { func (s *PackageFilesSuite) SetUpTest(c *C) {
s.cs = files.NewMockChecksumStorage()
s.files = PackageFiles{PackageFile{ s.files = PackageFiles{PackageFile{
Filename: "alien-arena-common_7.40-2_i386.deb", Filename: "alien-arena-common_7.40-2_i386.deb",
downloadPath: "pool/contrib/a/alien-arena", downloadPath: "pool/contrib/a/alien-arena",
@@ -32,24 +29,27 @@ func (s *PackageFilesSuite) SetUpTest(c *C) {
} }
func (s *PackageFilesSuite) TestVerify(c *C) { func (s *PackageFilesSuite) TestVerify(c *C) {
packagePool := files.NewPackagePool(c.MkDir(), false) packagePool := files.NewPackagePool(c.MkDir())
poolPath, _ := packagePool.Path(s.files[0].Filename, s.files[0].Checksums.MD5)
result, err := s.files[0].Verify(packagePool, s.cs) result, err := s.files[0].Verify(packagePool)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(result, Equals, false) c.Check(result, Equals, false)
tmpFilepath := filepath.Join(c.MkDir(), "file") err = os.MkdirAll(filepath.Dir(poolPath), 0755)
c.Assert(ioutil.WriteFile(tmpFilepath, []byte("abcde"), 0777), IsNil) c.Assert(err, IsNil)
s.files[0].PoolPath, _ = packagePool.Import(tmpFilepath, s.files[0].Filename, &s.files[0].Checksums, false, s.cs) file, err := os.Create(poolPath)
c.Assert(err, IsNil)
file.WriteString("abcde")
file.Close()
s.files[0].Checksums.Size = 187518 result, err = s.files[0].Verify(packagePool)
result, err = s.files[0].Verify(packagePool, s.cs)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(result, Equals, false) c.Check(result, Equals, false)
s.files[0].Checksums.Size = 5 s.files[0].Checksums.Size = 5
result, err = s.files[0].Verify(packagePool, s.cs) result, err = s.files[0].Verify(packagePool)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(result, Equals, true) c.Check(result, Equals, true)
} }
+41 -29
View File
@@ -2,11 +2,12 @@ package deb
import ( import (
"bytes" "bytes"
"io/ioutil" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"github.com/aptly-dev/aptly/files" "github.com/smira/aptly/files"
"github.com/smira/aptly/utils"
. "gopkg.in/check.v1" . "gopkg.in/check.v1"
) )
@@ -299,7 +300,7 @@ func (s *PackageSuite) TestMatchesDependency(c *C) {
// ~ // ~
c.Check( c.Check(
p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionRegexp, Version: "7\\.40-.*", p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionRegexp, Version: "7\\.40-.*",
Regexp: regexp.MustCompile(`7\.40-.*`)}), Equals, true) Regexp: regexp.MustCompile("7\\.40-.*")}), Equals, true)
c.Check( c.Check(
p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionRegexp, Version: "7\\.40-.*", p.MatchesDependency(Dependency{Pkg: "alien-arena-common", Architecture: "i386", Relation: VersionRegexp, Version: "7\\.40-.*",
Regexp: regexp.MustCompile("40")}), Equals, true) Regexp: regexp.MustCompile("40")}), Equals, true)
@@ -362,17 +363,19 @@ func (s *PackageSuite) TestPoolDirectory(c *C) {
} }
func (s *PackageSuite) TestLinkFromPool(c *C) { func (s *PackageSuite) TestLinkFromPool(c *C) {
packagePool := files.NewPackagePool(c.MkDir(), false) packagePool := files.NewPackagePool(c.MkDir())
cs := files.NewMockChecksumStorage() publishedStorage := files.NewPublishedStorage(c.MkDir())
publishedStorage := files.NewPublishedStorage(c.MkDir(), "", "")
p := NewPackageFromControlFile(s.stanza) p := NewPackageFromControlFile(s.stanza)
tmpFilepath := filepath.Join(c.MkDir(), "file") poolPath, _ := packagePool.Path(p.Files()[0].Filename, p.Files()[0].Checksums.MD5)
c.Assert(ioutil.WriteFile(tmpFilepath, nil, 0777), IsNil) err := os.MkdirAll(filepath.Dir(poolPath), 0755)
c.Assert(err, IsNil)
p.Files()[0].PoolPath, _ = packagePool.Import(tmpFilepath, p.Files()[0].Filename, &p.Files()[0].Checksums, false, cs) file, err := os.Create(poolPath)
c.Assert(err, IsNil)
file.Close()
err := p.LinkFromPool(publishedStorage, packagePool, "", "non-free", false) err = p.LinkFromPool(publishedStorage, packagePool, "", "non-free", false)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(p.Files()[0].Filename, Equals, "alien-arena-common_7.40-2_i386.deb") c.Check(p.Files()[0].Filename, Equals, "alien-arena-common_7.40-2_i386.deb")
c.Check(p.Files()[0].downloadPath, Equals, "pool/non-free/a/alien-arena") c.Check(p.Files()[0].downloadPath, Equals, "pool/non-free/a/alien-arena")
@@ -384,7 +387,7 @@ func (s *PackageSuite) TestLinkFromPool(c *C) {
} }
func (s *PackageSuite) TestFilepathList(c *C) { func (s *PackageSuite) TestFilepathList(c *C) {
packagePool := files.NewPackagePool(c.MkDir(), true) packagePool := files.NewPackagePool(c.MkDir())
p := NewPackageFromControlFile(s.stanza) p := NewPackageFromControlFile(s.stanza)
list, err := p.FilepathList(packagePool) list, err := p.FilepathList(packagePool)
@@ -393,24 +396,31 @@ func (s *PackageSuite) TestFilepathList(c *C) {
} }
func (s *PackageSuite) TestDownloadList(c *C) { func (s *PackageSuite) TestDownloadList(c *C) {
packagePool := files.NewPackagePool(c.MkDir(), false) packagePool := files.NewPackagePool(c.MkDir())
cs := files.NewMockChecksumStorage()
p := NewPackageFromControlFile(s.stanza) p := NewPackageFromControlFile(s.stanza)
p.Files()[0].Checksums.Size = 5 p.Files()[0].Checksums.Size = 5
poolPath, _ := packagePool.Path(p.Files()[0].Filename, p.Files()[0].Checksums.MD5)
list, err := p.DownloadList(packagePool, cs) list, err := p.DownloadList(packagePool)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(list, DeepEquals, []PackageDownloadTask{ c.Check(list, DeepEquals, []PackageDownloadTask{
{ {
File: &p.Files()[0], 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"}}})
tmpFilepath := filepath.Join(c.MkDir(), "file") err = os.MkdirAll(filepath.Dir(poolPath), 0755)
c.Assert(ioutil.WriteFile(tmpFilepath, []byte("abcde"), 0777), IsNil) c.Assert(err, IsNil)
p.Files()[0].PoolPath, _ = packagePool.Import(tmpFilepath, p.Files()[0].Filename, &p.Files()[0].Checksums, false, cs)
list, err = p.DownloadList(packagePool, cs) file, err := os.Create(poolPath)
c.Assert(err, IsNil)
file.WriteString("abcde")
file.Close()
list, err = p.DownloadList(packagePool)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(list, DeepEquals, []PackageDownloadTask{}) c.Check(list, DeepEquals, []PackageDownloadTask{})
} }
@@ -418,22 +428,24 @@ func (s *PackageSuite) TestDownloadList(c *C) {
func (s *PackageSuite) TestVerifyFiles(c *C) { func (s *PackageSuite) TestVerifyFiles(c *C) {
p := NewPackageFromControlFile(s.stanza) p := NewPackageFromControlFile(s.stanza)
packagePool := files.NewPackagePool(c.MkDir(), false) packagePool := files.NewPackagePool(c.MkDir())
cs := files.NewMockChecksumStorage() poolPath, _ := packagePool.Path(p.Files()[0].Filename, p.Files()[0].Checksums.MD5)
tmpFilepath := filepath.Join(c.MkDir(), "file") err := os.MkdirAll(filepath.Dir(poolPath), 0755)
c.Assert(ioutil.WriteFile(tmpFilepath, []byte("abcde"), 0777), IsNil) c.Assert(err, IsNil)
p.Files()[0].PoolPath, _ = packagePool.Import(tmpFilepath, p.Files()[0].Filename, &p.Files()[0].Checksums, false, cs) file, err := os.Create(poolPath)
c.Assert(err, IsNil)
file.WriteString("abcde")
file.Close()
p.Files()[0].Checksums.Size = 100 result, err := p.VerifyFiles(packagePool)
result, err := p.VerifyFiles(packagePool, cs)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(result, Equals, false) c.Check(result, Equals, false)
p.Files()[0].Checksums.Size = 5 p.Files()[0].Checksums.Size = 5
result, err = p.VerifyFiles(packagePool, cs) result, err = p.VerifyFiles(packagePool)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(result, Equals, true) c.Check(result, Equals, true)
} }
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
) )
var ppaRegexp = regexp.MustCompile("^ppa:([^/]+)/(.+)$") var ppaRegexp = regexp.MustCompile("^ppa:([^/]+)/(.+)$")
+1 -1
View File
@@ -1,7 +1,7 @@
package deb package deb
import ( import (
"github.com/aptly-dev/aptly/utils" "github.com/smira/aptly/utils"
. "gopkg.in/check.v1" . "gopkg.in/check.v1"
) )
+60 -131
View File
@@ -17,10 +17,9 @@ import (
"github.com/smira/go-uuid/uuid" "github.com/smira/go-uuid/uuid"
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/database"
"github.com/aptly-dev/aptly/pgp" "github.com/smira/aptly/utils"
"github.com/aptly-dev/aptly/utils"
) )
type repoSourceItem struct { type repoSourceItem struct {
@@ -41,13 +40,13 @@ type PublishedRepo struct {
Prefix string Prefix string
Distribution string Distribution string
Origin string Origin string
NotAutomatic string
ButAutomaticUpgrades string
Label string Label string
// Architectures is a list of all architectures published // Architectures is a list of all architectures published
Architectures []string Architectures []string
// SourceKind is "local"/"repo" // SourceKind is "local"/"repo"
SourceKind string SourceKind string
// Skip contents generation
SkipContents bool
// Map of sources by each component: component name -> source UUID // Map of sources by each component: component name -> source UUID
Sources map[string]string Sources map[string]string
@@ -56,17 +55,12 @@ type PublishedRepo struct {
Component string Component string
// SourceUUID is UUID of either snapshot or local repo // SourceUUID is UUID of either snapshot or local repo
SourceUUID string `codec:"SnapshotUUID"` SourceUUID string `codec:"SnapshotUUID"`
// Map of component to source items // Map of component to source items
sourceItems map[string]repoSourceItem sourceItems map[string]repoSourceItem
// Skip contents generation
SkipContents bool
// True if repo is being re-published // True if repo is being re-published
rePublishing bool rePublishing bool
// Provide index files per hash also
AcquireByHash bool
} }
// ParsePrefix splits [storage:]prefix into components // ParsePrefix splits [storage:]prefix into components
@@ -81,7 +75,6 @@ func ParsePrefix(param string) (storage, prefix string) {
} else { } else {
prefix = param prefix = param
} }
prefix = strings.TrimPrefix(strings.TrimSuffix(prefix, "/"), "/")
return return
} }
@@ -103,19 +96,19 @@ func walkUpTree(source interface{}, collectionFactory *CollectionFactory) (rootD
if snapshot, ok := head.(*Snapshot); ok { if snapshot, ok := head.(*Snapshot); ok {
for _, uuid := range snapshot.SourceIDs { for _, uuid := range snapshot.SourceIDs {
if snapshot.SourceKind == SourceRemoteRepo { if snapshot.SourceKind == "repo" {
remoteRepo, err := collectionFactory.RemoteRepoCollection().ByUUID(uuid) remoteRepo, err := collectionFactory.RemoteRepoCollection().ByUUID(uuid)
if err != nil { if err != nil {
continue continue
} }
current = append(current, remoteRepo) current = append(current, remoteRepo)
} else if snapshot.SourceKind == SourceLocalRepo { } else if snapshot.SourceKind == "local" {
localRepo, err := collectionFactory.LocalRepoCollection().ByUUID(uuid) localRepo, err := collectionFactory.LocalRepoCollection().ByUUID(uuid)
if err != nil { if err != nil {
continue continue
} }
current = append(current, localRepo) current = append(current, localRepo)
} else if snapshot.SourceKind == SourceSnapshot { } else if snapshot.SourceKind == "snapshot" {
snap, err := collectionFactory.SnapshotCollection().ByUUID(uuid) snap, err := collectionFactory.SnapshotCollection().ByUUID(uuid)
if err != nil { if err != nil {
continue continue
@@ -173,21 +166,24 @@ func NewPublishedRepo(storage, prefix, distribution string, architectures []stri
component string component string
snapshot *Snapshot snapshot *Snapshot
localRepo *LocalRepo localRepo *LocalRepo
fields = make(map[string][]string) ok bool
) )
// get first source // get first source
source = sources[0] source = sources[0]
// figure out source kind // figure out source kind
switch source.(type) { snapshot, ok = source.(*Snapshot)
case *Snapshot: if ok {
result.SourceKind = SourceSnapshot result.SourceKind = "snapshot"
case *LocalRepo: } else {
result.SourceKind = SourceLocalRepo localRepo, ok = source.(*LocalRepo)
default: if ok {
result.SourceKind = "local"
} else {
panic("unknown source kind") panic("unknown source kind")
} }
}
for i := range sources { for i := range sources {
component, source = components[i], sources[i] component, source = components[i], sources[i]
@@ -217,21 +213,11 @@ func NewPublishedRepo(storage, prefix, distribution string, architectures []stri
return nil, fmt.Errorf("duplicate component name: %s", component) return nil, fmt.Errorf("duplicate component name: %s", component)
} }
if result.SourceKind == SourceSnapshot { if result.SourceKind == "snapshot" {
snapshot = source.(*Snapshot) snapshot = source.(*Snapshot)
result.Sources[component] = snapshot.UUID result.Sources[component] = snapshot.UUID
result.sourceItems[component] = repoSourceItem{snapshot: snapshot} result.sourceItems[component] = repoSourceItem{snapshot: snapshot}
} else if result.SourceKind == "local" {
if !utils.StrSliceHasItem(fields["Origin"], snapshot.Origin) {
fields["Origin"] = append(fields["Origin"], snapshot.Origin)
}
if !utils.StrSliceHasItem(fields["NotAutomatic"], snapshot.NotAutomatic) {
fields["NotAutomatic"] = append(fields["NotAutomatic"], snapshot.NotAutomatic)
}
if !utils.StrSliceHasItem(fields["ButAutomaticUpgrades"], snapshot.ButAutomaticUpgrades) {
fields["ButAutomaticUpgrades"] = append(fields["ButAutomaticUpgrades"], snapshot.ButAutomaticUpgrades)
}
} else if result.SourceKind == SourceLocalRepo {
localRepo = source.(*LocalRepo) localRepo = source.(*LocalRepo)
result.Sources[component] = localRepo.UUID result.Sources[component] = localRepo.UUID
result.sourceItems[component] = repoSourceItem{localRepo: localRepo, packageRefs: localRepo.RefList()} result.sourceItems[component] = repoSourceItem{localRepo: localRepo, packageRefs: localRepo.RefList()}
@@ -240,7 +226,12 @@ func NewPublishedRepo(storage, prefix, distribution string, architectures []stri
// clean & verify prefix // clean & verify prefix
prefix = filepath.Clean(prefix) prefix = filepath.Clean(prefix)
prefix = strings.TrimPrefix(strings.TrimSuffix(prefix, "/"), "/") if strings.HasPrefix(prefix, "/") {
prefix = prefix[1:]
}
if strings.HasSuffix(prefix, "/") {
prefix = prefix[:len(prefix)-1]
}
prefix = filepath.Clean(prefix) prefix = filepath.Clean(prefix)
for _, part := range strings.Split(prefix, "/") { for _, part := range strings.Split(prefix, "/") {
@@ -261,23 +252,12 @@ func NewPublishedRepo(storage, prefix, distribution string, architectures []stri
} }
} }
if strings.Contains(distribution, "/") { if strings.Index(distribution, "/") != -1 {
return nil, fmt.Errorf("invalid distribution %s, '/' is not allowed", distribution) return nil, fmt.Errorf("invalid distribution %s, '/' is not allowed", distribution)
} }
result.Distribution = distribution result.Distribution = distribution
// only fields which are unique by all given snapshots are set on published
if len(fields["Origin"]) == 1 {
result.Origin = fields["Origin"][0]
}
if len(fields["NotAutomatic"]) == 1 {
result.NotAutomatic = fields["NotAutomatic"][0]
}
if len(fields["ButAutomaticUpgrades"]) == 1 {
result.ButAutomaticUpgrades = fields["ButAutomaticUpgrades"][0]
}
return result, nil return result, nil
} }
@@ -308,14 +288,11 @@ func (p *PublishedRepo) MarshalJSON() ([]byte, error) {
"Distribution": p.Distribution, "Distribution": p.Distribution,
"Label": p.Label, "Label": p.Label,
"Origin": p.Origin, "Origin": p.Origin,
"NotAutomatic": p.NotAutomatic,
"ButAutomaticUpgrades": p.ButAutomaticUpgrades,
"Prefix": p.Prefix, "Prefix": p.Prefix,
"SourceKind": p.SourceKind, "SourceKind": p.SourceKind,
"Sources": sources, "Sources": sources,
"Storage": p.Storage, "Storage": p.Storage,
"SkipContents": p.SkipContents, "SkipContents": p.SkipContents,
"AcquireByHash": p.AcquireByHash,
}) })
} }
@@ -338,26 +315,18 @@ func (p *PublishedRepo) String() string {
sources = append(sources, fmt.Sprintf("{%s: %s}", component, source)) sources = append(sources, fmt.Sprintf("{%s: %s}", component, source))
} }
var extras []string
var extra string var extra string
if p.Origin != "" { if p.Origin != "" {
extras = append(extras, fmt.Sprintf("origin: %s", p.Origin)) extra += fmt.Sprintf("origin: %s", p.Origin)
}
if p.NotAutomatic != "" {
extras = append(extras, fmt.Sprintf("notautomatic: %s", p.NotAutomatic))
}
if p.ButAutomaticUpgrades != "" {
extras = append(extras, fmt.Sprintf("butautomaticupgrades: %s", p.ButAutomaticUpgrades))
} }
if p.Label != "" { if p.Label != "" {
extras = append(extras, fmt.Sprintf("label: %s", p.Label)) if extra != "" {
extra += ", "
}
extra += fmt.Sprintf("label: %s", p.Label)
} }
extra = strings.Join(extras, ", ")
if extra != "" { if extra != "" {
extra = " (" + extra + ")" extra = " (" + extra + ")"
@@ -389,10 +358,10 @@ func (p *PublishedRepo) RefKey(component string) []byte {
// RefList returns list of package refs in local repo // RefList returns list of package refs in local repo
func (p *PublishedRepo) RefList(component string) *PackageRefList { func (p *PublishedRepo) RefList(component string) *PackageRefList {
item := p.sourceItems[component] item := p.sourceItems[component]
if p.SourceKind == SourceLocalRepo { if p.SourceKind == "local" {
return item.packageRefs return item.packageRefs
} }
if p.SourceKind == SourceSnapshot { if p.SourceKind == "snapshot" {
return item.snapshot.RefList() return item.snapshot.RefList()
} }
panic("unknown source") panic("unknown source")
@@ -411,7 +380,7 @@ func (p *PublishedRepo) Components() []string {
// UpdateLocalRepo updates content from local repo in component // UpdateLocalRepo updates content from local repo in component
func (p *PublishedRepo) UpdateLocalRepo(component string) { func (p *PublishedRepo) UpdateLocalRepo(component string) {
if p.SourceKind != SourceLocalRepo { if p.SourceKind != "local" {
panic("not local repo publish") panic("not local repo publish")
} }
@@ -424,7 +393,7 @@ func (p *PublishedRepo) UpdateLocalRepo(component string) {
// UpdateSnapshot switches snapshot for component // UpdateSnapshot switches snapshot for component
func (p *PublishedRepo) UpdateSnapshot(component string, snapshot *Snapshot) { func (p *PublishedRepo) UpdateSnapshot(component string, snapshot *Snapshot) {
if p.SourceKind != SourceSnapshot { if p.SourceKind != "snapshot" {
panic("not snapshot publish") panic("not snapshot publish")
} }
@@ -456,7 +425,7 @@ func (p *PublishedRepo) Decode(input []byte) error {
// old PublishedRepo were publishing only snapshots // old PublishedRepo were publishing only snapshots
if p.SourceKind == "" { if p.SourceKind == "" {
p.SourceKind = SourceSnapshot p.SourceKind = "snapshot"
} }
// <0.6 aptly used single SourceUUID + Component instead of Sources // <0.6 aptly used single SourceUUID + Component instead of Sources
@@ -487,7 +456,7 @@ func (p *PublishedRepo) GetLabel() string {
// Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them // Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them
func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageProvider aptly.PublishedStorageProvider, func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageProvider aptly.PublishedStorageProvider,
collectionFactory *CollectionFactory, signer pgp.Signer, progress aptly.Progress, forceOverwrite bool) error { collectionFactory *CollectionFactory, signer utils.Signer, progress aptly.Progress, forceOverwrite bool) error {
publishedStorage := publishedStorageProvider.GetPublishedStorage(p.Storage) publishedStorage := publishedStorageProvider.GetPublishedStorage(p.Storage)
err := publishedStorage.MkDir(filepath.Join(p.Prefix, "pool")) err := publishedStorage.MkDir(filepath.Join(p.Prefix, "pool"))
@@ -505,7 +474,8 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
return err return err
} }
defer func() { defer func() {
e := tempDB.Close() var e error
e = tempDB.Close()
if e != nil && progress != nil { if e != nil && progress != nil {
progress.Printf("failed to close temp DB: %s", err) progress.Printf("failed to close temp DB: %s", err)
} }
@@ -560,9 +530,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
} }
defer os.RemoveAll(tempDir) defer os.RemoveAll(tempDir)
indexes := newIndexFiles(publishedStorage, basePath, tempDir, suffix, p.AcquireByHash) indexes := newIndexFiles(publishedStorage, basePath, tempDir, suffix)
legacyContentIndexes := map[string]*ContentsIndex{}
for component, list := range lists { for component, list := range lists {
hadUdebs := false hadUdebs := false
@@ -601,32 +569,21 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
} }
} }
// Start a db batch. If we fill contents data we'll need
// to push each path of the package into the database.
// We'll want this batched so as to avoid an excessive
// amount of write() calls.
tempDB.StartBatch()
defer tempDB.FinishBatch()
for _, arch := range p.Architectures { for _, arch := range p.Architectures {
if pkg.MatchesArchitecture(arch) { if pkg.MatchesArchitecture(arch) {
var bufWriter *bufio.Writer var bufWriter *bufio.Writer
if !p.SkipContents { if !p.SkipContents {
key := fmt.Sprintf("%s-%v", arch, pkg.IsUdeb) key := fmt.Sprintf("%s-%v", arch, pkg.IsUdeb)
qualifiedName := []byte(pkg.QualifiedName())
contents := pkg.Contents(packagePool, progress)
for _, contentIndexesMap := range []map[string]*ContentsIndex{contentIndexes, legacyContentIndexes} { contentIndex := contentIndexes[key]
contentIndex := contentIndexesMap[key]
if contentIndex == nil { if contentIndex == nil {
contentIndex = NewContentsIndex(tempDB) contentIndex = NewContentsIndex(tempDB)
contentIndexesMap[key] = contentIndex contentIndexes[key] = contentIndex
} }
contentIndex.Push(qualifiedName, contents) contentIndex.Push(pkg, packagePool)
}
} }
bufWriter, err = indexes.PackageIndex(component, arch, pkg.IsUdeb).BufWriter() bufWriter, err = indexes.PackageIndex(component, arch, pkg.IsUdeb).BufWriter()
@@ -664,8 +621,7 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
continue continue
} }
var bufWriter *bufio.Writer bufWriter, err := indexes.ContentsIndex(component, arch, udeb).BufWriter()
bufWriter, err = indexes.ContentsIndex(component, arch, udeb).BufWriter()
if err != nil { if err != nil {
return fmt.Errorf("unable to generate contents index: %v", err) return fmt.Errorf("unable to generate contents index: %v", err)
} }
@@ -700,9 +656,6 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
release["Component"] = component release["Component"] = component
release["Origin"] = p.GetOrigin() release["Origin"] = p.GetOrigin()
release["Label"] = p.GetLabel() release["Label"] = p.GetLabel()
if p.AcquireByHash {
release["Acquire-By-Hash"] = "yes"
}
var bufWriter *bufio.Writer var bufWriter *bufio.Writer
bufWriter, err = indexes.ReleaseIndex(component, arch, udeb).BufWriter() bufWriter, err = indexes.ReleaseIndex(component, arch, udeb).BufWriter()
@@ -718,26 +671,6 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
} }
} }
for _, arch := range p.Architectures {
for _, udeb := range []bool{true, false} {
index := legacyContentIndexes[fmt.Sprintf("%s-%v", arch, udeb)]
if index == nil || index.Empty() {
continue
}
var bufWriter *bufio.Writer
bufWriter, err = indexes.LegacyContentsIndex(arch, udeb).BufWriter()
if err != nil {
return fmt.Errorf("unable to generate contents index: %v", err)
}
_, err = index.WriteTo(bufWriter)
if err != nil {
return fmt.Errorf("unable to generate contents index: %v", err)
}
}
}
if progress != nil { if progress != nil {
progress.Printf("Finalizing metadata files...\n") progress.Printf("Finalizing metadata files...\n")
} }
@@ -749,20 +682,11 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
release := make(Stanza) release := make(Stanza)
release["Origin"] = p.GetOrigin() release["Origin"] = p.GetOrigin()
if p.NotAutomatic != "" {
release["NotAutomatic"] = p.NotAutomatic
}
if p.ButAutomaticUpgrades != "" {
release["ButAutomaticUpgrades"] = p.ButAutomaticUpgrades
}
release["Label"] = p.GetLabel() release["Label"] = p.GetLabel()
release["Suite"] = p.Distribution release["Suite"] = p.Distribution
release["Codename"] = p.Distribution release["Codename"] = p.Distribution
release["Date"] = time.Now().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST") release["Date"] = time.Now().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST")
release["Architectures"] = strings.Join(utils.StrSlicesSubstract(p.Architectures, []string{ArchitectureSource}), " ") release["Architectures"] = strings.Join(utils.StrSlicesSubstract(p.Architectures, []string{"source"}), " ")
if p.AcquireByHash {
release["Acquire-By-Hash"] = "yes"
}
release["Description"] = " Generated by aptly\n" release["Description"] = " Generated by aptly\n"
release["MD5Sum"] = "" release["MD5Sum"] = ""
release["SHA1"] = "" release["SHA1"] = ""
@@ -806,7 +730,12 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP
return err return err
} }
return indexes.RenameFiles() err = indexes.RenameFiles()
if err != nil {
return err
}
return nil
} }
// RemoveFiles removes files that were created by Publish // RemoveFiles removes files that were created by Publish
@@ -905,7 +834,7 @@ func (collection *PublishedRepoCollection) Update(repo *PublishedRepo) (err erro
return return
} }
if repo.SourceKind == SourceLocalRepo { if repo.SourceKind == "local" {
for component, item := range repo.sourceItems { for component, item := range repo.sourceItems {
err = collection.db.Put(repo.RefKey(component), item.packageRefs.Encode()) err = collection.db.Put(repo.RefKey(component), item.packageRefs.Encode())
if err != nil { if err != nil {
@@ -920,7 +849,7 @@ func (collection *PublishedRepoCollection) Update(repo *PublishedRepo) (err erro
func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, collectionFactory *CollectionFactory) (err error) { func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, collectionFactory *CollectionFactory) (err error) {
repo.sourceItems = make(map[string]repoSourceItem) repo.sourceItems = make(map[string]repoSourceItem)
if repo.SourceKind == SourceSnapshot { if repo.SourceKind == "snapshot" {
for component, sourceUUID := range repo.Sources { for component, sourceUUID := range repo.Sources {
item := repoSourceItem{} item := repoSourceItem{}
@@ -935,7 +864,7 @@ func (collection *PublishedRepoCollection) LoadComplete(repo *PublishedRepo, col
repo.sourceItems[component] = item repo.sourceItems[component] = item
} }
} else if repo.SourceKind == SourceLocalRepo { } else if repo.SourceKind == "local" {
for component, sourceUUID := range repo.Sources { for component, sourceUUID := range repo.Sources {
item := repoSourceItem{} item := repoSourceItem{}
@@ -1003,7 +932,7 @@ func (collection *PublishedRepoCollection) ByUUID(uuid string) (*PublishedRepo,
func (collection *PublishedRepoCollection) BySnapshot(snapshot *Snapshot) []*PublishedRepo { func (collection *PublishedRepoCollection) BySnapshot(snapshot *Snapshot) []*PublishedRepo {
var result []*PublishedRepo var result []*PublishedRepo
for _, r := range collection.list { for _, r := range collection.list {
if r.SourceKind == SourceSnapshot { if r.SourceKind == "snapshot" {
if r.SourceUUID == snapshot.UUID { if r.SourceUUID == snapshot.UUID {
result = append(result, r) result = append(result, r)
} }
@@ -1023,7 +952,7 @@ func (collection *PublishedRepoCollection) BySnapshot(snapshot *Snapshot) []*Pub
func (collection *PublishedRepoCollection) ByLocalRepo(repo *LocalRepo) []*PublishedRepo { func (collection *PublishedRepoCollection) ByLocalRepo(repo *LocalRepo) []*PublishedRepo {
var result []*PublishedRepo var result []*PublishedRepo
for _, r := range collection.list { for _, r := range collection.list {
if r.SourceKind == SourceLocalRepo { if r.SourceKind == "local" {
if r.SourceUUID == repo.UUID { if r.SourceUUID == repo.UUID {
result = append(result, r) result = append(result, r)
} }
@@ -1140,7 +1069,7 @@ func (collection *PublishedRepoCollection) CleanupPrefixComponentFiles(prefix st
// Remove removes published repository, cleaning up directories, files // Remove removes published repository, cleaning up directories, files
func (collection *PublishedRepoCollection) Remove(publishedStorageProvider aptly.PublishedStorageProvider, func (collection *PublishedRepoCollection) Remove(publishedStorageProvider aptly.PublishedStorageProvider,
storage, prefix, distribution string, collectionFactory *CollectionFactory, progress aptly.Progress, storage, prefix, distribution string, collectionFactory *CollectionFactory, progress aptly.Progress,
force, skipCleanup bool) error { force bool) error {
repo, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution) repo, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
if err != nil { if err != nil {
return err return err
@@ -1177,7 +1106,7 @@ func (collection *PublishedRepoCollection) Remove(publishedStorageProvider aptly
collection.list[len(collection.list)-1], collection.list[repoPosition], collection.list = collection.list[len(collection.list)-1], collection.list[repoPosition], collection.list =
nil, collection.list[len(collection.list)-1], collection.list[:len(collection.list)-1] nil, collection.list[len(collection.list)-1], collection.list[:len(collection.list)-1]
if !skipCleanup && len(cleanComponents) > 0 { if len(cleanComponents) > 0 {
err = collection.CleanupPrefixComponentFiles(repo.Prefix, cleanComponents, err = collection.CleanupPrefixComponentFiles(repo.Prefix, cleanComponents,
publishedStorageProvider.GetPublishedStorage(storage), collectionFactory, progress) publishedStorageProvider.GetPublishedStorage(storage), collectionFactory, progress)
if err != nil { if err != nil {
+29 -77
View File
@@ -8,9 +8,9 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/aptly-dev/aptly/aptly" "github.com/smira/aptly/aptly"
"github.com/aptly-dev/aptly/database" "github.com/smira/aptly/database"
"github.com/aptly-dev/aptly/files" "github.com/smira/aptly/files"
"github.com/ugorji/go/codec" "github.com/ugorji/go/codec"
. "gopkg.in/check.v1" . "gopkg.in/check.v1"
@@ -74,7 +74,6 @@ type PublishedRepoSuite struct {
provider *FakeStorageProvider provider *FakeStorageProvider
publishedStorage, publishedStorage2 *files.PublishedStorage publishedStorage, publishedStorage2 *files.PublishedStorage
packagePool aptly.PackagePool packagePool aptly.PackagePool
cs aptly.ChecksumStorage
localRepo *LocalRepo localRepo *LocalRepo
snapshot, snapshot2 *Snapshot snapshot, snapshot2 *Snapshot
db database.Storage db database.Storage
@@ -87,31 +86,17 @@ var _ = Suite(&PublishedRepoSuite{})
func (s *PublishedRepoSuite) SetUpTest(c *C) { func (s *PublishedRepoSuite) SetUpTest(c *C) {
s.SetUpPackages() s.SetUpPackages()
s.db, _ = database.NewOpenDB(c.MkDir()) s.db, _ = database.OpenDB(c.MkDir())
s.factory = NewCollectionFactory(s.db) s.factory = NewCollectionFactory(s.db)
s.root = c.MkDir() s.root = c.MkDir()
s.publishedStorage = files.NewPublishedStorage(s.root, "", "") s.publishedStorage = files.NewPublishedStorage(s.root)
s.root2 = c.MkDir() s.root2 = c.MkDir()
s.publishedStorage2 = files.NewPublishedStorage(s.root2, "", "") s.publishedStorage2 = files.NewPublishedStorage(s.root2)
s.provider = &FakeStorageProvider{map[string]aptly.PublishedStorage{ s.provider = &FakeStorageProvider{map[string]aptly.PublishedStorage{
"": s.publishedStorage, "": s.publishedStorage,
"files:other": s.publishedStorage2}} "files:other": s.publishedStorage2}}
s.packagePool = files.NewPackagePool(s.root, false) s.packagePool = files.NewPackagePool(s.root)
s.cs = files.NewMockChecksumStorage()
tmpFilepath := filepath.Join(c.MkDir(), "file")
c.Assert(ioutil.WriteFile(tmpFilepath, nil, 0777), IsNil)
var err error
s.p1.Files()[0].PoolPath, err = s.packagePool.Import(tmpFilepath, s.p1.Files()[0].Filename, &s.p1.Files()[0].Checksums, false, s.cs)
c.Assert(err, IsNil)
s.p1.UpdateFiles(s.p1.Files())
s.p2.UpdateFiles(s.p1.Files())
s.p3.UpdateFiles(s.p1.Files())
s.reflist = NewPackageRefListFromPackageList(s.list)
repo, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{}, false, false) repo, _ := NewRemoteRepo("yandex", "http://mirror.yandex.ru/debian/", "squeeze", []string{"main"}, []string{}, false, false)
repo.packageRefs = s.reflist repo.packageRefs = s.reflist
@@ -146,6 +131,12 @@ func (s *PublishedRepoSuite) SetUpTest(c *C) {
s.repo5, _ = NewPublishedRepo("files:other", "ppa", "maverick", []string{"source"}, []string{"main"}, []interface{}{s.localRepo}, s.factory) s.repo5, _ = NewPublishedRepo("files:other", "ppa", "maverick", []string{"source"}, []string{"main"}, []interface{}{s.localRepo}, s.factory)
s.repo5.SkipContents = true s.repo5.SkipContents = true
poolPath, _ := s.packagePool.Path(s.p1.Files()[0].Filename, s.p1.Files()[0].Checksums.MD5)
err := os.MkdirAll(filepath.Dir(poolPath), 0755)
f, err := os.Create(poolPath)
c.Assert(err, IsNil)
f.Close()
} }
func (s *PublishedRepoSuite) TearDownTest(c *C) { func (s *PublishedRepoSuite) TearDownTest(c *C) {
@@ -277,7 +268,7 @@ func (s *PublishedRepoSuite) TestDistributionComponentGuessing(c *C) {
c.Check(repo.Distribution, Equals, "squeeze") c.Check(repo.Distribution, Equals, "squeeze")
c.Check(repo.Components(), DeepEquals, []string{"main"}) c.Check(repo.Components(), DeepEquals, []string{"main"})
_, err = NewPublishedRepo("", "ppa", "", nil, []string{"main"}, []interface{}{s.localRepo}, s.factory) repo, err = NewPublishedRepo("", "ppa", "", nil, []string{"main"}, []interface{}{s.localRepo}, s.factory)
c.Check(err, ErrorMatches, "unable to guess distribution name, please specify explicitly") c.Check(err, ErrorMatches, "unable to guess distribution name, please specify explicitly")
s.localRepo.DefaultDistribution = "precise" s.localRepo.DefaultDistribution = "precise"
@@ -301,7 +292,7 @@ func (s *PublishedRepoSuite) TestDistributionComponentGuessing(c *C) {
c.Check(repo.Distribution, Equals, "squeeze") c.Check(repo.Distribution, Equals, "squeeze")
c.Check(repo.Components(), DeepEquals, []string{"contrib", "main"}) c.Check(repo.Components(), DeepEquals, []string{"contrib", "main"})
_, err = NewPublishedRepo("", "ppa", "", nil, []string{"", ""}, []interface{}{s.snapshot, s.snapshot2}, s.factory) repo, err = NewPublishedRepo("", "ppa", "", nil, []string{"", ""}, []interface{}{s.snapshot, s.snapshot2}, s.factory)
c.Check(err, ErrorMatches, "duplicate component name: main") c.Check(err, ErrorMatches, "duplicate component name: main")
} }
@@ -449,7 +440,7 @@ type PublishedRepoCollectionSuite struct {
var _ = Suite(&PublishedRepoCollectionSuite{}) var _ = Suite(&PublishedRepoCollectionSuite{})
func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) { func (s *PublishedRepoCollectionSuite) SetUpTest(c *C) {
s.db, _ = database.NewOpenDB(c.MkDir()) s.db, _ = database.OpenDB(c.MkDir())
s.factory = NewCollectionFactory(s.db) s.factory = NewCollectionFactory(s.db)
s.snapshotCollection = s.factory.SnapshotCollection() s.snapshotCollection = s.factory.SnapshotCollection()
@@ -477,7 +468,7 @@ func (s *PublishedRepoCollectionSuite) TearDownTest(c *C) {
} }
func (s *PublishedRepoCollectionSuite) TestAddByStoragePrefixDistribution(c *C) { func (s *PublishedRepoCollectionSuite) TestAddByStoragePrefixDistribution(c *C) {
_, err := s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda") r, err := s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
c.Assert(err, ErrorMatches, "*.not found") c.Assert(err, ErrorMatches, "*.not found")
c.Assert(s.collection.Add(s.repo1), IsNil) c.Assert(s.collection.Add(s.repo1), IsNil)
@@ -489,7 +480,7 @@ func (s *PublishedRepoCollectionSuite) TestAddByStoragePrefixDistribution(c *C)
c.Assert(s.collection.Add(s.repo4), IsNil) c.Assert(s.collection.Add(s.repo4), IsNil)
c.Assert(s.collection.Add(s.repo5), IsNil) c.Assert(s.collection.Add(s.repo5), IsNil)
r, err := s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda") r, err = s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
c.Assert(err, IsNil) c.Assert(err, IsNil)
err = s.collection.LoadComplete(r, s.factory) err = s.collection.LoadComplete(r, s.factory)
@@ -505,17 +496,16 @@ func (s *PublishedRepoCollectionSuite) TestAddByStoragePrefixDistribution(c *C)
c.Assert(r.String(), Equals, s.repo1.String()) c.Assert(r.String(), Equals, s.repo1.String())
r, err = s.collection.ByStoragePrefixDistribution("files:other", "ppa", "precise") r, err = s.collection.ByStoragePrefixDistribution("files:other", "ppa", "precise")
c.Assert(err, IsNil)
c.Check(r.String(), Equals, s.repo5.String()) c.Check(r.String(), Equals, s.repo5.String())
} }
func (s *PublishedRepoCollectionSuite) TestByUUID(c *C) { func (s *PublishedRepoCollectionSuite) TestByUUID(c *C) {
_, err := s.collection.ByUUID(s.repo1.UUID) r, err := s.collection.ByUUID(s.repo1.UUID)
c.Assert(err, ErrorMatches, "*.not found") c.Assert(err, ErrorMatches, "*.not found")
c.Assert(s.collection.Add(s.repo1), IsNil) c.Assert(s.collection.Add(s.repo1), IsNil)
r, err := s.collection.ByUUID(s.repo1.UUID) r, err = s.collection.ByUUID(s.repo1.UUID)
c.Assert(err, IsNil) c.Assert(err, IsNil)
err = s.collection.LoadComplete(r, s.factory) err = s.collection.LoadComplete(r, s.factory)
@@ -562,7 +552,7 @@ func (s *PublishedRepoCollectionSuite) TestLoadPre0_6(c *C) {
Prefix: "ppa", Prefix: "ppa",
Distribution: "anaconda", Distribution: "anaconda",
Architectures: []string{"i386"}, Architectures: []string{"i386"},
SourceKind: SourceLocalRepo, SourceKind: "local",
Component: "contrib", Component: "contrib",
SourceUUID: s.localRepo.UUID, SourceUUID: s.localRepo.UUID,
} }
@@ -640,7 +630,7 @@ type PublishedRepoRemoveSuite struct {
var _ = Suite(&PublishedRepoRemoveSuite{}) var _ = Suite(&PublishedRepoRemoveSuite{})
func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) { func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) {
s.db, _ = database.NewOpenDB(c.MkDir()) s.db, _ = database.OpenDB(c.MkDir())
s.factory = NewCollectionFactory(s.db) s.factory = NewCollectionFactory(s.db)
s.snapshotCollection = s.factory.SnapshotCollection() s.snapshotCollection = s.factory.SnapshotCollection()
@@ -663,7 +653,7 @@ func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) {
s.collection.Add(s.repo5) s.collection.Add(s.repo5)
s.root = c.MkDir() s.root = c.MkDir()
s.publishedStorage = files.NewPublishedStorage(s.root, "", "") s.publishedStorage = files.NewPublishedStorage(s.root)
s.publishedStorage.MkDir("ppa/dists/anaconda") s.publishedStorage.MkDir("ppa/dists/anaconda")
s.publishedStorage.MkDir("ppa/dists/meduza") s.publishedStorage.MkDir("ppa/dists/meduza")
s.publishedStorage.MkDir("ppa/dists/osminog") s.publishedStorage.MkDir("ppa/dists/osminog")
@@ -673,7 +663,7 @@ func (s *PublishedRepoRemoveSuite) SetUpTest(c *C) {
s.publishedStorage.MkDir("pool/main") s.publishedStorage.MkDir("pool/main")
s.root2 = c.MkDir() s.root2 = c.MkDir()
s.publishedStorage2 = files.NewPublishedStorage(s.root2, "", "") s.publishedStorage2 = files.NewPublishedStorage(s.root2)
s.publishedStorage2.MkDir("ppa/dists/osminog") s.publishedStorage2.MkDir("ppa/dists/osminog")
s.publishedStorage2.MkDir("ppa/pool/contrib") s.publishedStorage2.MkDir("ppa/pool/contrib")
@@ -756,7 +746,7 @@ func (s *PublishedRepoRemoveSuite) TestRemoveFilesWithPrefixRoot(c *C) {
} }
func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2(c *C) { func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2(c *C) {
err := s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false, false) err := s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false)
c.Check(err, IsNil) c.Check(err, IsNil)
_, err = s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda") _, err = s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
@@ -776,48 +766,10 @@ func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2(c *C) {
c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists) c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists) c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
err = s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false, false) err = s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false)
c.Check(err, ErrorMatches, ".*not found") c.Check(err, ErrorMatches, ".*not found")
err = s.collection.Remove(s.provider, "", "ppa", "meduza", s.factory, nil, false, false) err = s.collection.Remove(s.provider, "", "ppa", "meduza", s.factory, nil, false)
c.Check(err, IsNil)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), Not(PathExists))
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), Not(PathExists))
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
}
func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2SkipCleanup(c *C) {
err := s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false, true)
c.Check(err, IsNil)
_, err = s.collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
c.Check(err, ErrorMatches, ".*not found")
collection := NewPublishedRepoCollection(s.db)
_, err = collection.ByStoragePrefixDistribution("", "ppa", "anaconda")
c.Check(err, ErrorMatches, ".*not found")
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/meduza"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/osminog"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/main"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/pool/contrib"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "dists/anaconda"), PathExists)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "pool/main"), PathExists)
c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/dists/osminog"), PathExists)
c.Check(filepath.Join(s.publishedStorage2.PublicPath(), "ppa/pool/contrib"), PathExists)
err = s.collection.Remove(s.provider, "", "ppa", "anaconda", s.factory, nil, false, true)
c.Check(err, ErrorMatches, ".*not found")
err = s.collection.Remove(s.provider, "", "ppa", "meduza", s.factory, nil, false, true)
c.Check(err, IsNil) c.Check(err, IsNil)
c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists)) c.Check(filepath.Join(s.publishedStorage.PublicPath(), "ppa/dists/anaconda"), Not(PathExists))
@@ -832,7 +784,7 @@ func (s *PublishedRepoRemoveSuite) TestRemoveRepo1and2SkipCleanup(c *C) {
} }
func (s *PublishedRepoRemoveSuite) TestRemoveRepo3(c *C) { func (s *PublishedRepoRemoveSuite) TestRemoveRepo3(c *C) {
err := s.collection.Remove(s.provider, "", ".", "anaconda", s.factory, nil, false, false) err := s.collection.Remove(s.provider, "", ".", "anaconda", s.factory, nil, false)
c.Check(err, IsNil) c.Check(err, IsNil)
_, err = s.collection.ByStoragePrefixDistribution("", ".", "anaconda") _, err = s.collection.ByStoragePrefixDistribution("", ".", "anaconda")
@@ -854,7 +806,7 @@ func (s *PublishedRepoRemoveSuite) TestRemoveRepo3(c *C) {
} }
func (s *PublishedRepoRemoveSuite) TestRemoveRepo5(c *C) { func (s *PublishedRepoRemoveSuite) TestRemoveRepo5(c *C) {
err := s.collection.Remove(s.provider, "files:other", "ppa", "osminog", s.factory, nil, false, false) err := s.collection.Remove(s.provider, "files:other", "ppa", "osminog", s.factory, nil, false)
c.Check(err, IsNil) c.Check(err, IsNil)
_, err = s.collection.ByStoragePrefixDistribution("files:other", "ppa", "osminog") _, err = s.collection.ByStoragePrefixDistribution("files:other", "ppa", "osminog")
+1 -1
View File
@@ -204,7 +204,7 @@ func (q *FieldQuery) Fast(list PackageCatalog) bool {
// String interface // String interface
func (q *FieldQuery) String() string { func (q *FieldQuery) String() string {
escape := func(val string) string { escape := func(val string) string {
if strings.ContainsAny(val, "()|,!{} \t\n") { if strings.IndexAny(val, "()|,!{} \t\n") != -1 {
return "'" + strings.Replace(strings.Replace(val, "\\", "\\\\", -1), "'", "\\'", -1) + "'" return "'" + strings.Replace(strings.Replace(val, "\\", "\\\\", -1), "'", "\\'", -1) + "'"
} }
return val return val

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