destination option for "beet move" (also tests)

This commit is contained in:
Adrian Sampson 2011-08-05 12:19:34 -07:00
parent 99b7cb8854
commit 45eeea343e
4 changed files with 126 additions and 14 deletions

View file

@ -212,7 +212,7 @@ class Item(object):
# Dealing with files themselves.
def move(self, library, copy=False, in_album=False):
def move(self, library, copy=False, in_album=False, basedir=None):
"""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
@ -225,14 +225,17 @@ class Item(object):
it. (This allows items to be moved before they are added to the
database, a performance optimization.)
Passes on appropriate exceptions if directories cannot be created
or moving/copying fails.
basedir overrides the library base directory for the
destination.
Passes on appropriate exceptions if directories cannot be
created or moving/copying fails.
Note that one should almost certainly call store() and
library.save() after this method in order to keep on-disk data
consistent.
"""
dest = library.destination(self, in_album=in_album)
dest = library.destination(self, in_album=in_album, basedir=basedir)
# Create necessary ancestry for the move.
util.mkdirall(dest)
@ -793,13 +796,15 @@ class Library(BaseLibrary):
self.conn.executescript(setup_sql)
self.conn.commit()
def destination(self, item, pathmod=None, in_album=False, fragment=False):
def destination(self, item, pathmod=None, in_album=False,
fragment=False, basedir=None):
"""Returns the path in the library directory designated for item
item (i.e., where the file ought to be). in_album forces the
item to be treated as part of an album. fragment makes this
method return just the path fragment underneath the root library
directory; the path is also returned as Unicode instead of
encoded as a bytestring.
encoded as a bytestring. basedir can override the library's base
directory for the destination.
"""
pathmod = pathmod or os.path
@ -859,7 +864,8 @@ class Library(BaseLibrary):
if fragment:
return subpath
else:
return normpath(os.path.join(self.directory, subpath))
basedir = basedir or self.directory
return normpath(os.path.join(basedir, subpath))
# Main interface.
@ -1154,14 +1160,17 @@ class Album(BaseAlbum):
(self.id,)
)
def move(self, copy=False):
def move(self, copy=False, basedir=None):
"""Moves (or copies) all items to their destination. Any
album art moves along with them.
album art moves along with them. basedir overrides the library
base directory for the destination.
"""
basedir = basedir or self._library.directory
# Move items.
items = list(self.items())
for item in items:
item.move(self._library, copy)
item.move(self._library, copy, basedir=basedir)
newdir = os.path.dirname(items[0].path)
# Move art.

View file

@ -958,13 +958,13 @@ def move_items(lib, dest, query, copy, album):
entity = 'album' if album else 'item'
logging.info('%s %i %ss.' % (action, len(objs), entity))
for obj in objs:
old_path = obj.item_path() if album else obj.path
old_path = obj.item_dir() if album else obj.path
logging.debug('moving: %s' % old_path)
if album:
obj.move(copy)
obj.move(copy, basedir=dest)
else:
obj.move(lib, copy)
obj.move(lib, copy, basedir=dest)
lib.store(obj)
lib.save()

View file

