Compare commits
22 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e963618b8 | ||
|
|
8212f1bd45 | ||
|
|
dca3bbdea3 | ||
|
|
8ed7dfef6f | ||
|
|
631f5be02f | ||
|
|
4f4ea2a402 | ||
|
|
5a5bffebd1 | ||
|
|
8749bc0844 | ||
|
|
f3d0c63db2 | ||
|
|
93a846db31 | ||
|
|
686c25d50f | ||
|
|
ef6555f084 | ||
|
|
3c6652c101 | ||
|
|
43af1684c1 | ||
|
|
ed549155b3 | ||
|
|
39ae91c81c | ||
|
|
b6acb3cd8c | ||
|
|
a467a8a094 | ||
|
|
78227c3c06 | ||
|
|
e4e802d1f8 | ||
|
|
b24a60ba9f | ||
|
|
461b600068 |
17 changed files with 533 additions and 30 deletions
43
CHANGES.md
43
CHANGES.md
|
|
@ -1,6 +1,49 @@
|
||||||
Change log
|
Change log
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
1.3.0 RC2 (2015-06-09)
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Firstly, two important notes:
|
||||||
|
|
||||||
|
- **This release contains breaking changes, and you will need to either remove or migrate your existing containers before running your app** - see the [upgrading section of the install docs](https://github.com/docker/compose/blob/1.3.0rc1/docs/install.md#upgrading) for details.
|
||||||
|
|
||||||
|
- Compose now requires Docker 1.6.0 or later.
|
||||||
|
|
||||||
|
We've done a lot of work in this release to remove hacks and make Compose more stable:
|
||||||
|
|
||||||
|
- Compose now uses Docker labels, rather than container names, to keep track of containers. This is both cleaner and more performant.
|
||||||
|
|
||||||
|
- Compose no longer uses "intermediate containers" when recreating containers for a service. This makes `docker-compose up` less complex and more resilient to failure.
|
||||||
|
|
||||||
|
There are some new features:
|
||||||
|
|
||||||
|
- `docker-compose up` has an **experimental** new behaviour: it will only recreate containers for services whose configuration has changed in `docker-compose.yml`. This will eventually become the default, but for now you can take it for a spin:
|
||||||
|
|
||||||
|
$ docker-compose up --x-smart-recreate
|
||||||
|
|
||||||
|
- When invoked in a subdirectory of a project, `docker-compose` will now climb up through parent directories until it finds a `docker-compose.yml`.
|
||||||
|
|
||||||
|
Several new configuration keys have been added to `docker-compose.yml`:
|
||||||
|
|
||||||
|
- `dockerfile`, like `docker build --file`, lets you specify an alternate Dockerfile to use with `build`.
|
||||||
|
- `labels`, like `docker run --labels`, lets you add custom metadata to containers.
|
||||||
|
- `extra_hosts`, like `docker run --add-host`, lets you add entries to a container's `/etc/hosts` file.
|
||||||
|
- `pid: host`, like `docker run --pid=host`, lets you reuse the same PID namespace as the host machine.
|
||||||
|
- `cpuset`, like `docker run --cpuset-cpus`, lets you specify which CPUs to allow execution in.
|
||||||
|
- `read_only`, like `docker run --read-only`, lets you mount a container's filesystem as read-only.
|
||||||
|
- `security_opt`, like `docker run --security-opt`, lets you specify [security options](https://docs.docker.com/reference/run/#security-configuration).
|
||||||
|
- `log_driver`, like `docker run --log-driver`, lets you specify a [log driver](https://docs.docker.com/reference/run/#logging-drivers-log-driver).
|
||||||
|
|
||||||
|
Many bugs have been fixed, including the following:
|
||||||
|
|
||||||
|
- The output of `docker-compose run` was sometimes truncated, especially when running under Jenkins.
|
||||||
|
- A service's volumes would sometimes not update after volume configuration was changed in `docker-compose.yml`.
|
||||||
|
- Authenticating against third-party registries would sometimes fail.
|
||||||
|
- `docker-compose run --rm` would fail to remove the container if the service had a `restart` policy in place.
|
||||||
|
|
||||||
|
Thanks @ahromis, @albers, @aleksandr-vin, @antoineco, @ccverak, @chernjie, @dnephin, @josephpage, @KyleJamesWalker, @lsowen, @mchasal, @sdake, @sherter, @stephenlawrence, @turtlemonvh, @vdemeester, @xuxinkun and @zwily!
|
||||||
|
|
||||||
1.2.0 (2015-04-16)
|
1.2.0 (2015-04-16)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,23 +53,26 @@ you can specify a test directory, file, module, class or method:
|
||||||
|
|
||||||
## Building binaries
|
## Building binaries
|
||||||
|
|
||||||
Linux:
|
`script/build-linux` will build the Linux binary inside a Docker container:
|
||||||
|
|
||||||
$ script/build-linux
|
$ script/build-linux
|
||||||
|
|
||||||
OS X:
|
`script/build-osx` will build the Mac OS X binary inside a virtualenv:
|
||||||
|
|
||||||
$ script/build-osx
|
$ script/build-osx
|
||||||
|
|
||||||
Note that this only works on Mountain Lion, not Mavericks, due to a
|
For official releases, you should build inside a Mountain Lion VM for proper
|
||||||
[bug in PyInstaller](http://www.pyinstaller.org/ticket/807).
|
compatibility. Run the this script first to prepare the environment before
|
||||||
|
building - it will use Homebrew to make sure Python is installed and
|
||||||
|
up-to-date.
|
||||||
|
|
||||||
|
$ script/prepare-osx
|
||||||
|
|
||||||
## Release process
|
## Release process
|
||||||
|
|
||||||
1. Open pull request that:
|
1. Open pull request that:
|
||||||
- Updates the version in `compose/__init__.py`
|
- Updates the version in `compose/__init__.py`
|
||||||
- Updates the binary URL in `docs/install.md`
|
- Updates the binary URL in `docs/install.md`
|
||||||
- Updates the script URL in `docs/completion.md`
|
|
||||||
- Adds release notes to `CHANGES.md`
|
- Adds release notes to `CHANGES.md`
|
||||||
2. Create unpublished GitHub release with release notes
|
2. Create unpublished GitHub release with release notes
|
||||||
3. Build Linux version on any Docker host with `script/build-linux` and attach
|
3. Build Linux version on any Docker host with `script/build-linux` and attach
|
||||||
|
|
|
||||||
39
Dockerfile
39
Dockerfile
|
|
@ -3,9 +3,11 @@ FROM debian:wheezy
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
apt-get update -qq; \
|
apt-get update -qq; \
|
||||||
apt-get install -y \
|
apt-get install -y \
|
||||||
python \
|
gcc \
|
||||||
python-pip \
|
make \
|
||||||
python-dev \
|
zlib1g \
|
||||||
|
zlib1g-dev \
|
||||||
|
libssl-dev \
|
||||||
git \
|
git \
|
||||||
apt-transport-https \
|
apt-transport-https \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
|
|
@ -15,6 +17,37 @@ RUN set -ex; \
|
||||||
; \
|
; \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Build Python 2.7.9 from source
|
||||||
|
RUN set -ex; \
|
||||||
|
curl -LO https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz; \
|
||||||
|
tar -xzf Python-2.7.9.tgz; \
|
||||||
|
cd Python-2.7.9; \
|
||||||
|
./configure --enable-shared; \
|
||||||
|
make; \
|
||||||
|
make install; \
|
||||||
|
cd ..; \
|
||||||
|
rm -rf /Python-2.7.9; \
|
||||||
|
rm Python-2.7.9.tgz
|
||||||
|
|
||||||
|
# Make libpython findable
|
||||||
|
ENV LD_LIBRARY_PATH /usr/local/lib
|
||||||
|
|
||||||
|
# Install setuptools
|
||||||
|
RUN set -ex; \
|
||||||
|
curl -LO https://bootstrap.pypa.io/ez_setup.py; \
|
||||||
|
python ez_setup.py; \
|
||||||
|
rm ez_setup.py
|
||||||
|
|
||||||
|
# Install pip
|
||||||
|
RUN set -ex; \
|
||||||
|
curl -LO https://pypi.python.org/packages/source/p/pip/pip-7.0.1.tar.gz; \
|
||||||
|
tar -xzf pip-7.0.1.tar.gz; \
|
||||||
|
cd pip-7.0.1; \
|
||||||
|
python setup.py install; \
|
||||||
|
cd ..; \
|
||||||
|
rm -rf pip-7.0.1; \
|
||||||
|
rm pip-7.0.1.tar.gz
|
||||||
|
|
||||||
ENV ALL_DOCKER_VERSIONS 1.6.0
|
ENV ALL_DOCKER_VERSIONS 1.6.0
|
||||||
|
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__version__ = '1.3.0dev'
|
__version__ = '1.3.0rc2'
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import sys
|
||||||
from docker.errors import APIError
|
from docker.errors import APIError
|
||||||
import dockerpty
|
import dockerpty
|
||||||
|
|
||||||
from .. import __version__
|
|
||||||
from .. import legacy
|
from .. import legacy
|
||||||
from ..project import NoSuchService, ConfigurationError
|
from ..project import NoSuchService, ConfigurationError
|
||||||
from ..service import BuildError, CannotBeScaledError, NeedsBuildError
|
from ..service import BuildError, CannotBeScaledError, NeedsBuildError
|
||||||
|
|
@ -20,7 +19,7 @@ from .docopt_command import NoSuchCommand
|
||||||
from .errors import UserError
|
from .errors import UserError
|
||||||
from .formatter import Formatter
|
from .formatter import Formatter
|
||||||
from .log_printer import LogPrinter
|
from .log_printer import LogPrinter
|
||||||
from .utils import yesno
|
from .utils import get_version_info, yesno
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -104,7 +103,7 @@ class TopLevelCommand(Command):
|
||||||
"""
|
"""
|
||||||
def docopt_options(self):
|
def docopt_options(self):
|
||||||
options = super(TopLevelCommand, self).docopt_options()
|
options = super(TopLevelCommand, self).docopt_options()
|
||||||
options['version'] = "docker-compose %s" % __version__
|
options['version'] = get_version_info()
|
||||||
return options
|
return options
|
||||||
|
|
||||||
def build(self, project, options):
|
def build(self, project, options):
|
||||||
|
|
@ -336,6 +335,7 @@ class TopLevelCommand(Command):
|
||||||
container_options['ports'] = []
|
container_options['ports'] = []
|
||||||
|
|
||||||
container = service.create_container(
|
container = service.create_container(
|
||||||
|
quiet=True,
|
||||||
one_off=True,
|
one_off=True,
|
||||||
insecure_registry=insecure_registry,
|
insecure_registry=insecure_registry,
|
||||||
**container_options
|
**container_options
|
||||||
|
|
@ -348,7 +348,6 @@ class TopLevelCommand(Command):
|
||||||
dockerpty.start(project.client, container.id, interactive=not options['-T'])
|
dockerpty.start(project.client, container.id, interactive=not options['-T'])
|
||||||
exit_code = container.wait()
|
exit_code = container.wait()
|
||||||
if options['--rm']:
|
if options['--rm']:
|
||||||
log.info("Removing %s..." % container.name)
|
|
||||||
project.client.remove_container(container.id)
|
project.client.remove_container(container.id)
|
||||||
sys.exit(exit_code)
|
sys.exit(exit_code)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ import datetime
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import platform
|
import platform
|
||||||
|
import ssl
|
||||||
|
|
||||||
|
from .. import __version__
|
||||||
|
|
||||||
|
|
||||||
def yesno(prompt, default=None):
|
def yesno(prompt, default=None):
|
||||||
|
|
@ -120,3 +123,11 @@ def is_mac():
|
||||||
|
|
||||||
def is_ubuntu():
|
def is_ubuntu():
|
||||||
return platform.system() == 'Linux' and platform.linux_distribution()[0] == 'Ubuntu'
|
return platform.system() == 'Linux' and platform.linux_distribution()[0] == 'Ubuntu'
|
||||||
|
|
||||||
|
|
||||||
|
def get_version_info():
|
||||||
|
return '\n'.join([
|
||||||
|
'docker-compose version: %s' % __version__,
|
||||||
|
"%s version: %s" % (platform.python_implementation(), platform.python_version()),
|
||||||
|
"OpenSSL version: %s" % ssl.OPENSSL_VERSION,
|
||||||
|
])
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,9 @@ def print_output_event(event, stream, is_terminal):
|
||||||
stream.write("%s %s%s" % (status, event['progress'], terminator))
|
stream.write("%s %s%s" % (status, event['progress'], terminator))
|
||||||
elif 'progressDetail' in event:
|
elif 'progressDetail' in event:
|
||||||
detail = event['progressDetail']
|
detail = event['progressDetail']
|
||||||
if 'current' in detail:
|
total = detail.get('total')
|
||||||
percentage = float(detail['current']) / float(detail['total']) * 100
|
if 'current' in detail and total:
|
||||||
|
percentage = float(detail['current']) / float(total) * 100
|
||||||
stream.write('%s (%.1f%%)%s' % (status, percentage, terminator))
|
stream.write('%s (%.1f%%)%s' % (status, percentage, terminator))
|
||||||
else:
|
else:
|
||||||
stream.write('%s%s' % (status, terminator))
|
stream.write('%s%s' % (status, terminator))
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,7 @@ class Service(object):
|
||||||
do_build=True,
|
do_build=True,
|
||||||
previous_container=None,
|
previous_container=None,
|
||||||
number=None,
|
number=None,
|
||||||
|
quiet=False,
|
||||||
**override_options):
|
**override_options):
|
||||||
"""
|
"""
|
||||||
Create a container for this service. If the image doesn't exist, attempt to pull
|
Create a container for this service. If the image doesn't exist, attempt to pull
|
||||||
|
|
@ -216,7 +217,7 @@ class Service(object):
|
||||||
previous_container=previous_container,
|
previous_container=previous_container,
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'name' in container_options:
|
if 'name' in container_options and not quiet:
|
||||||
log.info("Creating %s..." % container_options['name'])
|
log.info("Creating %s..." % container_options['name'])
|
||||||
|
|
||||||
return Container.create(self.client, **container_options)
|
return Container.create(self.client, **container_options)
|
||||||
|
|
@ -378,6 +379,7 @@ class Service(object):
|
||||||
do_build=False,
|
do_build=False,
|
||||||
previous_container=container,
|
previous_container=container,
|
||||||
number=container.labels.get(LABEL_CONTAINER_NUMBER),
|
number=container.labels.get(LABEL_CONTAINER_NUMBER),
|
||||||
|
quiet=True,
|
||||||
)
|
)
|
||||||
self.start_container(new_container)
|
self.start_container(new_container)
|
||||||
container.remove()
|
container.remove()
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ _docker-compose_docker-compose() {
|
||||||
|
|
||||||
case "$cur" in
|
case "$cur" in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W "--help -h --verbose --version --file -f --project-name -p" -- "$cur" ) )
|
COMPREPLY=( $( compgen -W "--help -h --verbose --version -v --file -f --project-name -p" -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
COMPREPLY=( $( compgen -W "${commands[*]}" -- "$cur" ) )
|
COMPREPLY=( $( compgen -W "${commands[*]}" -- "$cur" ) )
|
||||||
|
|
@ -293,7 +293,7 @@ _docker-compose_up() {
|
||||||
|
|
||||||
case "$cur" in
|
case "$cur" in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W "--allow-insecure-ssl -d --no-build --no-color --no-deps --no-recreate -t --timeout" -- "$cur" ) )
|
COMPREPLY=( $( compgen -W "--allow-insecure-ssl -d --no-build --no-color --no-deps --no-recreate -t --timeout --x-smart-recreate" -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
__docker-compose_services_all
|
__docker-compose_services_all
|
||||||
|
|
|
||||||
304
contrib/completion/zsh/_docker-compose
Normal file
304
contrib/completion/zsh/_docker-compose
Normal file
|
|
@ -0,0 +1,304 @@
|
||||||
|
#compdef docker-compose
|
||||||
|
|
||||||
|
# Description
|
||||||
|
# -----------
|
||||||
|
# zsh completion for docker-compose
|
||||||
|
# https://github.com/sdurrheimer/docker-compose-zsh-completion
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Version
|
||||||
|
# -------
|
||||||
|
# 0.1.0
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Authors
|
||||||
|
# -------
|
||||||
|
# * Steve Durrheimer <s.durrheimer@gmail.com>
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Inspiration
|
||||||
|
# -----------
|
||||||
|
# * @albers docker-compose bash completion script
|
||||||
|
# * @felixr docker zsh completion script : https://github.com/felixr/docker-zsh-completion
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# For compatibility reasons, Compose and therefore its completion supports several
|
||||||
|
# stack compositon files as listed here, in descending priority.
|
||||||
|
# Support for these filenames might be dropped in some future version.
|
||||||
|
__docker-compose_compose_file() {
|
||||||
|
local file
|
||||||
|
for file in docker-compose.y{,a}ml fig.y{,a}ml ; do
|
||||||
|
[ -e $file ] && {
|
||||||
|
echo $file
|
||||||
|
return
|
||||||
|
}
|
||||||
|
done
|
||||||
|
echo docker-compose.yml
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extracts all service names from docker-compose.yml.
|
||||||
|
___docker-compose_all_services_in_compose_file() {
|
||||||
|
local already_selected
|
||||||
|
local -a services
|
||||||
|
already_selected=$(echo ${words[@]} | tr " " "|")
|
||||||
|
awk -F: '/^[a-zA-Z0-9]/{print $1}' "${compose_file:-$(__docker-compose_compose_file)}" 2>/dev/null | grep -Ev "$already_selected"
|
||||||
|
}
|
||||||
|
|
||||||
|
# All services, even those without an existing container
|
||||||
|
__docker-compose_services_all() {
|
||||||
|
services=$(___docker-compose_all_services_in_compose_file)
|
||||||
|
_alternative "args:services:($services)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# All services that have an entry with the given key in their docker-compose.yml section
|
||||||
|
___docker-compose_services_with_key() {
|
||||||
|
local already_selected
|
||||||
|
local -a buildable
|
||||||
|
already_selected=$(echo ${words[@]} | tr " " "|")
|
||||||
|
# flatten sections to one line, then filter lines containing the key and return section name.
|
||||||
|
awk '/^[a-zA-Z0-9]/{printf "\n"};{printf $0;next;}' "${compose_file:-$(__docker-compose_compose_file)}" 2>/dev/null | awk -F: -v key=": +$1:" '$0 ~ key {print $1}' 2>/dev/null | grep -Ev "$already_selected"
|
||||||
|
}
|
||||||
|
|
||||||
|
# All services that are defined by a Dockerfile reference
|
||||||
|
__docker-compose_services_from_build() {
|
||||||
|
buildable=$(___docker-compose_services_with_key build)
|
||||||
|
_alternative "args:buildable services:($buildable)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# All services that are defined by an image
|
||||||
|
__docker-compose_services_from_image() {
|
||||||
|
pullable=$(___docker-compose_services_with_key image)
|
||||||
|
_alternative "args:pullable services:($pullable)"
|
||||||
|
}
|
||||||
|
|
||||||
|
__docker-compose_get_services() {
|
||||||
|
local kind expl
|
||||||
|
declare -a running stopped lines args services
|
||||||
|
|
||||||
|
docker_status=$(docker ps > /dev/null 2>&1)
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
_message "Error! Docker is not running."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
kind=$1
|
||||||
|
shift
|
||||||
|
[[ $kind = (stopped|all) ]] && args=($args -a)
|
||||||
|
|
||||||
|
lines=(${(f)"$(_call_program commands docker ps ${args})"})
|
||||||
|
services=(${(f)"$(_call_program commands docker-compose 2>/dev/null ${compose_file:+-f $compose_file} ${compose_project:+-p $compose_project} ps -q)"})
|
||||||
|
|
||||||
|
# Parse header line to find columns
|
||||||
|
local i=1 j=1 k header=${lines[1]}
|
||||||
|
declare -A begin end
|
||||||
|
while (( $j < ${#header} - 1 )) {
|
||||||
|
i=$(( $j + ${${header[$j,-1]}[(i)[^ ]]} - 1))
|
||||||
|
j=$(( $i + ${${header[$i,-1]}[(i) ]} - 1))
|
||||||
|
k=$(( $j + ${${header[$j,-1]}[(i)[^ ]]} - 2))
|
||||||
|
begin[${header[$i,$(($j-1))]}]=$i
|
||||||
|
end[${header[$i,$(($j-1))]}]=$k
|
||||||
|
}
|
||||||
|
lines=(${lines[2,-1]})
|
||||||
|
|
||||||
|
# Container ID
|
||||||
|
local line s name
|
||||||
|
local -a names
|
||||||
|
for line in $lines; do
|
||||||
|
if [[ $services == *"${line[${begin[CONTAINER ID]},${end[CONTAINER ID]}]%% ##}"* ]]; then
|
||||||
|
names=(${(ps:,:)${${line[${begin[NAMES]},-1]}%% *}})
|
||||||
|
for name in $names; do
|
||||||
|
s="${${name%_*}#*_}:${(l:15:: :::)${${line[${begin[CREATED]},${end[CREATED]}]/ ago/}%% ##}}"
|
||||||
|
s="$s, ${line[${begin[CONTAINER ID]},${end[CONTAINER ID]}]%% ##}"
|
||||||
|
s="$s, ${${${line[$begin[IMAGE],$end[IMAGE]]}/:/\\:}%% ##}"
|
||||||
|
if [[ ${line[${begin[STATUS]},${end[STATUS]}]} = Exit* ]]; then
|
||||||
|
stopped=($stopped $s)
|
||||||
|
else
|
||||||
|
running=($running $s)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ $kind = (running|all) ]] && _describe -t services-running "running services" running
|
||||||
|
[[ $kind = (stopped|all) ]] && _describe -t services-stopped "stopped services" stopped
|
||||||
|
}
|
||||||
|
|
||||||
|
__docker-compose_stoppedservices() {
|
||||||
|
__docker-compose_get_services stopped "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
__docker-compose_runningservices() {
|
||||||
|
__docker-compose_get_services running "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
__docker-compose_services () {
|
||||||
|
__docker-compose_get_services all "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
__docker-compose_caching_policy() {
|
||||||
|
oldp=( "$1"(Nmh+1) ) # 1 hour
|
||||||
|
(( $#oldp ))
|
||||||
|
}
|
||||||
|
|
||||||
|
__docker-compose_commands () {
|
||||||
|
local cache_policy
|
||||||
|
|
||||||
|
zstyle -s ":completion:${curcontext}:" cache-policy cache_policy
|
||||||
|
if [[ -z "$cache_policy" ]]; then
|
||||||
|
zstyle ":completion:${curcontext}:" cache-policy __docker-compose_caching_policy
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ( [[ ${+_docker_compose_subcommands} -eq 0 ]] || _cache_invalid docker_compose_subcommands) \
|
||||||
|
&& ! _retrieve_cache docker_compose_subcommands;
|
||||||
|
then
|
||||||
|
local -a lines
|
||||||
|
lines=(${(f)"$(_call_program commands docker-compose 2>&1)"})
|
||||||
|
_docker_compose_subcommands=(${${${lines[$((${lines[(i)Commands:]} + 1)),${lines[(I) *]}]}## #}/ ##/:})
|
||||||
|
_store_cache docker_compose_subcommands _docker_compose_subcommands
|
||||||
|
fi
|
||||||
|
_describe -t docker-compose-commands "docker-compose command" _docker_compose_subcommands
|
||||||
|
}
|
||||||
|
|
||||||
|
__docker-compose_subcommand () {
|
||||||
|
local -a _command_args
|
||||||
|
integer ret=1
|
||||||
|
case "$words[1]" in
|
||||||
|
(build)
|
||||||
|
_arguments \
|
||||||
|
'--no-cache[Do not use cache when building the image]' \
|
||||||
|
'*:services:__docker-compose_services_from_build' && ret=0
|
||||||
|
;;
|
||||||
|
(help)
|
||||||
|
_arguments ':subcommand:__docker-compose_commands' && ret=0
|
||||||
|
;;
|
||||||
|
(kill)
|
||||||
|
_arguments \
|
||||||
|
'-s[SIGNAL to send to the container. Default signal is SIGKILL.]:signal:_signals' \
|
||||||
|
'*:running services:__docker-compose_runningservices' && ret=0
|
||||||
|
;;
|
||||||
|
(logs)
|
||||||
|
_arguments \
|
||||||
|
'--no-color[Produce monochrome output.]' \
|
||||||
|
'*:services:__docker-compose_services_all' && ret=0
|
||||||
|
;;
|
||||||
|
(migrate-to-labels)
|
||||||
|
_arguments \
|
||||||
|
'(-):Recreate containers to add labels' && ret=0
|
||||||
|
;;
|
||||||
|
(port)
|
||||||
|
_arguments \
|
||||||
|
'--protocol=-[tcp or udap (defaults to tcp)]:protocol:(tcp udp)' \
|
||||||
|
'--index=-[index of the container if there are mutiple instances of a service (defaults to 1)]:index: ' \
|
||||||
|
'1:running services:__docker-compose_runningservices' \
|
||||||
|
'2:port:_ports' && ret=0
|
||||||
|
;;
|
||||||
|
(ps)
|
||||||
|
_arguments \
|
||||||
|
'-q[Only display IDs]' \
|
||||||
|
'*:services:__docker-compose_services_all' && ret=0
|
||||||
|
;;
|
||||||
|
(pull)
|
||||||
|
_arguments \
|
||||||
|
'--allow-insecure-ssl[Allow insecure connections to the docker registry]' \
|
||||||
|
'*:services:__docker-compose_services_from_image' && ret=0
|
||||||
|
;;
|
||||||
|
(rm)
|
||||||
|
_arguments \
|
||||||
|
'(-f --force)'{-f,--force}"[Don't ask to confirm removal]" \
|
||||||
|
'-v[Remove volumes associated with containers]' \
|
||||||
|
'*:stopped services:__docker-compose_stoppedservices' && ret=0
|
||||||
|
;;
|
||||||
|
(run)
|
||||||
|
_arguments \
|
||||||
|
'--allow-insecure-ssl[Allow insecure connections to the docker registry]' \
|
||||||
|
'-d[Detached mode: Run container in the background, print new container name.]' \
|
||||||
|
'--entrypoint[Overwrite the entrypoint of the image.]:entry point: ' \
|
||||||
|
'*-e[KEY=VAL Set an environment variable (can be used multiple times)]:environment variable KEY=VAL: ' \
|
||||||
|
'(-u --user)'{-u,--user=-}'[Run as specified username or uid]:username or uid:_users' \
|
||||||
|
"--no-deps[Don't start linked services.]" \
|
||||||
|
'--rm[Remove container after run. Ignored in detached mode.]' \
|
||||||
|
"--service-ports[Run command with the service's ports enabled and mapped to the host.]" \
|
||||||
|
'-T[Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY.]' \
|
||||||
|
'(-):services:__docker-compose_services' \
|
||||||
|
'(-):command: _command_names -e' \
|
||||||
|
'*::arguments: _normal' && ret=0
|
||||||
|
;;
|
||||||
|
(scale)
|
||||||
|
_arguments '*:running services:__docker-compose_runningservices' && ret=0
|
||||||
|
;;
|
||||||
|
(start)
|
||||||
|
_arguments '*:stopped services:__docker-compose_stoppedservices' && ret=0
|
||||||
|
;;
|
||||||
|
(stop|restart)
|
||||||
|
_arguments \
|
||||||
|
'(-t --timeout)'{-t,--timeout}"[Specify a shutdown timeout in seconds. (default: 10)]:seconds: " \
|
||||||
|
'*:running services:__docker-compose_runningservices' && ret=0
|
||||||
|
;;
|
||||||
|
(up)
|
||||||
|
_arguments \
|
||||||
|
'--allow-insecure-ssl[Allow insecure connections to the docker registry]' \
|
||||||
|
'-d[Detached mode: Run containers in the background, print new container names.]' \
|
||||||
|
'--no-color[Produce monochrome output.]' \
|
||||||
|
"--no-deps[Don't start linked services.]" \
|
||||||
|
"--no-recreate[If containers already exist, don't recreate them.]" \
|
||||||
|
"--no-build[Don't build an image, even if it's missing]" \
|
||||||
|
'(-t --timeout)'{-t,--timeout}"[Specify a shutdown timeout in seconds. (default: 10)]:seconds: " \
|
||||||
|
"--x-smart-recreate[Only recreate containers whose configuration or image needs to be updated. (EXPERIMENTAL)]" \
|
||||||
|
'*:services:__docker-compose_services_all' && ret=0
|
||||||
|
;;
|
||||||
|
(*)
|
||||||
|
_message 'Unknown sub command'
|
||||||
|
esac
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
_docker-compose () {
|
||||||
|
# Support for subservices, which allows for `compdef _docker docker-shell=_docker_containers`.
|
||||||
|
# Based on /usr/share/zsh/functions/Completion/Unix/_git without support for `ret`.
|
||||||
|
if [[ $service != docker-compose ]]; then
|
||||||
|
_call_function - _$service
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local curcontext="$curcontext" state line ret=1
|
||||||
|
typeset -A opt_args
|
||||||
|
|
||||||
|
_arguments -C \
|
||||||
|
'(- :)'{-h,--help}'[Get help]' \
|
||||||
|
'--verbose[Show more output]' \
|
||||||
|
'(- :)'{-v,--version}'[Print version and exit]' \
|
||||||
|
'(-f --file)'{-f,--file}'[Specify an alternate docker-compose file (default: docker-compose.yml)]:file:_files -g "*.yml"' \
|
||||||
|
'(-p --project-name)'{-p,--project-name}'[Specify an alternate project name (default: directory name)]:project name:' \
|
||||||
|
'(-): :->command' \
|
||||||
|
'(-)*:: :->option-or-argument' && ret=0
|
||||||
|
|
||||||
|
local counter=1
|
||||||
|
#local compose_file compose_project
|
||||||
|
while [ $counter -lt ${#words[@]} ]; do
|
||||||
|
case "${words[$counter]}" in
|
||||||
|
-f|--file)
|
||||||
|
(( counter++ ))
|
||||||
|
compose_file="${words[$counter]}"
|
||||||
|
;;
|
||||||
|
-p|--project-name)
|
||||||
|
(( counter++ ))
|
||||||
|
compose_project="${words[$counter]}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
(( counter++ ))
|
||||||
|
done
|
||||||
|
|
||||||
|
case $state in
|
||||||
|
(command)
|
||||||
|
__docker-compose_commands && ret=0
|
||||||
|
;;
|
||||||
|
(option-or-argument)
|
||||||
|
curcontext=${curcontext%:*:*}:docker-compose-$words[1]:
|
||||||
|
__docker-compose_subcommand && ret=0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
_docker-compose "$@"
|
||||||
|
|
@ -3,23 +3,44 @@ layout: default
|
||||||
title: Command Completion
|
title: Command Completion
|
||||||
---
|
---
|
||||||
|
|
||||||
#Command Completion
|
# Command Completion
|
||||||
|
|
||||||
Compose comes with [command completion](http://en.wikipedia.org/wiki/Command-line_completion)
|
Compose comes with [command completion](http://en.wikipedia.org/wiki/Command-line_completion)
|
||||||
for the bash shell.
|
for the bash and zsh shell.
|
||||||
|
|
||||||
##Installing Command Completion
|
## Installing Command Completion
|
||||||
|
|
||||||
|
### Bash
|
||||||
|
|
||||||
Make sure bash completion is installed. If you use a current Linux in a non-minimal installation, bash completion should be available.
|
Make sure bash completion is installed. If you use a current Linux in a non-minimal installation, bash completion should be available.
|
||||||
On a Mac, install with `brew install bash-completion`
|
On a Mac, install with `brew install bash-completion`
|
||||||
|
|
||||||
Place the completion script in `/etc/bash_completion.d/` (`/usr/local/etc/bash_completion.d/` on a Mac), using e.g.
|
|
||||||
|
|
||||||
curl -L https://raw.githubusercontent.com/docker/compose/1.2.0/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose
|
Place the completion script in `/etc/bash_completion.d/` (`/usr/local/etc/bash_completion.d/` on a Mac), using e.g.
|
||||||
|
|
||||||
|
curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose --version | awk '{print $2}')/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose
|
||||||
|
|
||||||
Completion will be available upon next login.
|
Completion will be available upon next login.
|
||||||
|
|
||||||
##Available completions
|
### Zsh
|
||||||
|
|
||||||
|
Place the completion script in your `/path/to/zsh/completion`, using e.g. `~/.zsh/completion/`
|
||||||
|
|
||||||
|
mkdir -p ~/.zsh/completion
|
||||||
|
curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose --version | awk '{print $2}')/contrib/completion/zsh/_docker-compose > ~/.zsh/completion/_docker-compose
|
||||||
|
|
||||||
|
Include the directory in your `$fpath`, e.g. by adding in `~/.zshrc`
|
||||||
|
|
||||||
|
fpath=(~/.zsh/completion $fpath)
|
||||||
|
|
||||||
|
Make sure `compinit` is loaded or do it by adding in `~/.zshrc`
|
||||||
|
|
||||||
|
autoload -Uz compinit && compinit -i
|
||||||
|
|
||||||
|
Then reload your shell
|
||||||
|
|
||||||
|
exec $SHELL -l
|
||||||
|
|
||||||
|
## Available completions
|
||||||
|
|
||||||
Depending on what you typed on the command line so far, it will complete
|
Depending on what you typed on the command line so far, it will complete
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ First, install Docker version 1.6 or greater:
|
||||||
|
|
||||||
To install Compose, run the following commands:
|
To install Compose, run the following commands:
|
||||||
|
|
||||||
curl -L https://github.com/docker/compose/releases/download/1.2.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
|
curl -L https://github.com/docker/compose/releases/download/1.3.0rc2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
|
||||||
chmod +x /usr/local/bin/docker-compose
|
chmod +x /usr/local/bin/docker-compose
|
||||||
|
|
||||||
> Note: If you get a "Permission denied" error, your `/usr/local/bin` directory probably isn't writable and you'll need to install Compose as the superuser. Run `sudo -i`, then the two commands above, then `exit`.
|
> Note: If you get a "Permission denied" error, your `/usr/local/bin` directory probably isn't writable and you'll need to install Compose as the superuser. Run `sudo -i`, then the two commands above, then `exit`.
|
||||||
|
|
@ -36,6 +36,18 @@ Compose can also be installed as a Python package:
|
||||||
No further steps are required; Compose should now be successfully installed.
|
No further steps are required; Compose should now be successfully installed.
|
||||||
You can test the installation by running `docker-compose --version`.
|
You can test the installation by running `docker-compose --version`.
|
||||||
|
|
||||||
|
### Upgrading
|
||||||
|
|
||||||
|
If you're coming from Compose 1.2 or earlier, you'll need to remove or migrate your existing containers after upgrading Compose. This is because, as of version 1.3, Compose uses Docker labels to keep track of containers, and so they need to be recreated with labels added.
|
||||||
|
|
||||||
|
If Compose detects containers that were created without labels, it will refuse to run so that you don't end up with two sets of them. If you want to keep using your existing containers (for example, because they have data volumes you want to preserve) you can migrate them with the following command:
|
||||||
|
|
||||||
|
docker-compose migrate-to-labels
|
||||||
|
|
||||||
|
Alternatively, if you're not worried about keeping them, you can remove them - Compose will just create new ones.
|
||||||
|
|
||||||
|
docker rm -f myapp_web_1 myapp_db_1 ...
|
||||||
|
|
||||||
## Compose documentation
|
## Compose documentation
|
||||||
|
|
||||||
- [User guide](index.md)
|
- [User guide](index.md)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
PyYAML==3.10
|
PyYAML==3.10
|
||||||
docker-py==1.2.2
|
docker-py==1.2.2
|
||||||
dockerpty==0.3.3
|
dockerpty==0.3.4
|
||||||
docopt==0.6.1
|
docopt==0.6.1
|
||||||
requests==2.6.1
|
requests==2.6.1
|
||||||
six==1.7.3
|
six==1.7.3
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
PATH="/usr/local/bin:$PATH"
|
||||||
|
|
||||||
rm -rf venv
|
rm -rf venv
|
||||||
virtualenv venv
|
virtualenv -p /usr/local/bin/python venv
|
||||||
venv/bin/pip install -r requirements.txt
|
venv/bin/pip install -r requirements.txt
|
||||||
venv/bin/pip install -r requirements-dev.txt
|
venv/bin/pip install -r requirements-dev.txt
|
||||||
venv/bin/pip install .
|
venv/bin/pip install .
|
||||||
|
|
|
||||||
53
script/prepare-osx
Executable file
53
script/prepare-osx
Executable file
|
|
@ -0,0 +1,53 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
python_version() {
|
||||||
|
python -V 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
openssl_version() {
|
||||||
|
python -c "import ssl; print ssl.OPENSSL_VERSION"
|
||||||
|
}
|
||||||
|
|
||||||
|
desired_python_version="2.7.9"
|
||||||
|
desired_python_brew_version="2.7.9"
|
||||||
|
python_formula="https://raw.githubusercontent.com/Homebrew/homebrew/1681e193e4d91c9620c4901efd4458d9b6fcda8e/Library/Formula/python.rb"
|
||||||
|
|
||||||
|
desired_openssl_version="1.0.1j"
|
||||||
|
desired_openssl_brew_version="1.0.1j_1"
|
||||||
|
openssl_formula="https://raw.githubusercontent.com/Homebrew/homebrew/62fc2a1a65e83ba9dbb30b2e0a2b7355831c714b/Library/Formula/openssl.rb"
|
||||||
|
|
||||||
|
PATH="/usr/local/bin:$PATH"
|
||||||
|
|
||||||
|
if !(which brew); then
|
||||||
|
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
brew update
|
||||||
|
|
||||||
|
if !(python_version | grep "$desired_python_version"); then
|
||||||
|
if brew list | grep python; then
|
||||||
|
brew unlink python
|
||||||
|
fi
|
||||||
|
|
||||||
|
brew install "$python_formula"
|
||||||
|
brew switch python "$desired_python_brew_version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if !(openssl_version | grep "$desired_openssl_version"); then
|
||||||
|
if brew list | grep openssl; then
|
||||||
|
brew unlink openssl
|
||||||
|
fi
|
||||||
|
|
||||||
|
brew install "$openssl_formula"
|
||||||
|
brew switch openssl "$desired_openssl_brew_version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "*** Using $(python_version)"
|
||||||
|
echo "*** Using $(openssl_version)"
|
||||||
|
|
||||||
|
if !(which virtualenv); then
|
||||||
|
pip install virtualenv
|
||||||
|
fi
|
||||||
|
|
||||||
2
setup.py
2
setup.py
|
|
@ -31,7 +31,7 @@ install_requires = [
|
||||||
'texttable >= 0.8.1, < 0.9',
|
'texttable >= 0.8.1, < 0.9',
|
||||||
'websocket-client >= 0.11.0, < 1.0',
|
'websocket-client >= 0.11.0, < 1.0',
|
||||||
'docker-py >= 1.2.2, < 1.3',
|
'docker-py >= 1.2.2, < 1.3',
|
||||||
'dockerpty >= 0.3.3, < 0.4',
|
'dockerpty >= 0.3.4, < 0.4',
|
||||||
'six >= 1.3.0, < 2',
|
'six >= 1.3.0, < 2',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,3 +17,21 @@ class ProgressStreamTestCase(unittest.TestCase):
|
||||||
]
|
]
|
||||||
events = progress_stream.stream_output(output, StringIO())
|
events = progress_stream.stream_output(output, StringIO())
|
||||||
self.assertEqual(len(events), 1)
|
self.assertEqual(len(events), 1)
|
||||||
|
|
||||||
|
def test_stream_output_div_zero(self):
|
||||||
|
output = [
|
||||||
|
'{"status": "Downloading", "progressDetail": {"current": '
|
||||||
|
'0, "start": 1413653874, "total": 0}, '
|
||||||
|
'"progress": "..."}',
|
||||||
|
]
|
||||||
|
events = progress_stream.stream_output(output, StringIO())
|
||||||
|
self.assertEqual(len(events), 1)
|
||||||
|
|
||||||
|
def test_stream_output_null_total(self):
|
||||||
|
output = [
|
||||||
|
'{"status": "Downloading", "progressDetail": {"current": '
|
||||||
|
'0, "start": 1413653874, "total": null}, '
|
||||||
|
'"progress": "..."}',
|
||||||
|
]
|
||||||
|
events = progress_stream.stream_output(output, StringIO())
|
||||||
|
self.assertEqual(len(events), 1)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue