2015-06-27 01:53:57 -04:00
|
|
|
import sys, os
|
|
|
|
|
|
|
|
PROJECT_ROOT_DIRECTORY = os.path.dirname(
|
|
|
|
os.path.dirname(os.path.realpath(__file__)))
|
|
|
|
|
|
|
|
def inject(lib_path):
|
|
|
|
path = os.path.join(PROJECT_ROOT_DIRECTORY, 'lib', lib_path)
|
|
|
|
sys.path.insert(0, path)
|
|
|
|
|
|
|
|
# version dependent libraries
|
|
|
|
if sys.version_info[0] >= 3:
|
|
|
|
inject('pyyaml/lib3')
|
|
|
|
else:
|
|
|
|
inject('pyyaml/lib')
|
|
|
|
|
|
|
|
if os.path.exists(os.path.join(PROJECT_ROOT_DIRECTORY, 'dotbot')):
|
|
|
|
if PROJECT_ROOT_DIRECTORY not in sys.path:
|
|
|
|
sys.path.insert(0, PROJECT_ROOT_DIRECTORY)
|
|
|
|
os.putenv('PYTHONPATH', PROJECT_ROOT_DIRECTORY)
|
|
|
|
|
|
|
|
|
|
|
|
import shutil
|
|
|
|
import dotbot
|
|
|
|
import tempfile
|
|
|
|
import unittest
|
|
|
|
import shlex
|
2015-06-27 19:36:23 -04:00
|
|
|
import yaml
|
2015-06-27 01:53:57 -04:00
|
|
|
|
|
|
|
try:
|
|
|
|
from StringIO import StringIO
|
|
|
|
except ImportError:
|
|
|
|
from io import StringIO
|
|
|
|
|
|
|
|
# mock is built-in after py3.3, otherwise import the 3rd party mock
|
|
|
|
try:
|
|
|
|
from unittest import mock
|
|
|
|
except ImportError:
|
|
|
|
import mock
|
|
|
|
|
|
|
|
|
|
|
|
class DotbotTestCase(unittest.TestCase):
|
|
|
|
""" Dotbot specific TestCase that will take care of setting up temporary directories and a convenience
|
|
|
|
function for simulating running Dotbot from the CLI """
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
""" Creates a temporary directory to run in for every test """
|
|
|
|
self.tempdir = tempfile.mkdtemp()
|
|
|
|
self.dotbot_dir = os.path.join(self.tempdir, 'dotbot')
|
|
|
|
self.home_dir = os.path.join(self.tempdir, 'home')
|
|
|
|
self.config_file = os.path.join(self.dotbot_dir, 'dotbot.config')
|
|
|
|
|
|
|
|
if int(os.environ.get('NO_CLEAN', '0')):
|
|
|
|
print(self.tempdir) # If we're not going to clean up, print out where we're runnin
|
|
|
|
|
|
|
|
os.mkdir(self.dotbot_dir)
|
|
|
|
os.mkdir(self.home_dir)
|
|
|
|
|
|
|
|
def add_file(self, filename, contents=""):
|
|
|
|
""" Create a file in temporary dotbot_dir. Optionally with content """
|
|
|
|
with open(os.path.join(self.dotbot_dir, filename), 'w') as f:
|
|
|
|
f.write(contents)
|
|
|
|
|
2015-06-27 19:36:23 -04:00
|
|
|
def add_home_file(self, filename, contents=""):
|
|
|
|
""" Create a file in the temporary home_dir. Optionally with content """
|
|
|
|
with open(os.path.join(self.home_dir, filename), 'w') as f:
|
|
|
|
f.write(contents)
|
|
|
|
|
2015-06-27 01:53:57 -04:00
|
|
|
def add_dirs(self, path):
|
|
|
|
""" Create directories within the temporary dotbot_dir. Acts like ``mkdir -p``. Path is relative to the
|
|
|
|
dotbot dir """
|
|
|
|
os.makedirs(os.path.join(self.dotbot_dir, path))
|
|
|
|
|
2015-06-27 19:36:23 -04:00
|
|
|
def add_home_dirs(self, path):
|
|
|
|
""" Create directories within the temporary home_dir. Acts like ``mkdir -p``. Path is relative to the
|
|
|
|
home dir """
|
|
|
|
os.makedirs(os.path.join(self.home_dir, path))
|
2015-06-27 01:53:57 -04:00
|
|
|
|
2015-06-27 19:36:23 -04:00
|
|
|
def add_symlink(self, path, dotbot_path=None):
|
|
|
|
""" Creates a symlink from ``self.home_dir``/path to ``self.dotbot_dir``/dotbot_path.
|
|
|
|
If dotbot_path is None, path will be used for home_dir and dotbot_dir """
|
|
|
|
dotbot_path = path if dotbot_path is None else dotbot_path
|
|
|
|
os.symlink(os.path.join(self.dotbot_dir, dotbot_path), os.path.join(self.home_dir, path))
|
|
|
|
|
|
|
|
def assertIsLinked(self, path, dotbot_path=None):
|
2015-06-27 01:53:57 -04:00
|
|
|
""" Asserts that the given ``path`` in self.home_dir is symlinked to the corresponding ``path``
|
|
|
|
in self.dotbot_dir """
|
2015-06-27 19:36:23 -04:00
|
|
|
dotbot_path = path if dotbot_path is None else dotbot_path
|
2015-06-27 01:53:57 -04:00
|
|
|
self.assertTrue(os.path.islink(os.path.join(self.home_dir, path)))
|
2015-06-27 19:36:23 -04:00
|
|
|
self.assertEqual(os.stat(os.path.join(self.dotbot_dir, dotbot_path)),
|
2015-06-27 01:53:57 -04:00
|
|
|
os.stat(os.path.join(self.home_dir, path)))
|
|
|
|
|
2015-06-27 19:36:23 -04:00
|
|
|
def assertNotLinked(self, path, dotbot_path=None):
|
|
|
|
""" Asserts that the given ``path`` in self.home_dir is symlinked to the corresponding ``path``
|
|
|
|
in self.dotbot_dir """
|
|
|
|
dotbot_path = path if dotbot_path is None else dotbot_path
|
|
|
|
self.assertNotEqual(os.stat(os.path.join(self.dotbot_dir, dotbot_path)),
|
|
|
|
os.stat(os.path.join(self.home_dir, path)))
|
|
|
|
|
2015-06-27 01:53:57 -04:00
|
|
|
def assertDoesNotExist(self, path):
|
|
|
|
""" Asserts the given ``path`` in self.home_dir does not exist """
|
|
|
|
self.assertFalse(os.path.exists(os.path.join(self.home_dir, path)) or
|
|
|
|
os.path.lexists(os.path.join(self.home_dir, path)))
|
|
|
|
|
|
|
|
def run_dotbot(self, config="", args="", skip_config=False):
|
|
|
|
""" Runs dotbot in a simulated way temporarily intercepting stdout, stderr, setting the HOME
|
|
|
|
environment variable to ``self.home_dir``, and setting sys.argv to the simulated command
|
|
|
|
line options. ``run_dotbot`` will automatically set the ``--base-directory`` and
|
|
|
|
``--config-file`` command line arguments appropriately.
|
|
|
|
|
|
|
|
The ``config`` argument is a string that is written out as the configuration file for dotbot
|
|
|
|
to use. The ``args`` argument is a string of extra command line arguments to pass to dotbot
|
|
|
|
just like they would be passed on the command line.
|
|
|
|
|
|
|
|
If ``skip_config`` is True, a config file will not be written.
|
|
|
|
|
|
|
|
Returns a tuple (out, err) of the stdout and stderr from dotbot.
|
|
|
|
"""
|
|
|
|
|
|
|
|
if not skip_config:
|
|
|
|
with open(self.config_file, 'w') as f:
|
2015-06-27 19:36:23 -04:00
|
|
|
if not isinstance(config, str):
|
|
|
|
f.write(yaml.dump(config, default_flow_style=False))
|
|
|
|
else:
|
|
|
|
f.write(config)
|
2015-06-27 01:53:57 -04:00
|
|
|
|
|
|
|
base_args = [
|
|
|
|
'dotbot',
|
2015-06-27 19:36:23 -04:00
|
|
|
'--base-directory', self.dotbot_dir,
|
2015-06-27 01:53:57 -04:00
|
|
|
'--config-file', self.config_file,
|
|
|
|
]
|
|
|
|
|
|
|
|
old_home, os.environ['HOME'] = os.path.expanduser('~'), self.home_dir
|
|
|
|
old_stdout, sys.stdout = sys.stdout, StringIO()
|
|
|
|
old_stderr, sys.stderr = sys.stderr, StringIO()
|
|
|
|
old_argv, sys.argv = sys.argv, base_args + shlex.split(args)
|
2015-06-27 19:36:23 -04:00
|
|
|
old_environ = os.environ.copy()
|
2015-06-27 01:53:57 -04:00
|
|
|
|
|
|
|
try:
|
2015-06-27 19:36:23 -04:00
|
|
|
dotbot.cli.main()
|
2015-06-27 01:53:57 -04:00
|
|
|
finally:
|
|
|
|
os.environ['HOME'] = old_home
|
|
|
|
out, sys.stdout = sys.stdout.getvalue(), old_stdout
|
|
|
|
err, sys.stderr = sys.stderr.getvalue(), old_stderr
|
|
|
|
sys.argv = old_argv
|
2015-06-27 19:36:23 -04:00
|
|
|
os.environ.clear()
|
|
|
|
os.environ.update(old_environ)
|
|
|
|
|
|
|
|
if int(os.environ.get('DEBUG', '0')):
|
|
|
|
print("\nDotbot Output:")
|
|
|
|
print('out:\n', out)
|
|
|
|
print('err:\n', err)
|
2015-06-27 01:53:57 -04:00
|
|
|
|
|
|
|
return out, err
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
""" Clean up the temporary directory that was created. Set NO_CLEAN=1 to disable cleanup """
|
|
|
|
if not int(os.environ.get('NO_CLEAN', '0')):
|
|
|
|
shutil.rmtree(self.tempdir)
|