fix copying destination for full-album imports

This commit is contained in:
Adrian Sampson 2011-04-10 10:57:13 -07:00
parent e478ae740d
commit 11c5b15c8d
4 changed files with 70 additions and 13 deletions

View file

@ -385,7 +385,7 @@ class Item(object):
# Dealing with files themselves.
def move(self, library, copy=False):
def move(self, library, copy=False, in_album=False):
"""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
@ -393,6 +393,11 @@ class Item(object):
If copy is True, moving the file is copied rather than moved.
If in_album is True, then the track is treated as part of an
album even if it does not yet have an album_id associated with
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.
@ -400,7 +405,7 @@ class Item(object):
library.save() after this method in order to keep on-disk data
consistent.
"""
dest = library.destination(self)
dest = library.destination(self, in_album=in_album)
# Create necessary ancestry for the move.
_mkdirall(dest)
@ -908,14 +913,15 @@ class Library(BaseLibrary):
self.conn.executescript(setup_sql)
self.conn.commit()
def destination(self, item, pathmod=None):
def destination(self, item, pathmod=None, in_album=False):
"""Returns the path in the library directory designated for item
item (i.e., where the file ought to be).
item (i.e., where the file ought to be). in_album forces the
item to be treated as part of an album.
"""
pathmod = pathmod or os.path
# Use a path format based on the album type, if available.
if not item.album_id:
if not item.album_id and not in_album:
# Singleton track. Never use the "album" formats.
if 'singleton' in self.path_formats:
path_format = self.path_formats['singleton']

View file

@ -563,7 +563,7 @@ def apply_choices(lib, copy, write, art, delete, progress):
for item in task.items]
for item in task.items:
if copy:
item.move(lib, True)
item.move(lib, True, task.choice_flag != CHOICE_TRACKS)
if write and task.choice_flag == CHOICE_ALBUM:
item.write()
@ -621,7 +621,7 @@ def simple_import(lib, paths, copy, delete, resume):
if delete:
old_paths = [os.path.realpath(item.path) for item in task.items]
for item in task.items:
item.move(lib, True)
item.move(lib, True, True)
album = lib.add_album(task.items, True)
lib.save()

View file

@ -1,6 +1,7 @@
"""Some common functionality for beets' test cases."""
import time
import sys
import os
# Mangle the search path to include the beets sources.
sys.path.insert(0, '..')
@ -126,3 +127,15 @@ class DummyIO(object):
def restore(self):
sys.stdin = sys.__stdin__
sys.stdout = sys.__stdout__
# Mixin for additional assertions.
class ExtraAsserts(object):
def assertExists(self, path):
self.assertTrue(os.path.exists(path),
'file does not exist: %s' % path)
def assertNotExists(self, path):
self.assertFalse(os.path.exists(path),
'file exists: %s' % path)

View file

@ -130,15 +130,21 @@ class ImportTest(unittest.TestCase):
paths = self._run_import(['sometrack'], delete=True)
self.assertFalse(os.path.exists(paths[0]))
class ImportApplyTest(unittest.TestCase):
class ImportApplyTest(unittest.TestCase, _common.ExtraAsserts):
def setUp(self):
self.libdir = os.path.join('rsrc', 'testlibdir')
os.mkdir(self.libdir)
self.lib = library.Library(':memory:', self.libdir)
self.lib.path_formats = {
'default': 'one',
'comp': 'two',
'singleton': 'three',
}
self.srcpath = os.path.join(self.libdir, 'srcfile.mp3')
shutil.copy(os.path.join('rsrc', 'full.mp3'), self.srcpath)
self.i = library.Item.from_path(self.srcpath)
self.i.comp = False
trackinfo = {'title': 'one', 'artist': 'some artist',
'track': 1, 'length': 1, 'id': 'trackid'}
@ -155,24 +161,56 @@ class ImportApplyTest(unittest.TestCase):
def tearDown(self):
shutil.rmtree(self.libdir)
def call_apply(self, coro, items, info):
def _call_apply(self, coro, items, info):
task = commands.ImportTask(None, None, None)
task.set_choice((info, items))
coro.send(task)
def _call_apply_choice(self, coro, items, choice):
task = commands.ImportTask(None, None, items)
task.set_choice(choice)
coro.send(task)
def test_apply_no_delete(self):
coro = commands.apply_choices(self.lib, True, False, False,
False, False)
coro.next() # Prime coroutine.
self.call_apply(coro, [self.i], self.info)
self.assertTrue(os.path.exists(self.srcpath))
self._call_apply(coro, [self.i], self.info)
self.assertExists(self.srcpath)
def test_apply_with_delete(self):
coro = commands.apply_choices(self.lib, True, False, False,
True, False)
coro.next() # Prime coroutine.
self.call_apply(coro, [self.i], self.info)
self.assertFalse(os.path.exists(self.srcpath))
self._call_apply(coro, [self.i], self.info)
self.assertNotExists(self.srcpath)
def test_apply_asis_uses_album_path(self):
coro = commands.apply_choices(self.lib, True, False, False,
False, False)
coro.next() # Prime coroutine.
self._call_apply_choice(coro, [self.i], commands.CHOICE_ASIS)
self.assertExists(
os.path.join(self.libdir, self.lib.path_formats['default']+'.mp3')
)
def test_apply_match_uses_album_path(self):
coro = commands.apply_choices(self.lib, True, False, False,
False, False)
coro.next() # Prime coroutine.
self._call_apply(coro, [self.i], self.info)
self.assertExists(
os.path.join(self.libdir, self.lib.path_formats['default']+'.mp3')
)
def test_apply_as_tracks_uses_singleton_path(self):
coro = commands.apply_choices(self.lib, True, False, False,
False, False)
coro.next() # Prime coroutine.
self._call_apply_choice(coro, [self.i], commands.CHOICE_TRACKS)
self.assertExists(
os.path.join(self.libdir, self.lib.path_formats['singleton']+'.mp3')
)
class DuplicateCheckTest(unittest.TestCase):
def setUp(self):