Merge lp:~mbp/bzr/192859-2.0-symlinks into lp:bzr/2.0

Proposed by Martin Pool
Status: Merged
Approved by: Martin Pool
Approved revision: no longer in the source branch.
Merged at revision: 4754
Proposed branch: lp:~mbp/bzr/192859-2.0-symlinks
Merge into: lp:bzr/2.0
Diff against target: 271 lines (+160/-10)
9 files modified
NEWS (+11/-0)
bzrlib/builtins.py (+1/-1)
bzrlib/mutabletree.py (+4/-0)
bzrlib/tests/__init__.py (+1/-0)
bzrlib/tests/per_workingtree/__init__.py (+2/-1)
bzrlib/tests/per_workingtree/test_symlinks.py (+98/-0)
bzrlib/tests/test_treeshape.py (+41/-0)
bzrlib/tests/test_upgrade.py (+0/-6)
bzrlib/tests/treeshape.py (+2/-2)
To merge this branch: bzr merge lp:~mbp/bzr/192859-2.0-symlinks
Reviewer Review Type Date Requested Status
Martin Pool Approve
Review via email: mp+30085@code.launchpad.net

Commit message

fix specific commit of a symlink (bug 128562)

Description of the change

This doesn't yet fix bug 192859, but it does fix another popular symlink bug 128562: specific commit of a symlink tries to commit the referent of the symlink. The fix is embarrassingly small but we also add some tests.

For a followon landing to trunk we might move tree_files out of builtins.

To post a comment you must log in.
Revision history for this message
Martin Pool (mbp) wrote :

John paired on this and verbally approved it, so I'll send it in.

