Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
Fixed #28 -- Added a command for generating a basic LXDock file (#32)
Browse files Browse the repository at this point in the history
* Fixed #28 -- Added a command for generating a basic LXDock file

* Removed uneccessary usage of codecs.open and mocked os.getcwd instead of os.path.exists
  • Loading branch information
ellmetha authored and Virgil Dupras committed Mar 9, 2017
1 parent b74ed59 commit 2d722cc
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 1 deletion.
8 changes: 7 additions & 1 deletion contrib/completion/bash/lxdock
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ___lxdock_container_names() {
_lxdock_complete () {
local cur cmd commands

commands='config destroy halt help provision shell status up'
commands='config destroy halt help init provision shell status up'

cur=${COMP_WORDS[COMP_CWORD]}
cmd=${COMP_WORDS[1]}
Expand Down Expand Up @@ -56,6 +56,12 @@ _lxdock_complete () {
containers="$(___lxdock_container_names)"
COMPREPLY=($(compgen -W "$containers" -- ${cur}))
;;
init)
case "${cur}" in
-*)
COMPREPLY=($(compgen -W "-f --force --image --project" -- ${cur})) ;;
esac
;;
provision)
containers="$(___lxdock_container_names)"
COMPREPLY=($(compgen -W "$containers" -- ${cur}))
Expand Down
1 change: 1 addition & 0 deletions docs/cli/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ help for a specifc subcommand. For example:
destroy
halt
help
init
provision
shell
status
Expand Down
24 changes: 24 additions & 0 deletions docs/cli/init.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
lxdock init
===========

**Command:** ``lxdock init``

This command can be used to generate a LXDock file containing highlights regarding some useful
options.

Options
-------

* ``--image`` - this option allows to use a specific container image in the generated configuration
* ``--project`` - this option allows to define the name of the project that will appear in the LXDock file
* ``--force`` or ``-f`` - this option allows to overwrite an exsting LXDock file if any

Examples
--------

.. code-block:: console
$ lxdock init # generates a basic LXDock file
$ lxdock init --image debian/jessie # generates a LXDock file defining a debian/jessie container
$ lxdock init --project myproject # generates a basic LXDock file defining a "myproject" project
$ lxdock init --force # overwrite an existing LXDock file if applicable
32 changes: 32 additions & 0 deletions lxdock/cli/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# TEMPLATES
# --

INIT_LXDOCK_FILE_CONTENT = """# This is a basic configuration file for LXDock.
# All configuration is done through this YML file that should be placed at the root of your project.
# The file define a basic LXDock project containing a single container with highlights regarding
# some other useful options.
name: {project_name}
image: {image}
# By default LXDock creates a single "default" container if you don't specify a "containers" option.
# But you need the "containers" option if you have more than one container.
# containers:
# - name: {project_name}01
# - name: {project_name}02
# - name: {project_name}02
# Most of the options can be redefined for each container definition, eg. the "image" option:
# image: archlinux
# You can use the "provisioning" option to define provisioning tools that should be used to
# provision your containers. For example, you could use Ansible as follows:
# provisioning:
# - type: ansible
# playbook: deploy/site.yml
# A common need is to access your project folder in your containers. To do this you can use the
# "shares" option:
# shares:
# - source: .
# dest: /myshare
"""
32 changes: 32 additions & 0 deletions lxdock/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ def __init__(self, argv=None):
'subcommand.')
self._parsers['help'].add_argument('subcommand', nargs='?', help='Subcommand name.')

# Creates the 'init' action.
self._parsers['init'] = subparsers.add_parser(
'init', help='Generate a LXDock file.',
description='Generate a LXDock file defining a single container and highlighting '
'useful options.')
self._parsers['init'].add_argument(
'-f', '--force', action='store_true', help='Overwrite existing LXDock file')
self._parsers['init'].add_argument('--image', help='Container image to use')
self._parsers['init'].add_argument('--project', help='Project name to use')