@ -45,17 +45,25 @@ class MoveTest(unittest.TestCase, _common.ExtraAsserts):
self.i.album = 'two'
self.i.title = 'three'
self.dest = join(self.libdir, 'one', 'two', 'three.mp3')
self.otherdir = join(_common.RSRC, 'testotherdir')
def tearDown(self):
if os.path.exists(self.path):
os.remove(self.path)
if os.path.exists(self.libdir):
shutil.rmtree(self.libdir)
if os.path.exists(self.otherdir):
shutil.rmtree(self.otherdir)
def test_move_arrives(self):
self.i.move(self.lib)
self.assertExists(self.dest)
def test_move_to_custom_dir(self):
self.i.move(self.lib, basedir=self.otherdir)
self.assertExists(join(self.otherdir, 'one', 'two', 'three.mp3'))
def test_move_departs(self):
self.i.move(self.lib)
self.assertNotExists(self.path)
@ -148,9 +156,13 @@ class AlbumFileTest(unittest.TestCase):
touch(self.i.path)
# Make an album.
self.ai = self.lib.add_album((self.i,))
# Alternate destination dir.
self.otherdir = os.path.join(_common.RSRC, 'testotherdir')
def tearDown(self):
if os.path.exists(self.libdir):
shutil.rmtree(self.libdir)
if os.path.exists(self.otherdir):
shutil.rmtree(self.otherdir)
def test_albuminfo_move_changes_paths(self):
self.ai.album = 'newAlbumName'
@ -177,7 +189,12 @@ class AlbumFileTest(unittest.TestCase):
self.assertTrue(os.path.exists(oldpath))
self.assertTrue(os.path.exists(self.i.path))
class ArtFileTest(unittest.TestCase):
def test_albuminfo_move_to_custom_dir(self):
self.ai.move(basedir=self.otherdir)
self.lib.load(self.i)
self.assert_('testotherdir' in self.i.path)
class ArtFileTest(unittest.TestCase, _common.ExtraAsserts):
def setUp(self):
# Make library and item.
self.lib = beets.library.Library(':memory:')
@ -194,9 +211,13 @@ class ArtFileTest(unittest.TestCase):
self.art = self.lib.get_album(self.i).art_destination('something.jpg')
touch(self.art)
self.ai.artpath = self.art
# Alternate destination dir.
self.otherdir = os.path.join(_common.RSRC, 'testotherdir')
def tearDown(self):
if os.path.exists(self.libdir):
shutil.rmtree(self.libdir)
if os.path.exists(self.otherdir):
shutil.rmtree(self.otherdir)
def test_art_deleted_when_items_deleted(self):
self.assertTrue(os.path.exists(self.art))
@ -215,6 +236,17 @@ class ArtFileTest(unittest.TestCase):
newart = self.lib.get_album(self.i).art_destination(self.art)
self.assertTrue(os.path.exists(newart))
def test_art_moves_with_album_to_custom_dir(self):
# Move the album to another directory.
self.ai.move(basedir=self.otherdir)
self.lib.load(self.i)
# Art should be in new directory.
self.assertNotExists(self.art)
newart = self.lib.get_album(self.i).artpath
self.assertExists(newart)
self.assertTrue('testotherdir' in newart)
def test_setart_copies_image(self):
newart = os.path.join(self.libdir, 'newart.jpg')
touch(newart)

View file

@ -199,6 +199,77 @@ class ModifyTest(unittest.TestCase):
item.read()
self.assertFalse('newAlbum' in item.path)
class MoveTest(unittest.TestCase, _common.ExtraAsserts):
def setUp(self):
self.io = _common.DummyIO()
self.io.install()
self.libdir = os.path.join(_common.RSRC, 'testlibdir')
os.mkdir(self.libdir)
self.itempath = os.path.join(self.libdir, 'srcfile')
shutil.copy(os.path.join(_common.RSRC, 'full.mp3'), self.itempath)
# Add a file to the library but don't copy it in yet.
self.lib = library.Library(':memory:', self.libdir)
self.i = library.Item.from_path(self.itempath)
self.lib.add(self.i, False)
self.album = self.lib.add_album([self.i])
# Alternate destination directory.
self.otherdir = os.path.join(_common.RSRC, 'testotherdir')
def tearDown(self):
self.io.restore()
shutil.rmtree(self.libdir)
if os.path.exists(self.otherdir):
shutil.rmtree(self.otherdir)
def _move(self, query=(), dest=None, copy=False, album=False):
commands.move_items(self.lib, dest, query, copy, album)
def test_move_item(self):
self._move()
self.lib.load(self.i)
self.assertTrue('testlibdir' in self.i.path)
self.assertExists(self.i.path)
self.assertNotExists(self.itempath)
def test_copy_item(self):
self._move(copy=True)
self.lib.load(self.i)
self.assertTrue('testlibdir' in self.i.path)
self.assertExists(self.i.path)
self.assertExists(self.itempath)
def test_move_album(self):
self._move(album=True)
self.lib.load(self.i)
self.assertTrue('testlibdir' in self.i.path)
self.assertExists(self.i.path)
self.assertNotExists(self.itempath)
def test_copy_album(self):
self._move(copy=True, album=True)
self.lib.load(self.i)
self.assertTrue('testlibdir' in self.i.path)
self.assertExists(self.i.path)
self.assertExists(self.itempath)
def test_move_item_custom_dir(self):
self._move(dest=self.otherdir)
self.lib.load(self.i)
self.assertTrue('testotherdir' in self.i.path)
self.assertExists(self.i.path)
self.assertNotExists(self.itempath)
def test_move_album_custom_dir(self):
self._move(dest=self.otherdir, album=True)
self.lib.load(self.i)
self.assertTrue('testotherdir' in self.i.path)
self.assertExists(self.i.path)
self.assertNotExists(self.itempath)
class UpdateTest(unittest.TestCase, _common.ExtraAsserts):
def setUp(self):
self.io = _common.DummyIO()