Skip to content

Commit

Permalink
Implement 'uninstall' command
Browse files Browse the repository at this point in the history
Fixes #10
  • Loading branch information
jacebrowning committed Feb 23, 2015
1 parent 216cf2d commit 89c4752
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ifndef TEST_RUNNER
# options are: nose, pytest
TEST_RUNNER := pytest
endif
UNIT_TEST_COVERAGE := 82
UNIT_TEST_COVERAGE := 80
INTEGRATION_TEST_COVERAGE := 96

# Project settings
Expand Down
2 changes: 1 addition & 1 deletion gdm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
exit("Python {}.{}+ is required.".format(*PYTHON_VERSION))

try:
from .commands import install
from .commands import install, uninstall
except ImportError: # pragma: no cover (manual test)
pass
14 changes: 11 additions & 3 deletions gdm/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,31 @@ def main(args=None, function=None):
shared = {'formatter_class': common.WideHelpFormatter,
'parents': [project, debug]}

# Build main parser
# Main parser
parser = argparse.ArgumentParser(prog=CLI, description=DESCRIPTION,
**shared)

subs = parser.add_subparsers(help="", dest='command', metavar="<command>")

# Build switch parser
info = "install the specified versions of all dependencies"
# Install parser
info = "get the specified versions of all dependencies"
subs.add_parser('install', description=info.capitalize() + '.',
help=info, **shared)

# Uninstall parser
info = "remove all installed dependencies"
subs.add_parser('uninstall', description=info.capitalize() + '.',
help=info, **shared)

# Parse arguments
args = parser.parse_args(args=args)
kwargs = {}
if args.command == 'install':
function = commands.install
kwargs['root'] = args.root
elif args.command == 'uninstall':
function = commands.uninstall
kwargs['root'] = args.root
if function is None:
parser.print_help()
sys.exit(1)
Expand Down
22 changes: 20 additions & 2 deletions gdm/commands.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Functions to manage the installation of dependencies."""

import os
import shutil

from . import common
from . import config
from .config import load, install_deps

log = common.logger(__name__)

Expand All @@ -13,7 +14,7 @@ def install(root=None):
root = _find_root(root)

log.info("installing dependencies...")
count = config.install_deps(root)
count = install_deps(root)
if count == 1:
log.info("installed 1 dependency")
elif count > 1:
Expand All @@ -24,6 +25,23 @@ def install(root=None):
return count


def uninstall(root=None):
"""Uninstall dependencies for a project."""
root = _find_root(root)

log.info("uninstalling dependencies...")
config = load(root)
if config:
if os.path.exists(config.location):
log.debug("deleting '%s'...", config.location)
shutil.rmtree(config.location)
log.info("dependencies uninstalled")
return True
else:
log.warn("no dependencies to uninstall")
return False


def _find_root(root, cwd=None):
if cwd is None:
cwd = os.getcwd()
Expand Down
20 changes: 15 additions & 5 deletions gdm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,22 @@ def install_deps(self):
return count


def install_deps(root, indent=0):
"""Install the dependences listed in the project's configuration file."""
def load(root):
"""Load the configuration for the current project."""
config = None
for filename in os.listdir(root):
if filename.lower() in Config.FILENAMES:
config = Config(root, filename)
log.debug("loaded config: %s", config.path)
config.indent = indent
return config.install_deps()
return 0
break
return config


def install_deps(root, indent=0):
"""Install the dependences listed in the project's configuration file."""
config = load(root)
if config:
config.indent = indent
return config.install_deps()
else:
return 0
17 changes: 14 additions & 3 deletions gdm/test/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
def test_install():
"""Verify dependencies can be installed."""
config = Config(FILES)
if os.path.exists(config.location):
shutil.rmtree(config.location)
shutil.rmtree(config.location, ignore_errors=True)
assert not os.path.exists(config.location)

# clean install
Expand All @@ -27,4 +26,16 @@ def test_install():
assert 'gdm_1' in os.listdir(config.location)
assert 'gdm_2' in os.listdir(config.location)

shutil.rmtree(os.path.join(FILES, 'src'))
shutil.rmtree(os.path.join(FILES, 'src'), ignore_errors=True)


@pytest.mark.integration
def test_uninstall():
"""Verify dependencies can be uninstalled."""
config = Config(FILES)
assert gdm.install(FILES)
assert os.path.isdir(config.location)

assert gdm.uninstall(FILES)

assert not os.path.isdir(config.location)
17 changes: 17 additions & 0 deletions gdm/test/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,23 @@ def test_install_root(self, mock_install):
mock_install.assert_called_once_with(root='mock/path/to/root')


class TestUninstall:

"""Unit tests for the `uninstall` command."""

@patch('gdm.commands.uninstall')
def test_uninstall(self, mock_uninstall):
"""Verify the 'uninstall' command can be run."""
cli.main(['uninstall'])
mock_uninstall.assert_called_once_with(root=None)

@patch('gdm.commands.uninstall')
def test_uninstall_root(self, mock_uninstall):
"""Verify the project's root can be specified."""
cli.main(['uninstall', '--root', 'mock/path/to/root'])
mock_uninstall.assert_called_once_with(root='mock/path/to/root')


class TestLogging:

"""Unit tests for logging."""
Expand Down
1 change: 1 addition & 0 deletions gdm/test/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
class TestFindRoot:

def test_specified(self):
os.chdir(PROJECT_PARENT)
assert FILES == _find_root(FILES)

def test_none(self):
Expand Down
17 changes: 16 additions & 1 deletion gdm/test/test_config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""Unit tests for the `config` module."""
# pylint: disable=R0201

import os

import pytest

from gdm.config import Source, Config, install_deps
from gdm.config import Source, Config, load, install_deps

from .conftest import FILES

Expand Down Expand Up @@ -74,6 +76,19 @@ def test_path(self):
assert "mock/root/gdm.yml" == config.path


class TestLoad:

def test_load(self):
"""Verify a configuration can be loaded."""
config = load(FILES)
assert None is not config

def test_load_missing(self):
"""Verify None is returned for a missing config."""
config = load(os.path.dirname(FILES))
assert None is config


class TestInstall:

@pytest.mark.integration
Expand Down

0 comments on commit 89c4752

Please sign in to comment.