diff --git a/beets/importer.py b/beets/importer.py index 526ac495b9..16a2b123b7 100644 --- a/beets/importer.py +++ b/beets/importer.py @@ -215,8 +215,8 @@ def set_config(self, config): iconfig['copy'] = False iconfig['link'] = False elif iconfig['link']: + iconfig['copy'] = False iconfig['move'] = False - iconfig['link'] = False # Only delete when copying. if not iconfig['copy']: diff --git a/beets/library.py b/beets/library.py index d20ecb0672..5c702c053e 100644 --- a/beets/library.py +++ b/beets/library.py @@ -580,13 +580,14 @@ def remove(self, delete=False, with_album=True): self._db._memotable = {} - def move(self, copy=False, basedir=None, with_album=True): + def move(self, copy=False, link=False, basedir=None, with_album=True): """Move the item to its designated location within the library directory (provided by destination()). Subdirectories are created as needed. If the operation succeeds, the item's path field is updated to reflect the new location. - If copy is True, moving the file is copied rather than moved. + If `copy` is true, moving the file is copied rather than moved. + Similarly, `link` creates a symlink instead. basedir overrides the library base directory for the destination. @@ -608,7 +609,7 @@ def move(self, copy=False, basedir=None, with_album=True): # Perform the move and store the change. old_path = self.path - self.move_file(dest, copy) + self.move_file(dest, copy, link) self.store() # If this item is in an album, move its art. @@ -846,7 +847,7 @@ def move_art(self, copy=False, link=False): util.prune_dirs(os.path.dirname(old_art), self._db.directory) - def move(self, copy=False, basedir=None): + def move(self, copy=False, link=False, basedir=None): """Moves (or copies) all items to their destination. Any album art moves along with them. basedir overrides the library base directory for the destination. The album is stored to the @@ -861,10 +862,10 @@ def move(self, copy=False, basedir=None): # Move items. items = list(self.items()) for item in items: - item.move(copy, basedir=basedir, with_album=False) + item.move(copy, link, basedir=basedir, with_album=False) # Move art. - self.move_art(copy) + self.move_art(copy, link) self.store() def item_dir(self): diff --git a/test/test_files.py b/test/test_files.py index 1eb54ffa38..272a33fe76 100644 --- a/test/test_files.py +++ b/test/test_files.py @@ -121,6 +121,20 @@ def test_move_avoids_collision_with_existing_file(self): self.assertEqual(os.path.dirname(self.i.path), os.path.dirname(dest)) + def test_link_arrives(self): + self.i.move(link=True) + self.assertExists(self.dest) + self.assertTrue(os.path.islink(self.dest)) + self.assertEqual(os.readlink(self.dest), self.path) + + def test_link_does_not_depart(self): + self.i.move(link=True) + self.assertExists(self.path) + + def test_link_changes_path(self): + self.i.move(link=True) + self.assertEqual(self.i.path, util.normpath(self.dest)) + class HelperTest(_common.TestCase): def test_ancestry_works_on_file(self): diff --git a/test/test_importer.py b/test/test_importer.py index feafad923c..4058e3ef6b 100644 --- a/test/test_importer.py +++ b/test/test_importer.py @@ -39,10 +39,10 @@ class AutotagStub(object): autotagger returns. """ - NONE = 'NONE' - IDENT = 'IDENT' - GOOD = 'GOOD' - BAD = 'BAD' + NONE = 'NONE' + IDENT = 'IDENT' + GOOD = 'GOOD' + BAD = 'BAD' MISSING = 'MISSING' """Generate an album match for all but one track """ @@ -196,7 +196,7 @@ def _create_import_dir(self, count=3): def _setup_import_session(self, import_dir=None, delete=False, threaded=False, copy=True, singletons=False, - move=False, autotag=True): + move=False, autotag=True, link=False): config['import']['copy'] = copy config['import']['delete'] = delete config['import']['timid'] = True @@ -205,6 +205,7 @@ def _setup_import_session(self, import_dir=None, delete=False, config['import']['move'] = move config['import']['autotag'] = autotag config['import']['resume'] = False + config['import']['link'] = link self.importer = TestImportSession( self.lib, logfile=None, query=None, @@ -321,6 +322,18 @@ def test_import_with_delete_prunes_directory_empty(self): self.importer.run() self.assertNotExists(os.path.join(self.import_dir, 'the_album')) + def test_import_link_arrives(self): + config['import']['link'] = True + self.importer.run() + for mediafile in self.import_media: + filename = os.path.join( + self.libdir, + 'Tag Artist', 'Tag Album', '%s.mp3' % mediafile.title + ) + self.assertExists(filename) + self.assertTrue(os.path.islink(filename)) + self.assertEqual(os.readlink(filename), mediafile.path) + class ImportZipTest(unittest.TestCase, ImportHelper): @@ -806,7 +819,7 @@ def tearDown(self): def test_add_album_for_different_artist_and_different_album(self): self.import_media[0].artist = "Artist B" - self.import_media[0].album = "Album B" + self.import_media[0].album = "Album B" self.import_media[0].save() self.importer.run() @@ -826,7 +839,7 @@ def test_add_album_for_different_artist_and_same_albumartist(self): self.assertEqual(artists, set(['Album Artist', 'Tag Artist'])) def test_add_album_for_same_artist_and_different_album(self): - self.import_media[0].album = "Album B" + self.import_media[0].album = "Album B" self.import_media[0].save() self.importer.run() @@ -834,7 +847,7 @@ def test_add_album_for_same_artist_and_different_album(self): self.assertEqual(albums, set(['Album B', 'Tag Album'])) def test_add_album_for_same_album_and_different_artist(self): - self.import_media[0].artist = "Artist B" + self.import_media[0].artist = "Artist B" self.import_media[0].save() self.importer.run() @@ -843,7 +856,7 @@ def test_add_album_for_same_album_and_different_artist(self): def test_incremental(self): config['import']['incremental'] = True - self.import_media[0].album = "Album B" + self.import_media[0].album = "Album B" self.import_media[0].save() self.importer.run()