Rev 5351: (mbp) tree_files and internal_tree files moved to WorkingTree (Martin Pool) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Mon Jul 19 15:26:13 BST 2010
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 5351 [merge]
revision-id: pqm at pqm.ubuntu.com-20100719142611-fbhst4ivcngc32d5
parent: pqm at pqm.ubuntu.com-20100719130851-igs92yvcf0y7j964
parent: mbp at canonical.com-20100716160455-fj4fpxsgjw1uy3d6
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2010-07-19 15:26:11 +0100
message:
(mbp) tree_files and internal_tree files moved to WorkingTree (Martin Pool)
added:
bzrlib/tests/per_workingtree/test_symlinks.py test_symlinks.py-20100715135626-4lw38d8njbzyec6l-1
bzrlib/tests/test_treeshape.py test_treeshape.py-20100715135036-z8vz2u7f3w7wg2it-1
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/builtins.py builtins.py-20050830033751-fc01482b9ca23183
bzrlib/conflicts.py conflicts.py-20051001061850-78ef952ba63d2b42
bzrlib/diff.py diff.py-20050309040759-26944fbbf2ebbf36
bzrlib/log.py log.py-20050505065812-c40ce11702fe5fb1
bzrlib/mutabletree.py mutabletree.py-20060906023413-4wlkalbdpsxi2r4y-2
bzrlib/shelf_ui.py shelver.py-20081005210102-33worgzwrtdw0yrm-1
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/per_workingtree/__init__.py __init__.py-20060203003124-b2aa5aca21a8bfad
bzrlib/tests/test_upgrade.py test_upgrade.py-20051004040251-555fe1d2bae1bc71
bzrlib/tests/treeshape.py treeshape.py-20051004094628-312a98f0194306a8
bzrlib/workingtree.py workingtree.py-20050511021032-29b6ec0a681e02e3
=== modified file 'NEWS'
--- a/NEWS 2010-07-16 13:53:26 +0000
+++ b/NEWS 2010-07-16 15:49:06 +0000
@@ -18,6 +18,10 @@
longer raised.
(Martin Pool)
+* `tree_files` and `internal_tree_files` are now deprecated in favor of
+ `WorkingTree.open_containing_paths`.
+ (Martin Pool)
+
New Features
************
@@ -1545,6 +1549,10 @@
history no longer crash when deleted files are involved.
(Vincent Ladeuil, John Arbash Meinel, #375898)
+* ``bzr commit SYMLINK`` now works, rather than trying to commit the
+ target of the symlink.
+ (Martin Pool, John Arbash Meinel, #128562)
+
* ``bzr revert`` now only takes write lock on working tree, instead of on
both working tree and branch.
(Danny van Heumen, #498409)
@@ -1579,6 +1587,13 @@
(John Arbash Meinel, #583486)
+Testing
+*******
+
+* ``build_tree_contents`` can create symlinks.
+ (Martin Pool, John Arbash Meinel)
+
+
bzr 2.0.5
#########
=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py 2010-07-16 13:53:26 +0000
+++ b/bzrlib/builtins.py 2010-07-16 16:04:55 +0000
@@ -75,6 +75,7 @@
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
+ at symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
def tree_files(file_list, default_branch=u'.', canonicalize=True,
apply_view=True):
return internal_tree_files(file_list, default_branch, canonicalize,
@@ -148,10 +149,13 @@
# XXX: Bad function name; should possibly also be a class method of
# WorkingTree rather than a function.
+ at symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
apply_view=True):
"""Convert command-line paths to a WorkingTree and relative paths.
+ Deprecated: use WorkingTree.open_containing_paths instead.
+
This is typically used for command-line processors that take one or
more filenames, and infer the workingtree that contains them.
@@ -167,50 +171,10 @@
:return: workingtree, [relative_paths]
"""
- if file_list is None or len(file_list) == 0:
- tree = WorkingTree.open_containing(default_branch)[0]
- if tree.supports_views() and apply_view:
- view_files = tree.views.lookup_view()
- if view_files:
- file_list = view_files
- view_str = views.view_display_str(view_files)
- note("Ignoring files outside view. View is %s" % view_str)
- return tree, file_list
- tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
- return tree, safe_relpath_files(tree, file_list, canonicalize,
- apply_view=apply_view)
-
-
-def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
- """Convert file_list into a list of relpaths in tree.
-
- :param tree: A tree to operate on.
- :param file_list: A list of user provided paths or None.
- :param apply_view: if True and a view is set, apply it or check that
- specified files are within it
- :return: A list of relative paths.
- :raises errors.PathNotChild: When a provided path is in a different tree
- than tree.
- """
- if file_list is None:
- return None
- if tree.supports_views() and apply_view:
- view_files = tree.views.lookup_view()
- else:
- view_files = []
- new_list = []
- # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
- # doesn't - fix that up here before we enter the loop.
- if canonicalize:
- fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
- else:
- fixer = tree.relpath
- for filename in file_list:
- relpath = fixer(osutils.dereference_path(filename))
- if view_files and not osutils.is_inside_any(view_files, relpath):
- raise errors.FileOutsideView(filename, view_files)
- new_list.append(relpath)
- return new_list
+ return WorkingTree.open_containing_paths(
+ file_list, default_directory='.',
+ canonicalize=True,
+ apply_view=True)
def _get_view_info_for_change_reporter(tree):
@@ -316,7 +280,7 @@
raise errors.BzrCommandError('bzr status --revision takes exactly'
' one or two revision specifiers')
- tree, relfile_list = tree_files(file_list)
+ tree, relfile_list = WorkingTree.open_containing_paths(file_list)
# Avoid asking for specific files when that is not needed.
if relfile_list == ['']:
relfile_list = None
@@ -754,7 +718,7 @@
raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
revision = _get_one_revision('inventory', revision)
- work_tree, file_list = tree_files(file_list)
+ work_tree, file_list = WorkingTree.open_containing_paths(file_list)
self.add_cleanup(work_tree.lock_read().unlock)
if revision is not None:
tree = revision.as_tree(work_tree.branch)
@@ -825,7 +789,7 @@
names_list = []
if len(names_list) < 2:
raise errors.BzrCommandError("missing file argument")
- tree, rel_names = tree_files(names_list, canonicalize=False)
+ tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
self.add_cleanup(tree.lock_tree_write().unlock)
self._run(tree, names_list, rel_names, after)
@@ -836,7 +800,8 @@
if after:
raise errors.BzrCommandError('--after cannot be specified with'
' --auto.')
- work_tree, file_list = tree_files(names_list, default_branch='.')
+ work_tree, file_list = WorkingTree.open_containing_paths(
+ names_list, default_directory='.')
self.add_cleanup(work_tree.lock_tree_write().unlock)
rename_map.RenameMap.guess_renames(work_tree, dry_run)
@@ -1519,7 +1484,7 @@
def run(self, file_list, verbose=False, new=False,
file_deletion_strategy='safe'):
- tree, file_list = tree_files(file_list)
+ tree, file_list = WorkingTree.open_containing_paths(file_list)
if file_list is not None:
file_list = [f for f in file_list]
@@ -3102,7 +3067,7 @@
properties = {}
- tree, selected_list = tree_files(selected_list)
+ tree, selected_list = WorkingTree.open_containing_paths(selected_list)
if selected_list == ['']:
# workaround - commit of root of tree should be exactly the same
# as just default commit in that tree, and succeed even though
@@ -3182,7 +3147,7 @@
reporter=None, verbose=verbose, revprops=properties,
authors=author, timestamp=commit_stamp,
timezone=offset,
- exclude=safe_relpath_files(tree, exclude))
+ exclude=tree.safe_relpath_files(exclude))
except PointlessCommit:
raise errors.BzrCommandError("No changes to commit."
" Use --unchanged to commit anyhow.")
@@ -4084,7 +4049,7 @@
from bzrlib.conflicts import restore
if merge_type is None:
merge_type = _mod_merge.Merge3Merger
- tree, file_list = tree_files(file_list)
+ tree, file_list = WorkingTree.open_containing_paths(file_list)
self.add_cleanup(tree.lock_write().unlock)
parents = tree.get_parent_ids()
if len(parents) != 2:
@@ -4200,7 +4165,7 @@
def run(self, revision=None, no_backup=False, file_list=None,
forget_merges=None):
- tree, file_list = tree_files(file_list)
+ tree, file_list = WorkingTree.open_containing_paths(file_list)
self.add_cleanup(tree.lock_tree_write().unlock)
if forget_merges:
tree.set_parent_ids(tree.get_parent_ids()[:1])
@@ -5702,7 +5667,8 @@
name=None,
switch=None,
):
- tree, file_list = tree_files(file_list, apply_view=False)
+ tree, file_list = WorkingTree.open_containing_paths(file_list,
+ apply_view=False)
current_view, view_dict = tree.views.get_view_info()
if name is None:
name = current_view
=== modified file 'bzrlib/conflicts.py'
--- a/bzrlib/conflicts.py 2010-05-28 14:15:28 +0000
+++ b/bzrlib/conflicts.py 2010-07-16 15:35:43 +0000
@@ -24,7 +24,6 @@
import errno
from bzrlib import (
- builtins,
cleanup,
commands,
errors,
@@ -127,7 +126,8 @@
if action is None:
action = 'done'
else:
- tree, file_list = builtins.tree_files(file_list)
+ tree, file_list = workingtree.WorkingTree.open_containing_paths(
+ file_list)
if file_list is None:
if action is None:
# FIXME: There is a special case here related to the option
=== modified file 'bzrlib/diff.py'
--- a/bzrlib/diff.py 2010-07-16 13:53:26 +0000
+++ b/bzrlib/diff.py 2010-07-16 15:20:17 +0000
@@ -420,9 +420,9 @@
# Get the specific files (all files is None, no files is [])
if make_paths_wt_relative and working_tree is not None:
- from bzrlib.builtins import safe_relpath_files
- other_paths = safe_relpath_files(working_tree, other_paths,
- apply_view=apply_view)
+ other_paths = working_tree.safe_relpath_files(
+ other_paths,
+ apply_view=apply_view)
specific_files.extend(other_paths)
if len(specific_files) == 0:
specific_files = None
=== modified file 'bzrlib/log.py'
--- a/bzrlib/log.py 2010-06-30 12:03:30 +0000
+++ b/bzrlib/log.py 2010-07-16 13:29:07 +0000
@@ -2017,7 +2017,7 @@
kind is one of values 'directory', 'file', 'symlink', 'tree-reference'.
branch will be read-locked.
"""
- from builtins import _get_revision_range, safe_relpath_files
+ from builtins import _get_revision_range
tree, b, path = bzrdir.BzrDir.open_containing_tree_or_branch(file_list[0])
add_cleanup(b.lock_read().unlock)
# XXX: It's damn messy converting a list of paths to relative paths when
@@ -2029,7 +2029,7 @@
# case of running log in a nested directory, assuming paths beyond the
# first one haven't been deleted ...
if tree:
- relpaths = [path] + safe_relpath_files(tree, file_list[1:])
+ relpaths = [path] + tree.safe_relpath_files(file_list[1:])
else:
relpaths = [path] + file_list[1:]
info_list = []
=== modified file 'bzrlib/mutabletree.py'
--- a/bzrlib/mutabletree.py 2010-05-10 11:34:20 +0000
+++ b/bzrlib/mutabletree.py 2010-07-16 13:06:33 +0000
@@ -375,6 +375,10 @@
This is designed more towards DWIM for humans than API clarity.
For the specific behaviour see the help for cmd_add().
+ :param file_list: List of zero or more paths. *NB: these are
+ interpreted relative to the process cwd, not relative to the
+ tree.* (Add and most other tree methods use tree-relative
+ paths.)
:param action: A reporter to be called with the inventory, parent_ie,
path and kind of the path being added. It may return a file_id if
a specific one should be used.
=== modified file 'bzrlib/shelf_ui.py'
--- a/bzrlib/shelf_ui.py 2010-05-26 15:58:08 +0000
+++ b/bzrlib/shelf_ui.py 2010-07-16 13:29:07 +0000
@@ -175,7 +175,7 @@
try:
target_tree = builtins._get_one_revision_tree('shelf2', revision,
tree.branch, tree)
- files = builtins.safe_relpath_files(tree, file_list)
+ files = tree.safe_relpath_files(file_list)
return klass(tree, target_tree, diff_writer, all, all, files,
message, destroy)
finally:
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py 2010-07-08 10:34:12 +0000
+++ b/bzrlib/tests/__init__.py 2010-07-16 13:06:33 +0000
@@ -3813,6 +3813,7 @@
'bzrlib.tests.test_transport_log',
'bzrlib.tests.test_tree',
'bzrlib.tests.test_treebuilder',
+ 'bzrlib.tests.test_treeshape',
'bzrlib.tests.test_tsort',
'bzrlib.tests.test_tuned_gzip',
'bzrlib.tests.test_ui',
=== modified file 'bzrlib/tests/per_workingtree/__init__.py'
--- a/bzrlib/tests/per_workingtree/__init__.py 2010-04-01 12:53:53 +0000
+++ b/bzrlib/tests/per_workingtree/__init__.py 2010-07-16 13:06:33 +0000
@@ -101,6 +101,7 @@
'revision_tree',
'set_root_id',
'smart_add',
+ 'symlinks',
'uncommit',
'unversion',
'views',
=== added file 'bzrlib/tests/per_workingtree/test_symlinks.py'
--- a/bzrlib/tests/per_workingtree/test_symlinks.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/per_workingtree/test_symlinks.py 2010-07-16 15:49:06 +0000
@@ -0,0 +1,98 @@
+# Copyright (C) 2010 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""Test symlink support.
+
+See eg <https://bugs.launchpad.net/bzr/+bug/192859>
+"""
+
+from bzrlib import (
+ builtins,
+ tests,
+ workingtree,
+ )
+from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
+
+
+class TestSmartAddTree(TestCaseWithWorkingTree):
+
+ _test_needs_features = [tests.SymlinkFeature]
+
+ def test_smart_add_symlink(self):
+ tree = self.make_branch_and_tree('tree')
+ self.build_tree_contents([
+ ('tree/link@', 'target'),
+ ])
+ tree.smart_add(['tree/link'])
+ self.assertIsNot(None, tree.path2id('link'))
+ self.assertIs(None, tree.path2id('target'))
+ self.assertEqual('symlink',
+ tree.kind(tree.path2id('link')))
+
+ def test_smart_add_symlink_pointing_outside(self):
+ tree = self.make_branch_and_tree('tree')
+ self.build_tree_contents([
+ ('tree/link@', '../../../../target'),
+ ])
+ tree.smart_add(['tree/link'])
+ self.assertIsNot(None, tree.path2id('link'))
+ self.assertIs(None, tree.path2id('target'))
+ self.assertEqual('symlink',
+ tree.kind(tree.path2id('link')))
+
+ def test_open_containing_through_symlink(self):
+ self.make_test_tree()
+ self.check_open_containing('link/content', 'tree', 'content')
+ self.check_open_containing('link/sublink', 'tree', 'sublink')
+ # this next one is a bit debatable, but arguably it's better that
+ # open_containing is only concerned with opening the tree
+ # and then you can deal with symlinks along the way if you want
+ self.check_open_containing('link/sublink/subcontent', 'tree',
+ 'sublink/subcontent')
+
+ def check_open_containing(self, to_open, expected_tree_name,
+ expected_relpath):
+ wt, relpath = workingtree.WorkingTree.open_containing(to_open)
+ self.assertEquals(relpath, expected_relpath)
+ self.assertEndsWith(wt.basedir, expected_tree_name)
+
+ def test_tree_files(self):
+ # not strictly a WorkingTree method, but it should be
+ # probably the root cause for
+ # <https://bugs.launchpad.net/bzr/+bug/128562>
+ self.make_test_tree()
+ self.check_tree_files(['tree/outerlink'],
+ 'tree', ['outerlink'])
+ self.check_tree_files(['link/outerlink'],
+ 'tree', ['outerlink'])
+ self.check_tree_files(['link/sublink/subcontent'],
+ 'tree', ['subdir/subcontent'])
+
+ def check_tree_files(self, to_open, expected_tree, expect_paths):
+ tree, relpaths = workingtree.WorkingTree.open_containing_paths(to_open)
+ self.assertEndsWith(tree.basedir, expected_tree)
+ self.assertEquals(expect_paths, relpaths)
+
+ def make_test_tree(self):
+ tree = self.make_branch_and_tree('tree')
+ self.build_tree_contents([
+ ('link@', 'tree'),
+ ('tree/outerlink@', '/not/there'),
+ ('tree/content', 'hello'),
+ ('tree/sublink@', 'subdir'),
+ ('tree/subdir/',),
+ ('tree/subdir/subcontent', 'subcontent stuff')
+ ])
=== added file 'bzrlib/tests/test_treeshape.py'
--- a/bzrlib/tests/test_treeshape.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/test_treeshape.py 2010-07-15 13:55:46 +0000
@@ -0,0 +1,41 @@
+# Copyright (C) 2010 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+import os
+
+
+from bzrlib import tests
+
+
+class TestTreeShape(tests.TestCaseWithTransport):
+
+ def test_build_tree(self):
+ """Test tree-building test helper"""
+ self.build_tree_contents([
+ ('foo', 'new contents'),
+ ('.bzr/',),
+ ('.bzr/README', 'hello'),
+ ])
+ self.failUnlessExists('foo')
+ self.failUnlessExists('.bzr/README')
+ self.assertFileEqual('hello', '.bzr/README')
+
+ def test_build_tree_symlink(self):
+ self.requireFeature(tests.SymlinkFeature)
+ self.build_tree_contents([('link@', 'target')])
+ self.assertEqual('target',
+ os.readlink('link'))
=== modified file 'bzrlib/tests/test_upgrade.py'
--- a/bzrlib/tests/test_upgrade.py 2010-06-20 11:18:38 +0000
+++ b/bzrlib/tests/test_upgrade.py 2010-07-16 13:06:33 +0000
@@ -43,12 +43,6 @@
class TestUpgrade(TestCaseWithTransport):
- def test_build_tree(self):
- """Test tree-building test helper"""
- self.build_tree_contents(_upgrade1_template)
- self.failUnlessExists('foo')
- self.failUnlessExists('.bzr/README')
-
def test_upgrade_simple(self):
"""Upgrade simple v0.0.4 format to latest format"""
eq = self.assertEquals
=== modified file 'bzrlib/tests/treeshape.py'
--- a/bzrlib/tests/treeshape.py 2010-05-05 00:05:29 +0000
+++ b/bzrlib/tests/treeshape.py 2010-07-16 13:06:33 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005 Canonical Ltd
+# Copyright (C) 2005, 2010 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -51,7 +51,7 @@
if name[-1] == '/':
os.mkdir(name)
elif name[-1] == '@':
- raise NotImplementedError('symlinks not handled yet')
+ os.symlink(tt[1], tt[0][:-1])
else:
f = file(name, 'wb')
try:
=== modified file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py 2010-07-15 13:33:30 +0000
+++ b/bzrlib/workingtree.py 2010-07-19 14:26:11 +0000
@@ -349,10 +349,67 @@
if path is None:
path = osutils.getcwd()
control, relpath = bzrdir.BzrDir.open_containing(path)
-
return control.open_workingtree(), relpath
@staticmethod
+ def open_containing_paths(file_list, default_directory='.',
+ canonicalize=True, apply_view=True):
+ """Open the WorkingTree that contains a set of paths.
+
+ Fail if the paths given are not all in a single tree.
+
+ This is used for the many command-line interfaces that take a list of
+ any number of files and that require they all be in the same tree.
+ """
+ # recommended replacement for builtins.internal_tree_files
+ if file_list is None or len(file_list) == 0:
+ tree = WorkingTree.open_containing(default_directory)[0]
+ # XXX: doesn't really belong here, and seems to have the strange
+ # side effect of making it return a bunch of files, not the whole
+ # tree -- mbp 20100716
+ if tree.supports_views() and apply_view:
+ view_files = tree.views.lookup_view()
+ if view_files:
+ file_list = view_files
+ view_str = views.view_display_str(view_files)
+ note("Ignoring files outside view. View is %s" % view_str)
+ return tree, file_list
+ tree = WorkingTree.open_containing(file_list[0])[0]
+ return tree, tree.safe_relpath_files(file_list, canonicalize,
+ apply_view=apply_view)
+
+ def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
+ """Convert file_list into a list of relpaths in tree.
+
+ :param self: A tree to operate on.
+ :param file_list: A list of user provided paths or None.
+ :param apply_view: if True and a view is set, apply it or check that
+ specified files are within it
+ :return: A list of relative paths.
+ :raises errors.PathNotChild: When a provided path is in a different self
+ than self.
+ """
+ if file_list is None:
+ return None
+ if self.supports_views() and apply_view:
+ view_files = self.views.lookup_view()
+ else:
+ view_files = []
+ new_list = []
+ # self.relpath exists as a "thunk" to osutils, but canonical_relpath
+ # doesn't - fix that up here before we enter the loop.
+ if canonicalize:
+ fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
+ else:
+ fixer = self.relpath
+ for filename in file_list:
+ relpath = fixer(osutils.dereference_path(filename))
+ if view_files and not osutils.is_inside_any(view_files, relpath):
+ raise errors.FileOutsideView(filename, view_files)
+ new_list.append(relpath)
+ return new_list
+
+ @staticmethod
def open_downlevel(path=None):
"""Open an unsupported working tree.
More information about the bazaar-commits
mailing list