docs/plum/cli/main.py

178 lines
4.6 KiB
Python

import logging
import sys
import re
from inspect import getdoc
from .. import __version__
from .command import Command
from .formatter import Formatter
from .log_printer import LogPrinter
from docker.client import APIError
from .errors import UserError
from .docopt_command import NoSuchCommand
log = logging.getLogger(__name__)
def main():
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter())
console_handler.setLevel(logging.INFO)
root_logger = logging.getLogger()
root_logger.addHandler(console_handler)
root_logger.setLevel(logging.DEBUG)
# Disable requests logging
logging.getLogger("requests").propagate = False
try:
command = TopLevelCommand()
command.sys_dispatch()
except KeyboardInterrupt:
log.error("\nAborting.")
exit(1)
except UserError, e:
log.error(e.msg)
exit(1)
except NoSuchCommand, e:
log.error("No such command: %s", e.command)
log.error("")
log.error("\n".join(parse_doc_section("commands:", getdoc(e.supercommand))))
exit(1)
except APIError, e:
log.error(e.explanation)
exit(1)
# stolen from docopt master
def parse_doc_section(name, source):
pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
re.IGNORECASE | re.MULTILINE)
return [s.strip() for s in pattern.findall(source)]
class TopLevelCommand(Command):
""".
Usage:
plum [options] [COMMAND] [ARGS...]
plum -h|--help
Options:
--verbose Show more output
--version Print version and exit
Commands:
ps List services and containers
run Run a one-off command
start Start services
stop Stop services
"""
def docopt_options(self):
options = super(TopLevelCommand, self).docopt_options()
options['version'] = "plum %s" % __version__
return options
def ps(self, options):
"""
List services and containers.
Usage: ps [options]
Options:
-q Only display IDs
"""
if options['-q']:
for container in self.project.containers(all=True):
print container.id
else:
headers = [
'Name',
'Command',
'State',
'Ports',
]
rows = []
for container in self.project.containers(all=True):
rows.append([
container.name,
container.human_readable_command,
container.human_readable_state,
container.human_readable_ports,
])
print Formatter().table(headers, rows)
def run(self, options):
"""
Run a one-off command.
Usage: run SERVICE COMMAND [ARGS...]
"""
service = self.project.get_service(options['SERVICE'])
if service is None:
raise UserError("No such service: %s" % options['SERVICE'])
container_options = {
'command': [options['COMMAND']] + options['ARGS'],
}
container = service.create_container(**container_options)
stream = container.logs(stream=True)
service.start_container(container, ports=None)
for data in stream:
if data is None:
break
print data
def start(self, options):
"""
Start all services
Usage: start [-d]
"""
if options['-d']:
self.project.start()
return
running = []
unstarted = []
for s in self.project.services:
if len(s.containers()) == 0:
unstarted.append((s, s.create_container()))
else:
running += s.containers(all=False)
log_printer = LogPrinter(running + [c for (s, c) in unstarted])
for (s, c) in unstarted:
s.start_container(c)
try:
log_printer.run()
finally:
self.project.stop()
def stop(self, options):
"""
Stop all services
Usage: stop
"""
self.project.stop()
def logs(self, options):
"""
View containers' output
Usage: logs
"""
containers = self.project.containers(all=False)
print "Attaching to", list_containers(containers)
LogPrinter(containers, attach_params={'logs': True}).run()
def list_containers(containers):
return ", ".join(c.name for c in containers)