mirror of
https://github.com/beetbox/beets.git
synced 2026-02-03 05:51:36 +01:00
Implement --pretend option for the move command
The method `show_path_changes` takes a list of tuples (source, destination) that will be printed on either single / double line, as proposed in #1405.
This commit is contained in:
parent
adebb850b5
commit
be484f2af0
5 changed files with 76 additions and 10 deletions
|
|
@ -615,6 +615,44 @@ def show_model_changes(new, old=None, fields=None, always=False):
|
|||
return bool(changes)
|
||||
|
||||
|
||||
def show_path_changes(path_changes):
|
||||
""" Given a list of tuples (source, destination) that indicate the path
|
||||
changes, the changes are shown. Output is guaranteed to be unicode.
|
||||
|
||||
Every tuple is shown on a single line if the terminal width permits it,
|
||||
else it is split over two lines. E.g.,
|
||||
|
||||
Source -> Destination
|
||||
|
||||
vs.
|
||||
|
||||
Source
|
||||
-> Destination
|
||||
"""
|
||||
sources, destinations = zip(*path_changes)
|
||||
|
||||
# Ensure unicode output
|
||||
sources = map(util.displayable_path, sources)
|
||||
destinations = map(util.displayable_path, destinations)
|
||||
|
||||
# Calculate widths for terminal split
|
||||
col_width = (term_width() - len(' -> ')) // 2
|
||||
max_width = len(max(sources + destinations, key=len))
|
||||
|
||||
if max_width > col_width:
|
||||
# Print every change over two lines
|
||||
for source, dest in zip(sources, destinations):
|
||||
log.info(u'{0} \n -> {1}', source, dest)
|
||||
else:
|
||||
# Print every change on a single line, and add a header
|
||||
title_pad = max_width - len('Source ') + len(' -> ')
|
||||
|
||||
log.info(u'Source {0} Destination', ' ' * title_pad)
|
||||
for source, dest in zip(sources, destinations):
|
||||
pad = max_width - len(source)
|
||||
log.info(u'{0} {1} -> {2}', source, ' ' * pad, dest)
|
||||
|
||||
|
||||
class CommonOptionsParser(optparse.OptionParser, object):
|
||||
"""Offers a simple way to add common formatting options.
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import re
|
|||
|
||||
import beets
|
||||
from beets import ui
|
||||
from beets.ui import print_, input_, decargs
|
||||
from beets.ui import print_, input_, decargs, show_path_changes
|
||||
from beets import autotag
|
||||
from beets.autotag import Recommendation
|
||||
from beets.autotag import hooks
|
||||
|
|
@ -1344,7 +1344,7 @@ default_commands.append(modify_cmd)
|
|||
|
||||
# move: Move/copy files to the library or a new base directory.
|
||||
|
||||
def move_items(lib, dest, query, copy, album):
|
||||
def move_items(lib, dest, query, copy, album, pretend):
|
||||
"""Moves or copies items to a new base directory, given by dest. If
|
||||
dest is None, then the library's base directory is used, making the
|
||||
command "consolidate" files.
|
||||
|
|
@ -1355,11 +1355,19 @@ def move_items(lib, dest, query, copy, album):
|
|||
action = 'Copying' if copy else 'Moving'
|
||||
entity = 'album' if album else 'item'
|
||||
log.info(u'{0} {1} {2}s.', action, len(objs), entity)
|
||||
for obj in objs:
|
||||
log.debug(u'moving: {0}', util.displayable_path(obj.path))
|
||||
if pretend:
|
||||
if album:
|
||||
show_path_changes([(item.path, item.destination(basedir=dest))
|
||||
for obj in objs for item in obj.items()])
|
||||
else:
|
||||
show_path_changes([(obj.path, obj.destination(basedir=dest))
|
||||
for obj in objs])
|
||||
else:
|
||||
for obj in objs:
|
||||
log.debug(u'moving: {0}', util.displayable_path(obj.path))
|
||||
|
||||
obj.move(copy, basedir=dest)
|
||||
obj.store()
|
||||
obj.move(copy, basedir=dest)
|
||||
obj.store()
|
||||
|
||||
|
||||
def move_func(lib, opts, args):
|
||||
|
|
@ -1369,7 +1377,7 @@ def move_func(lib, opts, args):
|
|||
if not os.path.isdir(dest):
|
||||
raise ui.UserError('no such directory: %s' % dest)
|
||||
|
||||
move_items(lib, dest, decargs(args), opts.copy, opts.album)
|
||||
move_items(lib, dest, decargs(args), opts.copy, opts.album, opts.pretend)
|
||||
|
||||
|
||||
move_cmd = ui.Subcommand(
|
||||
|
|
@ -1383,6 +1391,9 @@ move_cmd.parser.add_option(
|
|||
'-c', '--copy', default=False, action='store_true',
|
||||
help='copy instead of moving'
|
||||
)
|
||||
move_cmd.parser.add_option(
|
||||
'-p', '--pretend', default=False, action='store_true',
|
||||
help='show how files would be moved, but don\'t touch anything')
|
||||
move_cmd.parser.add_album_option()
|
||||
move_cmd.func = move_func
|
||||
default_commands.append(move_cmd)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ New features:
|
|||
This plugin is still in an experimental phase. :bug:`1450`
|
||||
* The :doc:`/plugins/fetchart` plugin will now complain for the `enforce_ratio`
|
||||
and `min_width` options if no local imaging backend is available. :bug:`1460`
|
||||
* The `move` command has a new `-p/--pretend` option, making the command show
|
||||
how the items will be moved, without modifying the files on disk.
|
||||
|
||||
|
||||
Fixes:
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ move
|
|||
````
|
||||
::
|
||||
|
||||
beet move [-ca] [-d DIR] QUERY
|
||||
beet move [-cap] [-d DIR] QUERY
|
||||
|
||||
Move or copy items in your library.
|
||||
|
||||
|
|
@ -255,6 +255,10 @@ destination directory with ``-d`` manually, you can move items matching a query
|
|||
anywhere in your filesystem. The ``-c`` option copies files instead of moving
|
||||
them. As with other commands, the ``-a`` option matches albums instead of items.
|
||||
|
||||
To perform a "dry run", just use the ``-p`` (for "pretend") flag. This will
|
||||
show you all how the files would be moved but won't actually change anything
|
||||
on disk.
|
||||
|
||||
.. _update-cmd:
|
||||
|
||||
update
|
||||
|
|
|
|||
|
|
@ -373,8 +373,9 @@ class MoveTest(_common.TestCase):
|
|||
# Alternate destination directory.
|
||||
self.otherdir = os.path.join(self.temp_dir, 'testotherdir')
|
||||
|
||||
def _move(self, query=(), dest=None, copy=False, album=False):
|
||||
commands.move_items(self.lib, dest, query, copy, album)
|
||||
def _move(self, query=(), dest=None, copy=False, album=False,
|
||||
pretend=False):
|
||||
commands.move_items(self.lib, dest, query, copy, album, pretend)
|
||||
|
||||
def test_move_item(self):
|
||||
self._move()
|
||||
|
|
@ -418,6 +419,16 @@ class MoveTest(_common.TestCase):
|
|||
self.assertExists(self.i.path)
|
||||
self.assertNotExists(self.itempath)
|
||||
|
||||
def test_pretend_move_item(self):
|
||||
self._move(dest=self.otherdir, pretend=True)
|
||||
self.i.load()
|
||||
self.assertIn('srcfile', self.i.path)
|
||||
|
||||
def test_pretend_move_album(self):
|
||||
self._move(album=True, pretend=True)
|
||||
self.i.load()
|
||||
self.assertIn('srcfile', self.i.path)
|
||||
|
||||
|
||||
class UpdateTest(_common.TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
|||
Loading…
Reference in a new issue