Skip to content

Commit

Permalink
Merge pull request #141 from akretion/imp-init
Browse files Browse the repository at this point in the history
refactor docky init
  • Loading branch information
hparfr authored Mar 23, 2021
2 parents e9f3799 + 9f79b5e commit 2e26337
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 146 deletions.
4 changes: 0 additions & 4 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
include docky/template/odoo.docker-compose.yml
include docky/template/locomotive.docker-compose.yml
include docky/template/wagon.docker-compose.yml
include docky/template/ruby.docker-compose.yml
include requirements.txt
9 changes: 5 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,10 @@ Usage: commands
docky init
Bootstraps a project using a template. This will ask you a series of questions to create customized `.env <https://docs.docker.com/compose/env-file/>`_ and docker-compose.yml files that you can further edit.
The template used is for running an Odoo server with some optional tools.
Bootstraps a odoo project using a template (https://github.com/akretion/docky-odoo-template)
This will ask you a series of questions to create customized `.env <https://docs.docker.com/compose/env-file/>`_ and docker-compose.yml files that you can further edit.
Note that the template presumes that you have a running Traefik container on the "traefik" docker network.

You can also start from a template like this one : https://github.com/akretion/docky-odoo-template

For more information on other commands, use docky --help and check the `documentation <https://github.com/akretion/docky/blob/master/doc/command_line.rst>`_.


Expand Down Expand Up @@ -119,6 +117,9 @@ see : https://github.com/docker/compose/issues/6151
Changelog
----------

version 7.0.4
- use `copier` for managing the template

version 7.0.0

- remove the need of docky config file in $HOME
Expand Down
2 changes: 1 addition & 1 deletion docky/cmd/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

class Docky(cli.Application):
PROGNAME = "docky"
VERSION = '7.0.3'
VERSION = '7.0.4'
SUBCOMMAND_HELPMSG = None

def _run(self, cmd, retcode=FG):
Expand Down
28 changes: 7 additions & 21 deletions docky/cmd/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,16 @@


from .base import Docky
from ..common.generator import GenerateComposeFile, GenerateEnvFile

TEMPLATE_SERVICE = ['odoo']
from ..common.generator import GenerateProject


@Docky.subcommand("init")
class DockyInit(cli.Application):
"""Initalize a project"""

TEMPLATE_URL = "https://github.com/akretion/docky-odoo-template.git"
TEMPLATE_BRANCH = "14.0"
template_branch = cli.SwitchAttr("--b", help="Template's branch", argtype=str, default=TEMPLATE_BRANCH)
template_url = cli.SwitchAttr("--url", help="Template's url", argtype=str, default=TEMPLATE_URL)

def main(self, *args, **kwargs):
self._generate_env()
self._generate_dev_docker_compose_file()

def _generate_dev_docker_compose_file(self):
for service in TEMPLATE_SERVICE:
generate = ask(
"Do you want to generate docker-compose.yml "
"automatically for %s" % service,
default=True)
if generate:
return GenerateComposeFile(service).generate()

def _generate_env(self):
generate = ask(
"Do you want to generate .env file ?", default=True)
if generate:
return GenerateEnvFile().generate()
GenerateProject().generate(url=self.template_url, branch=self.template_branch)
138 changes: 23 additions & 115 deletions docky/common/generator.py
Original file line number Diff line number Diff line change
@@ -1,125 +1,33 @@
#!/usr/bin/env python
# coding: utf-8

import yaml
import pkg_resources
from plumbum.cli.terminal import ask, prompt
from plumbum.cmd import echo, id
from plumbum.cmd import id, copier, ls
from plumbum.commands.modifiers import FG
from plumbum import local
from slugify import slugify
from compose.config.environment import Environment

from ..common.api import logger


class IndentDumper(yaml.Dumper):

def increase_indent(self, flow=False, indentless=False):
return super(IndentDumper, self).increase_indent(flow, False)


class GenerateComposeFile(object):

def __init__(self, service):
super(GenerateComposeFile, self).__init__()
# Do not use os.path.join()
self.service = service
resource_path = '../template/%s.docker-compose.yml' % service
template = pkg_resources.resource_stream(__name__, resource_path)
config = template.read()
self.config = yaml.safe_load(config)

def _ask_optional_service(self):
"""Container can be set as optional by adding the key
"optional" and "description". This method will ask the user to
use or not this optional container"""
answer = {}
for name, config in self.config['services'].copy().items():
if config.get('optional'):
option = config['optional']
if option not in answer:
answer[option] = ask(
"%s. Do you want to install it"
% option, default=False)
if answer[option]:
# remove useless docker compose key
del self.config['services'][name]['optional']
if 'links' not in self.config['services'][self.service]:
self.config['services'][self.service]['links'] = []
self.config['services'][self.service]['links'].append(name)
else:
del self.config['services'][name]

def generate(self):
self._ask_optional_service()
with open('docker-compose.yml', 'w') as dc_tmp_file:
dc_tmp_file.write(yaml.dump(
self.config, Dumper=IndentDumper, default_flow_style=False))


class GenerateEnvFile(object):
'''Create or add some variables to .env.
If a variable is already present, don't change it
'''
def _key_compose_file(self):
# create an (prod|dev).docker-compose.yml
# and set it in compose_file variable
# TODO: extract it
# TODO: create file properly
env_file = '%s.docker-compose.yml' % self._key_env()
if not local.path(env_file).exists():
(echo['version: "3"'] > env_file)()
return (
'docker-compose.yml:%s.docker-compose.yml'
% self._key_env())

def _key_uid(self):
class GenerateProject(object):
def _uid(self):
return id['-u']().replace('\n', '')

def _key_compose_project_name(self):
return get_project_name()

def _key_env(self):
return self.env

@property
def env(self):
# set current environment for creating file dev.docker-compose
# TODO: use --env flag instead
if not hasattr(self, '_env'):
self._env = prompt('Current environment ?', default='dev')
return self._env

@property
def keys(self):
self._keys = {
'UID': self._key_uid,
'ENV': self._key_env,
'COMPOSE_FILE': self._key_compose_file,
'COMPOSE_PROJECT_NAME': self._key_compose_project_name,
}
return self._keys

def generate(self):
logger.info('Writing .env file')
env = Environment.from_env_file('.')
to_add = []
for key, fun in self.keys.items():
if env.get(key):
logger.debug(
'%s already present in .env, not modified' % key)
else:
logger.debug('Adding %s to .env' % key)
to_add.append('%s=%s' % (key, fun()))
for line in to_add:
# append line to file
(echo[line] >> '.env')()


def get_project_name():
env = Environment.from_env_file('.')
return env.get(
'COMPOSE_PROJECT_NAME',
'%s_%s' % (slugify(local.env.user), slugify(local.cwd.name))
)
def _project_name(self):
return slugify(local.cwd.name)

def _is_copier_dir(self):
return local.path(".copier-answers.yml").is_file()

def _is_empty(self):
# we don't care with dot files
return len(ls()) == 0

def generate(self, url, branch):
if self._is_copier_dir():
# if already inited ask the user with questions
return copier['update'] & FG
else:
if not self._is_empty():
raise BaseException("Not empty dir")
return copier['-d', f'uid={self._uid()}', '-d', f'project_name={self._project_name()}', "-b", branch, url, '.'] & FG

2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ docker-compose>=1.23.1
plumbum
rainbow_logging_handler
python-slugify

git+https://github.com/hparfr/copier@vcs_branch
# Only for solving installation issue with pip that fail to
# solve the version of request compatible with docker and docker-compose
requests<3,>=2.20.0

0 comments on commit 2e26337

Please sign in to comment.