59
59
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
62
def tree_files(file_list, default_branch=u'.'):
62
def tree_files(file_list, default_branch=u'.', canonicalize=True):
64
return internal_tree_files(file_list, default_branch)
64
return internal_tree_files(file_list, default_branch, canonicalize)
65
65
except errors.FileInWrongBranch, e:
66
66
raise errors.BzrCommandError("%s is not in the same branch as %s" %
67
67
(e.path, file_list[0]))
87
87
# XXX: Bad function name; should possibly also be a class method of
88
88
# WorkingTree rather than a function.
89
def internal_tree_files(file_list, default_branch=u'.'):
89
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True):
90
90
"""Convert command-line paths to a WorkingTree and relative paths.
92
92
This is typically used for command-line processors that take one or
104
104
if file_list is None or len(file_list) == 0:
105
105
return WorkingTree.open_containing(default_branch)[0], file_list
106
106
tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
107
return tree, safe_relpath_files(tree, file_list)
110
def safe_relpath_files(tree, file_list):
107
return tree, safe_relpath_files(tree, file_list, canonicalize)
110
def safe_relpath_files(tree, file_list, canonicalize=True):
111
111
"""Convert file_list into a list of relpaths in tree.
113
113
:param tree: A tree to operate on.
119
119
if file_list is None:
122
# tree.relpath exists as a "thunk" to osutils, but canonical_relpath
123
# doesn't - fix that up here before we enter the loop.
125
fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
122
128
for filename in file_list:
124
new_list.append(tree.relpath(osutils.dereference_path(filename)))
130
new_list.append(fixer(osutils.dereference_path(filename)))
125
131
except errors.PathNotChild:
126
132
raise errors.FileInWrongBranch(tree.branch, filename)
656
662
if len(names_list) < 2:
657
663
raise errors.BzrCommandError("missing file argument")
658
tree, rel_names = tree_files(names_list)
664
tree, rel_names = tree_files(names_list, canonicalize=False)
659
665
tree.lock_write()
661
667
self._run(tree, names_list, rel_names, after)
675
681
into_existing = False
677
683
inv = tree.inventory
678
from_id = tree.path2id(rel_names[0])
684
# 'fix' the case of a potential 'from'
685
from_id = tree.path2id(
686
tree.get_canonical_inventory_path(rel_names[0]))
679
687
if (not osutils.lexists(names_list[0]) and
680
688
from_id and inv.get_file_kind(from_id) == "directory"):
681
689
into_existing = False
683
691
if into_existing:
684
692
# move into existing directory
693
# All entries reference existing inventory items, so fix them up
694
# for cicp file-systems.
695
rel_names = tree.get_canonical_inventory_paths(rel_names)
685
696
for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
686
697
self.outf.write("%s => %s\n" % pair)
689
700
raise errors.BzrCommandError('to mv multiple files the'
690
701
' destination must be a versioned'
692
tree.rename_one(rel_names[0], rel_names[1], after=after)
693
self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
704
# for cicp file-systems: the src references an existing inventory
706
src = tree.get_canonical_inventory_path(rel_names[0])
707
# Find the canonical version of the destination: In all cases, the
708
# parent of the target must be in the inventory, so we fetch the
709
# canonical version from there (we do not always *use* the
710
# canonicalized tail portion - we may be attempting to rename the
712
canon_dest = tree.get_canonical_inventory_path(rel_names[1])
713
dest_parent = osutils.dirname(canon_dest)
714
spec_tail = osutils.basename(rel_names[1])
715
# For a CICP file-system, we need to avoid creating 2 inventory
716
# entries that differ only by case. So regardless of the case
717
# we *want* to use (ie, specified by the user or the file-system),
718
# we must always choose to use the case of any existing inventory
719
# items. The only exception to this is when we are attempting a
720
# case-only rename (ie, canonical versions of src and dest are
722
dest_id = tree.path2id(canon_dest)
723
if dest_id is None or tree.path2id(src) == dest_id:
724
# No existing item we care about, so work out what case we
725
# are actually going to use.
727
# If 'after' is specified, the tail must refer to a file on disk.
729
dest_parent_fq = osutils.pathjoin(tree.basedir, dest_parent)
731
# pathjoin with an empty tail adds a slash, which breaks
733
dest_parent_fq = tree.basedir
735
dest_tail = osutils.canonical_relpath(
737
osutils.pathjoin(dest_parent_fq, spec_tail))
739
# not 'after', so case as specified is used
740
dest_tail = spec_tail
742
# Use the existing item so 'mv' fails with AlreadyVersioned.
743
dest_tail = os.path.basename(canon_dest)
744
dest = osutils.pathjoin(dest_parent, dest_tail)
745
mutter("attempting to move %s => %s", src, dest)
746
tree.rename_one(src, dest, after=after)
747
self.outf.write("%s => %s\n" % (src, dest))
696
750
class cmd_pull(Command):