diff options
-rw-r--r-- | AUTHORS.rst | 1 | ||||
-rw-r--r-- | HISTORY.rst | 5 | ||||
-rw-r--r-- | README.rst | 11 | ||||
-rw-r--r-- | dotfiles/__init__.py | 2 | ||||
-rw-r--r-- | dotfiles/core.py | 20 | ||||
-rwxr-xr-x | test_dotfiles.py | 82 |
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 +++++ @@ -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) |