review: Approve
Revision history for this message
Martin Pool (mbp) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2010-07-14 07:46:55 +0000
3+++ NEWS 2010-07-16 13:08:41 +0000
4@@ -18,6 +18,10 @@
5 history no longer crash when deleted files are involved.
6 (Vincent Ladeuil, John Arbash Meinel, #375898)
7
8+* ``bzr commit SYMLINK`` now works, rather than trying to commit the
9+ target of the symlink.
10+ (Martin Pool, John Arbash Meinel, #128562)
11+
12 * ``bzr revert`` now only takes write lock on working tree, instead of on
13 both working tree and branch.
14 (Danny van Heumen, #498409)
15@@ -57,6 +61,13 @@
16 (John Arbash Meinel, #583486)
17
18
19+Testing
20+*******
21+
22+* ``build_tree_contents`` can create symlinks.
23+ (Martin Pool, John Arbash Meinel)
24+
25+
26 bzr 2.0.5
27 #########
28
29
30=== modified file 'bzrlib/builtins.py'
31--- bzrlib/builtins.py 2010-03-08 13:12:55 +0000
32+++ bzrlib/builtins.py 2010-07-16 13:08:41 +0000
33@@ -172,7 +172,7 @@
34 view_str = views.view_display_str(view_files)
35 note("Ignoring files outside view. View is %s" % view_str)
36 return tree, file_list
37- tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
38+ tree = WorkingTree.open_containing(file_list[0])[0]
39 return tree, safe_relpath_files(tree, file_list, canonicalize,
40 apply_view=apply_view)
41
42
43=== modified file 'bzrlib/mutabletree.py'
44--- bzrlib/mutabletree.py 2009-09-28 02:02:30 +0000
45+++ bzrlib/mutabletree.py 2010-07-16 13:08:41 +0000
46@@ -358,6 +358,10 @@
47 This is designed more towards DWIM for humans than API clarity.
48 For the specific behaviour see the help for cmd_add().
49
50+ :param file_list: List of zero or more paths. *NB: these are
51+ interpreted relative to the process cwd, not relative to the
52+ tree.* (Add and most other tree methods use tree-relative
53+ paths.)
54 :param action: A reporter to be called with the inventory, parent_ie,
55 path and kind of the path being added. It may return a file_id if
56 a specific one should be used.
57
58=== modified file 'bzrlib/tests/__init__.py'
59--- bzrlib/tests/__init__.py 2010-04-28 20:58:47 +0000
60+++ bzrlib/tests/__init__.py 2010-07-16 13:08:41 +0000
61@@ -3597,6 +3597,7 @@
62 'bzrlib.tests.test_transport_log',
63 'bzrlib.tests.test_tree',
64 'bzrlib.tests.test_treebuilder',
65+ 'bzrlib.tests.test_treeshape',
66 'bzrlib.tests.test_tsort',
67 'bzrlib.tests.test_tuned_gzip',
68 'bzrlib.tests.test_ui',
69
70=== modified file 'bzrlib/tests/per_workingtree/__init__.py'
71--- bzrlib/tests/per_workingtree/__init__.py 2009-08-04 04:36:34 +0000
72+++ bzrlib/tests/per_workingtree/__init__.py 2010-07-16 13:08:41 +0000
73@@ -1,4 +1,4 @@
74-# Copyright (C) 2006, 2007 Canonical Ltd
75+# Copyright (C) 2006, 2007, 2010 Canonical Ltd
76 #
77 # This program is free software; you can redistribute it and/or modify
78 # it under the terms of the GNU General Public License as published by
79@@ -101,6 +101,7 @@
80 'revision_tree',
81 'set_root_id',
82 'smart_add',
83+ 'symlinks',
84 'uncommit',
85 'unversion',
86 'views',
87
88=== added file 'bzrlib/tests/per_workingtree/test_symlinks.py'
89--- bzrlib/tests/per_workingtree/test_symlinks.py 1970-01-01 00:00:00 +0000
90+++ bzrlib/tests/per_workingtree/test_symlinks.py 2010-07-16 13:08:41 +0000
91@@ -0,0 +1,98 @@
92+# Copyright (C) 2010 Canonical Ltd
93+#
94+# This program is free software; you can redistribute it and/or modify
95+# it under the terms of the GNU General Public License as published by
96+# the Free Software Foundation; either version 2 of the License, or
97+# (at your option) any later version.
98+#
99+# This program is distributed in the hope that it will be useful,
100+# but WITHOUT ANY WARRANTY; without even the implied warranty of
101+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
102+# GNU General Public License for more details.
103+#
104+# You should have received a copy of the GNU General Public License
105+# along with this program; if not, write to the Free Software
106+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
107+
108+"""Test symlink support.
109+
110+See eg <https://bugs.launchpad.net/bzr/+bug/192859>
111+"""
112+
113+from bzrlib import (
114+ builtins,
115+ tests,
116+ workingtree,
117+ )
118+from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
119+
120+
121+class TestSmartAddTree(TestCaseWithWorkingTree):
122+
123+ _test_needs_features = [tests.SymlinkFeature]
124+
125+ def test_smart_add_symlink(self):
126+ tree = self.make_branch_and_tree('tree')
127+ self.build_tree_contents([
128+ ('tree/link@', 'target'),
129+ ])
130+ tree.smart_add(['tree/link'])
131+ self.assertIsNot(None, tree.path2id('link'))
132+ self.assertIs(None, tree.path2id('target'))
133+ self.assertEqual('symlink',
134+ tree.kind(tree.path2id('link')))
135+
136+ def test_smart_add_symlink_pointing_outside(self):
137+ tree = self.make_branch_and_tree('tree')
138+ self.build_tree_contents([
139+ ('tree/link@', '../../../../target'),
140+ ])
141+ tree.smart_add(['tree/link'])
142+ self.assertIsNot(None, tree.path2id('link'))
143+ self.assertIs(None, tree.path2id('target'))
144+ self.assertEqual('symlink',
145+ tree.kind(tree.path2id('link')))
146+
147+ def test_open_containing_through_symlink(self):
148+ self.make_test_tree()
149+ self.check_open_containing('link/content', 'tree', 'content')
150+ self.check_open_containing('link/sublink', 'tree', 'sublink')
151+ # this next one is a bit debatable, but arguably it's better that
152+ # open_containing is only concerned with opening the tree
153+ # and then you can deal with symlinks along the way if you want
154+ self.check_open_containing('link/sublink/subcontent', 'tree',
155+ 'sublink/subcontent')
156+
157+ def check_open_containing(self, to_open, expected_tree_name,
158+ expected_relpath):
159+ wt, relpath = workingtree.WorkingTree.open_containing(to_open)
160+ self.assertEquals(relpath, expected_relpath)
161+ self.assertEndsWith(wt.basedir, expected_tree_name)
162+
163+ def test_tree_files(self):
164+ # not strictly a WorkingTree method, but it should be
165+ # probably the root cause for
166+ # <https://bugs.launchpad.net/bzr/+bug/128562>
167+ self.make_test_tree()
168+ self.check_tree_files(['tree/outerlink'],
169+ 'tree', ['outerlink'])
170+ self.check_tree_files(['link/outerlink'],
171+ 'tree', ['outerlink'])
172+ self.check_tree_files(['link/sublink/subcontent'],
173+ 'tree', ['subdir/subcontent'])
174+
175+ def check_tree_files(self, to_open, expected_tree, expect_paths):
176+ tree, relpaths = builtins.tree_files(to_open)
177+ self.assertEndsWith(tree.basedir, expected_tree)
178+ self.assertEquals(expect_paths, relpaths)
179+
180+ def make_test_tree(self):
181+ tree = self.make_branch_and_tree('tree')
182+ self.build_tree_contents([
183+ ('link@', 'tree'),
184+ ('tree/outerlink@', '/not/there'),
185+ ('tree/content', 'hello'),
186+ ('tree/sublink@', 'subdir'),
187+ ('tree/subdir/',),
188+ ('tree/subdir/subcontent', 'subcontent stuff')
189+ ])
190
191=== added file 'bzrlib/tests/test_treeshape.py'
192--- bzrlib/tests/test_treeshape.py 1970-01-01 00:00:00 +0000
193+++ bzrlib/tests/test_treeshape.py 2010-07-16 13:08:41 +0000
194@@ -0,0 +1,41 @@
195+# Copyright (C) 2010 Canonical Ltd
196+#
197+# This program is free software; you can redistribute it and/or modify
198+# it under the terms of the GNU General Public License as published by
199+# the Free Software Foundation; either version 2 of the License, or
200+# (at your option) any later version.
201+#
202+# This program is distributed in the hope that it will be useful,
203+# but WITHOUT ANY WARRANTY; without even the implied warranty of
204+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
205+# GNU General Public License for more details.
206+#
207+# You should have received a copy of the GNU General Public License
208+# along with this program; if not, write to the Free Software
209+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
210+
211+
212+import os
213+
214+
215+from bzrlib import tests
216+
217+
218+class TestTreeShape(tests.TestCaseWithTransport):
219+
220+ def test_build_tree(self):
221+ """Test tree-building test helper"""
222+ self.build_tree_contents([
223+ ('foo', 'new contents'),
224+ ('.bzr/',),
225+ ('.bzr/README', 'hello'),
226+ ])
227+ self.failUnlessExists('foo')
228+ self.failUnlessExists('.bzr/README')
229+ self.assertFileEqual('hello', '.bzr/README')
230+
231+ def test_build_tree_symlink(self):
232+ self.requireFeature(tests.SymlinkFeature)
233+ self.build_tree_contents([('link@', 'target')])
234+ self.assertEqual('target',
235+ os.readlink('link'))
236
237=== modified file 'bzrlib/tests/test_upgrade.py'
238--- bzrlib/tests/test_upgrade.py 2009-05-07 05:08:46 +0000
239+++ bzrlib/tests/test_upgrade.py 2010-07-16 13:08:41 +0000
240@@ -43,12 +43,6 @@
241
242 class TestUpgrade(TestCaseWithTransport):
243
244- def test_build_tree(self):
245- """Test tree-building test helper"""
246- self.build_tree_contents(_upgrade1_template)
247- self.failUnlessExists('foo')
248- self.failUnlessExists('.bzr/README')
249-
250 def test_upgrade_simple(self):
251 """Upgrade simple v0.0.4 format to latest format"""
252 eq = self.assertEquals
253
254=== modified file 'bzrlib/tests/treeshape.py'
255--- bzrlib/tests/treeshape.py 2009-03-23 14:59:43 +0000
256+++ bzrlib/tests/treeshape.py 2010-07-16 13:08:41 +0000
257@@ -1,4 +1,4 @@
258-# Copyright (C) 2005 Canonical Ltd
259+# Copyright (C) 2005, 2010 Canonical Ltd
260 #
261 # This program is free software; you can redistribute it and/or modify
262 # it under the terms of the GNU General Public License as published by
263@@ -47,7 +47,7 @@
264 if name[-1] == '/':
265 os.mkdir(name)
266 elif name[-1] == '@':
267- raise NotImplementedError('symlinks not handled yet')
268+ os.symlink(tt[1], tt[0][:-1])
269 else:
270 f = file(name, 'wb')
271 try:

Subscribers

People subscribed via source and target branches