aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml15
-rw-r--r--README.rst20
-rw-r--r--dotfiles/cli.py6
-rw-r--r--dotfiles/core.py18
-rwxr-xr-xtest_dotfiles.py72
5 files changed, 116 insertions, 15 deletions
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..8e6edd7
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,15 @@
+language: python
+python:
+ - "2.5"
+ - "2.6"
+ - "2.7"
+ - "3.2"
+ - "3.3"
+
+# command to install dependencies
+install:
+ - "pip install . --use-mirrors"
+
+# command to run tests
+script:
+ - "python test_dotfiles.py"
diff --git a/README.rst b/README.rst
index dca0e9b..640d174 100644
--- a/README.rst
+++ b/README.rst
@@ -1,11 +1,17 @@
Dotfile management made easy
============================
+.. image:: https://pypip.in/v/dotfiles/badge.png
+ :target: https://pypi.python.org/pypi/dotfiles
+
+.. image:: https://secure.travis-ci.org/jbernard/dotfiles.png?branch=develop
+ :target: http://travis-ci.org/jbernard/dotfiles
+
``dotfiles`` is a tool to make managing your dotfile symlinks in ``$HOME``
easy, allowing you to keep all your dotfiles in a single directory.
-Hosting is up to you. Using whatever VCS you prefer, or even rsync, you can
-easily distribute your dotfiles repository across multiple hosts.
+Hosting is up to you. You can use a VCS like git, Dropbox, or even rsync to
+distribute your dotfiles repository across multiple hosts.
The repository can be specified at runtime, so you can manage multiple
repositories without hassle. See the Configuration_ section below for further
@@ -29,12 +35,14 @@ Interface
``-r, --remove <file...>``
Remove dotfile(s) from the repository.
-``-s, --sync``
+``-s, --sync [file...]``
Update dotfile symlinks. You can overwrite colliding files with ``-f`` or
- ``--force``.
+ ``--force``. All dotfiles are assumed if you do not specify any files to
+ this command.
-``-m, --move``
- Move dotfiles repository to another location.
+``-m, --move <path>``
+ Move dotfiles repository to another location, updating all symlinks in the
+ process.
For all commands you can use the ``--dry-run`` option, which will print actions
and won't modify anything on your drive.
diff --git a/dotfiles/cli.py b/dotfiles/cli.py
index 940495e..c0984d6 100644
--- a/dotfiles/cli.py
+++ b/dotfiles/cli.py
@@ -177,10 +177,8 @@ def parse_config(config_file):
def dispatch(dotfiles, action, force, args):
if action in ['list', 'check']:
getattr(dotfiles, action)()
- elif action in ['add', 'remove']:
+ elif action in ['add', 'remove', 'sync']:
getattr(dotfiles, action)(args)
- elif action == 'sync':
- dotfiles.sync(force)
elif action == 'move':
if len(args) > 1:
print("Error: Move cannot handle multiple targets.")
@@ -212,7 +210,7 @@ def main():
(cli_opts, args) = parse_args()
- settings['homedir'] = realpath_expanduser(cli_opts.homedir or
+ settings['homedir'] = realpath_expanduser(cli_opts.homedir or
defaults['homedir'])
settings['config_file'] = realpath_expanduser(cli_opts.config_file or
defaults['config_file'])
diff --git a/dotfiles/core.py b/dotfiles/core.py
index 1dfcea7..b2e2d0c 100644
--- a/dotfiles/core.py
+++ b/dotfiles/core.py
@@ -152,7 +152,7 @@ class Dotfiles(object):
self._load_recursive(pkg_path)
else:
self.dotfiles.append(Dotfile(dotfile[len(self.prefix):],
- os.path.join(src_dir, dotfile), dst_dir,
+ os.path.join(src_dir, dotfile), dst_dir,
add_dot=not bool(sub_dir), dry_run=self.dry_run))
# Externals are top-level only
@@ -182,12 +182,21 @@ class Dotfiles(object):
self.list(verbose=False)
- def sync(self, force=False):
+ def sync(self, files=None, force=False):
"""Synchronize this repository, creating and updating the necessary
symbolic links."""
- for dotfile in self.dotfiles:
+ # unless a set of files is specified, operate on all files
+ if not files:
+ dotfiles = self.dotfiles
+ else:
+ files = map(lambda x: os.path.join(self.homedir, x), files)
+ dotfiles = [x for x in self.dotfiles if x.name in files]
+ if not dotfiles:
+ raise Exception("file not found")
+
+ for dotfile in dotfiles:
dotfile.sync(force)
def add(self, files):
@@ -211,6 +220,9 @@ class Dotfiles(object):
if pkg_name in self.packages:
home = os.path.join(self.homedir, sub_dir)
target = self._fqpn(file, pkg_name=pkg_name)
+ dirname = os.path.dirname(target)
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
else:
home = self.homedir
target = self._fqpn(file)
diff --git a/test_dotfiles.py b/test_dotfiles.py
index 88ffe67..babe43c 100755
--- a/test_dotfiles.py
+++ b/test_dotfiles.py
@@ -180,7 +180,7 @@ class DotfilesTestCase(unittest.TestCase):
self.assertPathEqual(
os.path.join(self.repository, original),
os.path.join(self.homedir, symlink))
-
+
def test_packages(self):
"""
Test packages.
@@ -197,7 +197,7 @@ class DotfilesTestCase(unittest.TestCase):
os.makedirs(dirname)
touch(path)
- # Create Dotiles object
+ # Create Dotfiles object
dotfiles = core.Dotfiles(
homedir=self.homedir, repository=self.repository,
prefix='', ignore=[], externals={}, packages=['package'],
@@ -232,6 +232,74 @@ class DotfilesTestCase(unittest.TestCase):
dotfiles.move(self.repository)
check_all(files, symlinks)
+ def test_missing_package(self):
+ """
+ Test a non-existent package.
+ """
+
+ package_file = '.package/bar'
+
+ # Create Dotfiles object
+ dotfiles = core.Dotfiles(
+ homedir=self.homedir, repository=self.repository,
+ prefix='', ignore=[], externals={}, packages=['package'],
+ dry_run=False)
+
+ path = os.path.join(self.homedir, package_file)
+ dirname = os.path.dirname(path)
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+ touch(path)
+
+ dotfiles.add([os.path.join(self.homedir, package_file)])
+
+
+ def test_single_sync(self):
+ """
+ Test syncing a single file in the repo
+
+ The following repo dir exists:
+
+ bashrc
+ netrc
+ vimrc
+
+ Syncing only vimrc should have the folowing sync result in home:
+
+ .vimrc -> Dotfiles/vimrc
+
+ """
+
+ # define the repository contents
+ repo_files = (
+ ('bashrc', False),
+ ('netrc', False),
+ ('vimrc', True))
+
+ # populate the repository
+ for dotfile, _ in repo_files:
+ touch(os.path.join(self.repository, dotfile))
+
+ dotfiles = core.Dotfiles(
+ homedir=self.homedir, repository=self.repository,
+ prefix='', ignore=[], externals={}, packages=[],
+ dry_run=False)
+
+ # sync only certain dotfiles
+ for dotfile, should_sync in repo_files:
+ if should_sync:
+ dotfiles.sync(files=['.%s' % dotfile])
+
+ # verify home directory contents
+ for dotfile, should_sync in repo_files:
+ if should_sync:
+ self.assertPathEqual(
+ os.path.join(self.repository, dotfile),
+ os.path.join(self.homedir, '.%s' % dotfile))
+ else:
+ self.assertFalse(os.path.exists(
+ os.path.join(self.homedir, dotfile)))
+
def suite():
suite = unittest.TestLoader().loadTestsFromTestCase(DotfilesTestCase)