def test_force_sync_directory_symlink(self): """Test a forced sync on a directory symlink. A bug was reported where a user wanted to replace a dotfile repository with an other one. They had a .vim directory in their home directory which was obviously also a symbolic link. This caused: OSError: Cannot call rmtree on a symbolic link """ # Create a dotfile symlink to some directory os.mkdir(os.path.join(self.homedir, 'vim')) os.symlink(os.path.join(self.homedir, 'vim'), os.path.join(self.homedir, '.vim')) # Create a vim directory in the repository. This will cause the above # symlink to be overwritten on sync. os.mkdir(os.path.join(self.repository, 'vim')) # Make sure the symlink points to the correct location. self.assertPathEqual( os.path.join(self.homedir, '.vim'), os.path.join(self.homedir, 'vim')) dotfiles = Dotfiles( homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=[], dry_run=False) dotfiles.sync(force=True) # The symlink should now point to the directory in the repository. self.assertPathEqual( os.path.join(self.homedir, '.vim'), os.path.join(self.repository, 'vim'))
def test_add_package_file(self): """ Test adding a package that isn't already in the repository """ package_dir = os.path.join(self.homedir, '.%s/%s' % ('config', 'gtk-3.0')) os.makedirs(package_dir) touch('%s/testfile' % package_dir) dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=['config'], dry_run=False) # This should succeed and the directory structure in the repository # should be created since it didn't already exist. dotfiles.add(['.config/gtk-3.0']) self.assertTrue( os.path.islink(os.path.join(self.homedir, '.config/gtk-3.0')))
def test_package_and_prefix(self): """Test syncing a package when using a non-default prefix.""" package_dir = os.path.join(self.repository, '.config/awesome') os.makedirs(package_dir) touch('%s/testfile' % package_dir) dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='.', ignore=[], externals={}, packages=['.config'], dry_run=False, quiet=True) dotfiles.sync() expected = os.path.join(self.homedir, ".config") self.assertTrue(os.path.isdir(expected)) expected = os.path.join(expected, "awesome") self.assertTrue(os.path.islink(expected)) expected = os.path.join(expected, "testfile") self.assertTrue(os.path.isfile(expected))
def test_add_package(self): """ Test adding a package that isn't already in the repository """ package_dir = os.path.join(self.homedir, '.%s/%s' % ('config', 'gtk-3.0')) os.makedirs(package_dir) touch('%s/testfile' % package_dir) dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=['config'], dry_run=False, quiet=True) # This should fail, you should not be able to add dotfiles that are # defined to be packages. dotfiles.add(['.config']) self.assertFalse(os.path.islink(os.path.join(self.homedir, '.config')))
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.repository, original)) dotfiles = Dotfiles( homedir=self.homedir, path=self.repository, prefix='', ignore=ignore, externals={}, packages=[], dry_run=False) 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.homedir)), sorted([f[1] for f in all_dotfiles] + ['Dotfiles'])) for original, symlink in all_dotfiles: self.assertPathEqual( os.path.join(self.repository, original), os.path.join(self.homedir, symlink))
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.repository, original)) dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=ignore, externals={}, packages=[], dry_run=False) 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.homedir)), sorted([f[1] for f in all_dotfiles] + ['Dotfiles'])) for original, symlink in all_dotfiles: self.assertPathEqual( os.path.join(self.repository, original), os.path.join(self.homedir, symlink))
def test_packages(self): """ Test packages. """ files = ['foo', 'package/bar'] symlinks = ['.foo', '.package/bar'] join = os.path.join # Create files for filename in files: path = join(self.repository, filename) dirname = os.path.dirname(path) if not os.path.exists(dirname): os.makedirs(dirname) touch(path) # Create Dotfiles object dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=['package'], dry_run=False) # Create symlinks in homedir dotfiles.sync() # Verify it created what we expect def check_all(files, symlinks): self.assertTrue(os.path.isdir(join(self.homedir, '.package'))) for src, dst in zip(files, symlinks): self.assertTrue( is_link_to(join(self.homedir, dst), join(self.repository, src))) check_all(files, symlinks) # Add files to the repository new_files = [join(self.homedir, f) for f in ['.bar', '.package/foo']] for filename in new_files: path = join(self.homedir, filename) touch(path) new_repo_files = ['bar', 'package/foo'] dotfiles.add(new_files) check_all(files + new_repo_files, symlinks + new_files) # Remove them from the repository dotfiles.remove(new_files) check_all(files, symlinks) # Move the repository self.repository = join(self.homedir, 'Dotfiles2') dotfiles.move(self.repository) check_all(files, symlinks)
def test_packages(self): """ Test packages. """ files = ['foo', 'package/bar', 'package2/foo/bar'] symlinks = ['.foo', '.package/bar', '.package2/foo/bar'] join = os.path.join # Create files for filename in files: path = join(self.repository, filename) dirname = os.path.dirname(path) if not os.path.exists(dirname): os.makedirs(dirname) touch(path) # Create Dotfiles object dotfiles = Dotfiles( homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=set(['package', 'package2/foo']), dry_run=False) # Create symlinks in homedir dotfiles.sync() # Verify it created what we expect for folder in ['.package', '.package2', '.package2/foo']: self.assertTrue(os.path.isdir(join(self.homedir, folder))) def check_all(files, symlinks): for src, dst in zip(files, symlinks): self.assertTrue(is_link_to(join(self.homedir, dst), join(self.repository, src))) check_all(files, symlinks) # Add files to the repository new_files = [join(self.homedir, f) for f in ['.bar', '.package/foo', '.package2/foo/bar2']] for filename in new_files: path = join(self.homedir, filename) touch(path) new_repo_files = ['bar', 'package/foo', 'package2/foo/bar2'] dotfiles.add(new_files) check_all(files + new_repo_files, symlinks + new_files) # Remove them from the repository dotfiles.remove(new_files) check_all(files, symlinks) # Move the repository self.repository = join(self.homedir, 'Dotfiles2') dotfiles.move(self.repository) check_all(files, symlinks)
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 = Dotfiles( homedir=self.homedir, path=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 test_missing_package(self): """ Test a non-existent package. """ package_file = '.package/bar' # Create Dotfiles object dotfiles = Dotfiles(homedir=self.homedir, path=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_no_dot_prefix(self): # define the repository contents repo_files = ('bashrc', 'netrc', 'vimrc') # populate the repository for dotfile in repo_files: touch(os.path.join(self.repository, dotfile)) dotfiles = Dotfiles( homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=[], dry_run=False, no_dot_prefix=True) dotfiles.sync() # verify home directory contents for dotfile in repo_files: self.assertPathEqual( os.path.join(self.repository, dotfile), os.path.join(self.homedir, dotfile))
def test_add_package(self): """ Test adding a package that isn't already in the repository """ package_dir = os.path.join(self.homedir, '.%s/%s' % ('config', 'gtk-3.0')) os.makedirs(package_dir) touch('%s/testfile' % package_dir) dotfiles = Dotfiles( homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=['config'], dry_run=False, quiet=True) # This should fail, you should not be able to add dotfiles that are # defined to be packages. dotfiles.add(['.config']) self.assertFalse(os.path.islink(os.path.join(self.homedir, '.config')))
def test_add_package_file(self): """ Test adding a package that isn't already in the repository """ package_dir = os.path.join(self.homedir, '.%s/%s' % ('config', 'gtk-3.0')) os.makedirs(package_dir) touch('%s/testfile' % package_dir) dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=['config'], dry_run=False) # This should succeed and the directory structure in the repository # should be created since it didn't already exist. df = os.path.join(self.homedir, '.config/gtk-3.0') dotfiles.add([df]) self.assertTrue(os.path.islink(df))
def test_missing_remove(self): """Test removing a dotfile that's been removed from the repository.""" repo_file = os.path.join(self.repository, 'testdotfile') touch(repo_file) dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=[], dry_run=False) dotfiles.sync() # remove the dotfile from the repository, homedir symlink is now broken os.remove(repo_file) # remove the broken symlink dotfiles.remove(['.testdotfile']) # verify symlink was removed self.assertFalse( os.path.exists(os.path.join(self.homedir, '.testdotfile')))
def test_move_repository(self): """Test the move() method for a Dotfiles repository.""" touch(os.path.join(self.repository, 'bashrc')) dotfiles = Dotfiles( homedir=self.homedir, path=self.repository, prefix='', ignore=[], force=True, externals={}, packages=[], dry_run=False) dotfiles.sync() # Make sure sync() did the right thing. self.assertPathEqual( os.path.join(self.homedir, '.bashrc'), os.path.join(self.repository, 'bashrc')) target = os.path.join(self.homedir, 'MyDotfiles') dotfiles.move(target) self.assertTrue(os.path.exists(os.path.join(target, 'bashrc'))) self.assertPathEqual( os.path.join(self.homedir, '.bashrc'), os.path.join(target, 'bashrc'))
def test_missing_remove(self): """Test removing a dotfile that's been removed from the repository.""" repo_file = os.path.join(self.repository, 'testdotfile') touch(repo_file) dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=[], dry_run=False) dotfiles.sync() # remove the dotfile from the repository, homedir symlink is now broken os.remove(repo_file) # remove the broken symlink dotfiles.remove(['.testdotfile']) # verify symlink was removed self.assertFalse(os.path.exists( os.path.join(self.homedir, '.testdotfile')))
def test_force_sync_directory(self): """Test forced sync when the dotfile is a directory. I installed the lastpass chrome extension which stores a socket in ~/.lastpass. So I added that directory as an external to /tmp and attempted a forced sync. An error occurred because sync() calls os.remove() as it mistakenly assumes the dotfile is a file and not a directory. """ os.mkdir(os.path.join(self.homedir, '.lastpass')) externals = {'.lastpass': '******'} dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals=externals, packages=[], dry_run=False) dotfiles.sync(force=True) self.assertPathEqual( os.path.join(self.homedir, '.lastpass'), '/tmp')
def test_hosts_mode(self): """Test that host mode behaves correctly.""" all_repo_files = ( ('.vimrc', 'all'), ('.mozilla', 'guiworkstation'), ) for homefile, host in all_repo_files: touch(os.path.join(self.homedir, homefile)) os.makedirs(os.path.join(self.repository, 'all.host')) dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=[], dry_run=False) self.assertTrue(dotfiles.hosts_mode()) for homefile, host in all_repo_files: dotfiles.add([os.path.join(self.homedir, homefile)], host) self.verifyFileStatus(homefile, host) for homefile, host in all_repo_files: os.unlink(os.path.join(self.homedir, homefile)) dotfiles._load() dotfiles.sync() self.verifyFileStatus('.vimrc', 'all') self.assertTrue(not os.path.exists(os.path.join(self.homedir, '.mozilla'))) dotfiles._load() dotfiles.sync(hostname='guiworkstation') self.assertTrue(os.path.exists(os.path.join(self.homedir, '.mozilla'))) dotfiles._load() dotfiles.remove([os.path.join(self.homedir, '.mozilla')], 'guiworkstation') dotfiles._load() dotfiles.sync(hostname='guiworkstation') self.verifyFileStatus('.vimrc', 'all') self.assertTrue(not os.path.islink(os.path.join(self.homedir, '.mozilla')))
def test_dotdir_file_add_sync_remove(self): """Test that is is possible to add files in dot-directories and that they are managed correctly. This is especially usefull for applications that mix state files and configuration files in their dot-directory, for instance : - .unison which contains *prf and state files - .lftp which contains rc (conf file) and log, cwd_history. """ os.mkdir(os.path.join(self.homedir, '.unison')) os.mkdir(os.path.join(self.homedir, '.lftp')) all_repo_files = ( ('.vimrc', True), ('.unison/home.prf', True), ('.unison/are8d491ed362b0a4cf3e8d77ef3e08a1c', False), ('.unison/fpe8d491ed362b0a4cf3e8d77ef3e08a1c', False), ('.lftp/log', False), ('.lftp/rc', True), ('.lftp/cwd_history', False), ) repo_dir = '.ikiwiki' for homefile, in_repository in all_repo_files: touch(os.path.join(self.homedir, homefile)) os.mkdir(os.path.join(self.homedir, repo_dir)) dotfiles = Dotfiles(homedir=self.homedir, path=self.repository, prefix='', ignore=[], externals={}, packages=[], dry_run=False) dotfiles.add([os.path.join(self.homedir, homefile) for homefile, in_repo in all_repo_files if in_repo]) for homefile, in_repository in all_repo_files: if in_repository: self.verifyFileStatus(homefile) for dotdir in ('.unison', '.lftp'): homepath = os.path.join(self.homedir, dotdir) self.assertTrue(not os.path.islink(homepath)) self.assertTrue(os.path.isdir(homepath)) os.unlink(os.path.join(self.homedir, '.vimrc')) os.unlink(os.path.join(self.homedir, '.lftp/rc')) os.unlink(os.path.join(self.homedir, '.unison/home.prf')) touch(os.path.join(self.homedir, '.unison/home.prf')) dotfiles._load() # refresh file states dotfiles.sync() for homefile in ('.vimrc', '.lftp/rc'): self.verifyFileStatus(homefile) self.assertTrue(not os.path.islink(os.path.join(self.homedir, '.unison/home.prf'))) self.assertTrue(os.path.isfile(os.path.join(self.homedir, '.unison/home.prf'))) dotfiles._load() # refresh file states dotfiles.sync(force=True) self.verifyFileStatus('.unison/home.prf') dotfiles.remove([os.path.join(self.homedir, '.lftp/rc')]) self.assertTrue(not os.path.islink(os.path.join(self.homedir, '.lftp/rc'))) self.assertTrue(os.path.isfile(os.path.join(self.homedir, '.lftp/rc')))