# Creates the 'provision' action.
self._parsers['provision'] = subparsers.add_parser(
'provision', help='Provision containers.',
Expand Down Expand Up @@ -163,6 +173,28 @@ def help(self, args):
# args.subcommand is not a valid subcommand!
raise CLIError('No such command: {}'.format(args.subcommand))

def init(self, args):
import os
from ..conf.constants import ALLOWED_FILENAMES
from .constants import INIT_LXDOCK_FILE_CONTENT
cwd = os.getcwd()
project_name = args.project or os.path.split(cwd)[1]

# Check if an existing config file is already present in the current working directory.
existing_config = [
filename for filename in ALLOWED_FILENAMES
if os.path.exists(os.path.join(cwd, filename))]
if existing_config and not args.force:
raise CLIError(
'An existing LXDock file is already present in this directory! Using "lxdock init" '
'could overwrite this file. Use the -f/--force to overwrite existing LXDock files.')

# Compute the content of the LXDock file to write and write it to a lxdock.yml file.
init_filecontent = INIT_LXDOCK_FILE_CONTENT.format(
project_name=project_name, image=args.image or 'ubuntu/xenial')
with open('lxdock.yml', mode='w', encoding='utf-8') as fd:
fd.write(init_filecontent)

def provision(self, args):
self.project.provision(container_names=args.name)

Expand Down
58 changes: 58 additions & 0 deletions tests/unit/cli/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pytest

from lxdock.cli.constants import INIT_LXDOCK_FILE_CONTENT
from lxdock.cli.main import LXDock, main
from lxdock.cli.project import get_project
from lxdock.conf.config import Config
Expand Down Expand Up @@ -252,3 +253,60 @@ def test_project_property_works(
project1, project2 = n.project, n.project
assert project1 == project2
assert from_config_mock.call_count == 1

@unittest.mock.patch('builtins.open')
def test_can_generate_a_basic_lxdock_file(self, mock_open):
fd_mock = unittest.mock.Mock()
mock_open.return_value.__enter__.return_value = fd_mock
LXDock(['init', ])
assert mock_open.call_count == 1
assert mock_open.call_args[0] == ('lxdock.yml', )
assert fd_mock.write.call_count == 1
assert fd_mock.write.call_args[0][0] == INIT_LXDOCK_FILE_CONTENT.format(
project_name=os.path.split(os.getcwd())[1], image='ubuntu/xenial')

@unittest.mock.patch('builtins.open')
@unittest.mock.patch('os.getcwd')
def test_cannot_generate_a_lxdock_file_if_there_is_already_an_existing_lxdock_file(
self, mock_getcwd, mock_open):
mock_getcwd.return_value = os.path.join(FIXTURE_ROOT, 'project01')
fd_mock = unittest.mock.Mock()
mock_open.return_value.__enter__.return_value = fd_mock
with pytest.raises(SystemExit):
LXDock(['init', ])

@unittest.mock.patch('builtins.open')
@unittest.mock.patch('os.getcwd')
def test_can_generate_a_lxdock_file_by_overwritting_an_existing_file_with_the_force_option(
self, mock_getcwd, mock_open):
mock_getcwd.return_value = os.path.join(FIXTURE_ROOT, 'project01')
fd_mock = unittest.mock.Mock()
mock_open.return_value.__enter__.return_value = fd_mock
LXDock(['init', '--force'])
assert mock_open.call_count == 1
assert mock_open.call_args[0] == ('lxdock.yml', )
assert fd_mock.write.call_count == 1
assert fd_mock.write.call_args[0][0] == INIT_LXDOCK_FILE_CONTENT.format(
project_name=os.path.split(os.getcwd())[1], image='ubuntu/xenial')

@unittest.mock.patch('builtins.open')
def test_can_generate_a_lxdock_file_with_a_custom_image(self, mock_open):
fd_mock = unittest.mock.Mock()
mock_open.return_value.__enter__.return_value = fd_mock
LXDock(['init', '--image', 'debian/jessie', ])
assert mock_open.call_count == 1
assert mock_open.call_args[0] == ('lxdock.yml', )
assert fd_mock.write.call_count == 1
assert fd_mock.write.call_args[0][0] == INIT_LXDOCK_FILE_CONTENT.format(
project_name=os.path.split(os.getcwd())[1], image='debian/jessie')

@unittest.mock.patch('builtins.open')
def test_can_generate_a_lxdock_file_with_a_custom_project_name(self, mock_open):
fd_mock = unittest.mock.Mock()
mock_open.return_value.__enter__.return_value = fd_mock
LXDock(['init', '--project', 'customproject', ])
assert mock_open.call_count == 1
assert mock_open.call_args[0] == ('lxdock.yml', )
assert fd_mock.write.call_count == 1
assert fd_mock.write.call_args[0][0] == INIT_LXDOCK_FILE_CONTENT.format(
project_name='customproject', image='ubuntu/xenial')

0 comments on commit 2d722cc

Please sign in to comment.