aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS.rst1
-rw-r--r--HISTORY.rst5
-rw-r--r--README.rst11
-rw-r--r--dotfiles/__init__.py2
-rw-r--r--dotfiles/core.py20
-rwxr-xr-xtest_dotfiles.py82
6 files changed, 95 insertions, 26 deletions
diff --git a/AUTHORS.rst b/AUTHORS.rst
index 4bdcc0b..a183cc8 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -10,3 +10,4 @@ Patches and Suggestions
```````````````````````
- Anaƫl Beutot
+- Remco Wendt <remco@maykinmedia.nl>
diff --git a/HISTORY.rst b/HISTORY.rst
index 64c4346..e69970c 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,6 +1,11 @@
History
-------
+0.4.3
++++++
+
+* Add glob style pattern support for the ignore option
+
0.4.2
+++++
diff --git a/README.rst b/README.rst
index d717ff9..7546373 100644
--- a/README.rst
+++ b/README.rst
@@ -81,7 +81,8 @@ example configuration file might look like: ::
repository = ~/Dotfiles
ignore = [
'.git',
- '.gitignore']
+ '.gitignore',
+ '*.swp']
externals = {
'.bzr.log': '/dev/null',
'.uml': '/tmp'}
@@ -124,9 +125,11 @@ I have the following in my ``~/.dotfilesrc``: ::
[dotfiles]
ignore = [
'.git',
- '.gitignore']
+ '.gitignore',
+ '*.swp]
-Any file you list in ``ignore`` will be skipped.
+Any file you list in ``ignore`` will be skipped. The ``ignore`` option supports
+glob file patterns.
License
-------
@@ -156,4 +159,4 @@ changes to the **develop** branch (or branch off of it), and send a pull
request. Make sure you add yourself to AUTHORS_.
.. _`the repository`: https://github.com/jbernard/dotfiles
-.. _AUTHORS: https://github.com/jbernard/dotfiles/blob/master/AUTHORS
+.. _AUTHORS: https://github.com/jbernard/dotfiles/blob/master/AUTHORS.rst
diff --git a/dotfiles/__init__.py b/dotfiles/__init__.py
index fcb882b..63e0d2b 100644
--- a/dotfiles/__init__.py
+++ b/dotfiles/__init__.py
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
-from core import *
+from .core import *
diff --git a/dotfiles/core.py b/dotfiles/core.py
index f3241c9..60bfc1e 100644
--- a/dotfiles/core.py
+++ b/dotfiles/core.py
@@ -9,9 +9,10 @@ This module provides the basic functionality of dotfiles.
import os
import shutil
+import fnmatch
-__version__ = '0.4.2'
+__version__ = '0.4.3'
__author__ = "Jon Bernard"
__license__ = "GPL"
@@ -78,27 +79,30 @@ class Dotfiles(object):
self._load()
-
def _load(self):
"""Load each dotfile in the repository."""
self.dotfiles = list()
- for dotfile in list(x for x in os.listdir(self.repo) if x not in self.ignore):
+ all_repofiles = os.listdir(self.repo)
+ repofiles_to_symlink = set(all_repofiles)
+
+ for pat in self.ignore:
+ repofiles_to_symlink.difference_update(fnmatch.filter(all_repofiles, pat))
+
+ for dotfile in repofiles_to_symlink:
self.dotfiles.append(Dotfile(dotfile[len(self.prefix):],
os.path.join(self.repo, dotfile), self.home))
for dotfile in self.externals.keys():
self.dotfiles.append(Dotfile(dotfile, self.externals[dotfile], self.home))
-
def _fqpn(self, dotfile):
"""Return the fully qualified path to a dotfile."""
return os.path.join(self.repo,
self.prefix + os.path.basename(dotfile).strip('.'))
-
def list(self, verbose=True):
"""List the contents of this repository."""
@@ -106,13 +110,11 @@ class Dotfiles(object):
if dotfile.status or verbose:
print dotfile
-
def check(self):
"""List only unmanaged and/or missing dotfiles."""
self.list(verbose=False)
-
def sync(self, force=False):
"""Synchronize this repository, creating and updating the necessary
@@ -121,19 +123,16 @@ class Dotfiles(object):
for dotfile in self.dotfiles:
dotfile.sync(force)
-
def add(self, files):
"""Add dotfile(s) to the repository."""
self._perform_action('add', files)
-
def remove(self, files):
"""Remove dotfile(s) from the repository."""
self._perform_action('remove', files)
-
def _perform_action(self, action, files):
for file in files:
if os.path.basename(file).startswith('.'):
@@ -141,7 +140,6 @@ class Dotfiles(object):
else:
print "Skipping \"%s\", not a dotfile" % file
-
def move(self, target):
"""Move the repository to another location."""
diff --git a/test_dotfiles.py b/test_dotfiles.py
index bb54578..f9d6fcf 100755
--- a/test_dotfiles.py
+++ b/test_dotfiles.py
@@ -30,6 +30,11 @@ class DotfilesTestCase(unittest.TestCase):
shutil.rmtree(self.home)
+ def assertPathEqual(self, path1, path2):
+ self.assertEqual(
+ os.path.realpath(path1),
+ os.path.realpath(path2))
+
def test_force_sync_directory(self):
"""Test forced sync when the dotfile is a directory.
@@ -48,8 +53,9 @@ class DotfilesTestCase(unittest.TestCase):
dotfiles.sync(force=True)
- self.assertEqual(
- os.path.realpath(os.path.join(self.home, '.lastpass')), '/tmp')
+ self.assertPathEqual(
+ os.path.join(self.home, '.lastpass'),
+ '/tmp')
def test_move_repository(self):
"""Test the move() method for a Dotfiles repository."""
@@ -63,8 +69,8 @@ class DotfilesTestCase(unittest.TestCase):
dotfiles.sync()
# Make sure sync() did the right thing.
- self.assertEqual(
- os.path.realpath(os.path.join(self.home, '.bashrc')),
+ self.assertPathEqual(
+ os.path.join(self.home, '.bashrc'),
os.path.join(self.repo, 'bashrc'))
target = os.path.join(self.home, 'MyDotfiles')
@@ -72,8 +78,8 @@ class DotfilesTestCase(unittest.TestCase):
dotfiles.move(target)
self.assertTrue(os.path.exists(os.path.join(target, 'bashrc')))
- self.assertEqual(
- os.path.realpath(os.path.join(self.home, '.bashrc')),
+ self.assertPathEqual(
+ os.path.join(self.home, '.bashrc'),
os.path.join(target, 'bashrc'))
def test_sync_unmanaged_directory_symlink(self):
@@ -96,8 +102,8 @@ class DotfilesTestCase(unittest.TestCase):
os.mkdir(os.path.join(self.repo, 'vim'))
# Make sure the symlink points to the correct location.
- self.assertEqual(
- os.path.realpath(os.path.join(self.home, '.vim')),
+ self.assertPathEqual(
+ os.path.join(self.home, '.vim'),
os.path.join(self.home, 'vim'))
dotfiles = core.Dotfiles(
@@ -107,10 +113,66 @@ class DotfilesTestCase(unittest.TestCase):
dotfiles.sync(force=True)
# The symlink should now point to the directory in the repository.
- self.assertEqual(
- os.path.realpath(os.path.join(self.home, '.vim')),
+ self.assertPathEqual(
+ os.path.join(self.home, '.vim'),
os.path.join(self.repo, 'vim'))
+ def test_glob_ignore_pattern(self):
+ """ Test that the use of glob pattern matching works in the ignores list.
+
+ The following repo dir exists:
+
+ myscript.py
+ myscript.pyc
+ myscript.pyo
+ bashrc
+ bashrc.swp
+ vimrc
+ vimrc.swp
+ install.sh
+
+ Using the glob pattern dotfiles should have the following sync result in home:
+
+ .myscript.py -> Dotfiles/myscript.py
+ .bashrc -> Dotfiles/bashrc
+ .vimrc -> Dotfiles/vimrc
+
+ """
+ ignore = ['*.swp', '*.py?', 'install.sh']
+
+ all_repo_files = (
+ ('myscript.py', '.myscript.py'),
+ ('myscript.pyc', None),
+ ('myscript.pyo', None),
+ ('bashrc', '.bashrc'),
+ ('bashrc.swp', None),
+ ('vimrc', '.vimrc'),
+ ('vimrc.swp', None),
+ ('install.sh', None)
+ )
+
+ all_dotfiles = [f for f in all_repo_files if f[1] is not None]
+
+ for original, symlink in all_repo_files:
+ touch(os.path.join(self.repo, original))
+
+ dotfiles = core.Dotfiles(
+ home=self.home, repo=self.repo, prefix='',
+ ignore=ignore, externals={})
+
+ dotfiles.sync()
+
+ # Now check that the files that should have a symlink
+ # point to the correct file and are the only files that
+ # exist in the home dir.
+ self.assertEqual(
+ sorted(os.listdir(self.home)),
+ sorted([f[1] for f in all_dotfiles] + ['Dotfiles']))
+
+ for original, symlink in all_dotfiles:
+ self.assertPathEqual(
+ os.path.join(self.repo, original),
+ os.path.join(self.home, symlink))
def suite():
suite = unittest.TestLoader().loadTestsFromTestCase(DotfilesTestCase)