14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from cStringIO import StringIO
21
from bzrlib import ignores
23
from bzrlib.branch import Branch
24
from bzrlib import bzrdir, conflicts, errors, workingtree
25
from bzrlib.bzrdir import BzrDir
26
from bzrlib.errors import NotBranchError, NotVersionedError
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27
26
from bzrlib.lockdir import LockDir
28
27
from bzrlib.mutabletree import needs_tree_write_lock
29
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
30
from bzrlib.symbol_versioning import zero_thirteen
31
28
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
32
from bzrlib.trace import mutter
33
from bzrlib.transport import get_transport
34
29
from bzrlib.workingtree import (
42
37
class TestTreeDirectory(TestCaseWithTransport):
44
39
def test_kind_character(self):
66
61
class TestDefaultFormat(TestCaseWithTransport):
68
63
def test_get_set_default_format(self):
69
old_format = workingtree.WorkingTreeFormat.get_default_format()
71
self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
72
workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
74
# the default branch format is used by the meta dir format
75
# which is not the default bzrdir format at this point
76
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
77
dir.create_repository()
79
result = dir.create_workingtree()
80
self.assertEqual(result, 'A tree')
82
workingtree.WorkingTreeFormat.set_default_format(old_format)
83
self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
64
old_format = workingtree.format_registry.get_default()
66
self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
67
workingtree.format_registry.set_default(SampleTreeFormat())
69
# the default branch format is used by the meta dir format
70
# which is not the default bzrdir format at this point
71
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
72
dir.create_repository()
74
result = dir.create_workingtree()
75
self.assertEqual(result, 'A tree')
77
workingtree.format_registry.set_default(old_format)
78
self.assertEqual(old_format, workingtree.format_registry.get_default())
80
def test_get_set_default_format_by_key(self):
81
old_format = workingtree.format_registry.get_default()
83
format = SampleTreeFormat()
84
workingtree.format_registry.register(format)
85
self.addCleanup(workingtree.format_registry.remove, format)
86
self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
87
workingtree.format_registry.set_default_key(format.get_format_string())
89
# the default branch format is used by the meta dir format
90
# which is not the default bzrdir format at this point
91
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
92
dir.create_repository()
94
result = dir.create_workingtree()
95
self.assertEqual(result, 'A tree')
97
workingtree.format_registry.set_default_key(
98
old_format.get_format_string())
99
self.assertEqual(old_format, workingtree.format_registry.get_default())
102
tree = self.make_branch_and_tree('.')
103
open_direct = workingtree.WorkingTree.open('.')
104
self.assertEqual(tree.basedir, open_direct.basedir)
105
open_no_args = workingtree.WorkingTree.open()
106
self.assertEqual(tree.basedir, open_no_args.basedir)
108
def test_open_containing(self):
109
tree = self.make_branch_and_tree('.')
110
open_direct, relpath = workingtree.WorkingTree.open_containing('.')
111
self.assertEqual(tree.basedir, open_direct.basedir)
112
self.assertEqual('', relpath)
113
open_no_args, relpath = workingtree.WorkingTree.open_containing()
114
self.assertEqual(tree.basedir, open_no_args.basedir)
115
self.assertEqual('', relpath)
116
open_subdir, relpath = workingtree.WorkingTree.open_containing('subdir')
117
self.assertEqual(tree.basedir, open_subdir.basedir)
118
self.assertEqual('subdir', relpath)
86
121
class SampleTreeFormat(workingtree.WorkingTreeFormat):
87
122
"""A sample format
89
this format is initializable, unsupported to aid in testing the
124
this format is initializable, unsupported to aid in testing the
90
125
open and open_downlevel routines.
107
143
return "opened tree."
146
class SampleExtraTreeFormat(workingtree.WorkingTreeFormat):
147
"""A sample format that does not support use in a metadir.
151
def get_format_string(self):
152
# Not usable in a metadir, so no format string
155
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
156
accelerator_tree=None, hardlink=False):
157
raise NotImplementedError(self.initialize)
159
def is_supported(self):
162
def open(self, transport, _found=False):
163
raise NotImplementedError(self.open)
110
166
class TestWorkingTreeFormat(TestCaseWithTransport):
111
167
"""Tests for the WorkingTreeFormat facility."""
169
def test_find_format_string(self):
170
# is the right format object found for a working tree?
171
branch = self.make_branch('branch')
172
self.assertRaises(errors.NoWorkingTree,
173
workingtree.WorkingTreeFormat.find_format_string, branch.bzrdir)
174
transport = branch.bzrdir.get_workingtree_transport(None)
176
transport.put_bytes("format", "some format name")
177
# The format does not have to be known by Bazaar,
178
# find_format_string just retrieves the name
179
self.assertEquals("some format name",
180
workingtree.WorkingTreeFormat.find_format_string(branch.bzrdir))
113
182
def test_find_format(self):
114
183
# is the right format object found for a working tree?
115
184
# create a branch with a few known format objects.
149
218
format.initialize(dir)
150
219
# register a format for it.
151
workingtree.WorkingTreeFormat.register_format(format)
220
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
221
workingtree.WorkingTreeFormat.register_format, format)
222
self.assertTrue(format in
223
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
224
workingtree.WorkingTreeFormat.get_formats))
152
225
# which branch.Open will refuse (not supported)
153
226
self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
154
227
# but open_downlevel will work
155
228
self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
156
229
# unregister the format
157
workingtree.WorkingTreeFormat.unregister_format(format)
230
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
231
workingtree.WorkingTreeFormat.unregister_format, format)
232
self.assertFalse(format in
233
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
234
workingtree.WorkingTreeFormat.get_formats))
237
class TestWorkingTreeFormatRegistry(TestCase):
240
super(TestWorkingTreeFormatRegistry, self).setUp()
241
self.registry = workingtree.WorkingTreeFormatRegistry()
243
def test_register_unregister_format(self):
244
format = SampleTreeFormat()
245
self.registry.register(format)
246
self.assertEquals(format, self.registry.get("Sample tree format."))
247
self.registry.remove(format)
248
self.assertRaises(KeyError, self.registry.get, "Sample tree format.")
250
def test_get_all(self):
251
format = SampleTreeFormat()
252
self.assertEquals([], self.registry._get_all())
253
self.registry.register(format)
254
self.assertEquals([format], self.registry._get_all())
256
def test_register_extra(self):
257
format = SampleExtraTreeFormat()
258
self.assertEquals([], self.registry._get_all())
259
self.registry.register_extra(format)
260
self.assertEquals([format], self.registry._get_all())
262
def test_register_extra_lazy(self):
263
self.assertEquals([], self.registry._get_all())
264
self.registry.register_extra_lazy("bzrlib.tests.test_workingtree",
265
"SampleExtraTreeFormat")
266
formats = self.registry._get_all()
267
self.assertEquals(1, len(formats))
268
self.assertIsInstance(formats[0], SampleExtraTreeFormat)
160
271
class TestWorkingTreeFormat3(TestCaseWithTransport):
222
327
control.create_repository()
223
328
control.create_branch()
224
329
tree = workingtree.WorkingTreeFormat3().initialize(control)
225
tree._control_files._transport.delete("pending-merges")
330
tree._transport.delete("pending-merges")
226
331
self.assertEqual([], tree.get_parent_ids())
229
class TestFormat2WorkingTree(TestCaseWithTransport):
230
"""Tests that are specific to format 2 trees."""
232
def create_format2_tree(self, url):
233
return self.make_branch_and_tree(
234
url, format=bzrlib.bzrdir.BzrDirFormat6())
236
def test_conflicts(self):
237
# test backwards compatability
238
tree = self.create_format2_tree('.')
239
self.assertRaises(errors.UnsupportedOperation, tree.set_conflicts,
241
file('lala.BASE', 'wb').write('labase')
242
expected = conflicts.ContentsConflict('lala')
243
self.assertEqual(list(tree.conflicts()), [expected])
244
file('lala', 'wb').write('la')
245
tree.add('lala', 'lala-id')
246
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
247
self.assertEqual(list(tree.conflicts()), [expected])
248
file('lala.THIS', 'wb').write('lathis')
249
file('lala.OTHER', 'wb').write('laother')
250
# When "text conflict"s happen, stem, THIS and OTHER are text
251
expected = conflicts.TextConflict('lala', file_id='lala-id')
252
self.assertEqual(list(tree.conflicts()), [expected])
253
os.unlink('lala.OTHER')
254
os.mkdir('lala.OTHER')
255
expected = conflicts.ContentsConflict('lala', file_id='lala-id')
256
self.assertEqual(list(tree.conflicts()), [expected])
259
class TestNonFormatSpecificCode(TestCaseWithTransport):
260
"""This class contains tests of workingtree that are not format specific."""
262
def test_gen_file_id(self):
263
file_id = self.applyDeprecated(zero_thirteen, workingtree.gen_file_id,
265
self.assertStartsWith(file_id, 'filename-')
267
def test_gen_root_id(self):
268
file_id = self.applyDeprecated(zero_thirteen, workingtree.gen_root_id)
269
self.assertStartsWith(file_id, 'tree_root-')
271
def test__translate_ignore_rule(self):
272
tree = self.make_branch_and_tree('.')
273
# translation should return the regex, the number of groups in it,
274
# and the original rule in a tuple.
275
# there are three sorts of ignore rules:
276
# root only - regex is the rule itself without the leading ./
279
tree._translate_ignore_rule("./rootdirrule"))
280
# full path - regex is the rule itself
282
"(path\\/to\\/file$)",
283
tree._translate_ignore_rule("path/to/file"))
284
# basename only rule - regex is a rule that ignores everything up
285
# to the last / in the filename
287
"((?:.*/)?(?!.*/)basenamerule$)",
288
tree._translate_ignore_rule("basenamerule"))
290
def test__combine_ignore_rules(self):
291
tree = self.make_branch_and_tree('.')
292
# the combined ignore regexs need the outer group indices
293
# placed in a dictionary with the rules that were combined.
294
# an empty set of rules
295
# this is returned as a list of combined regex,rule sets, because
296
# python has a limit of 100 combined regexes.
297
compiled_rules = tree._combine_ignore_rules([])
298
self.assertEqual([], compiled_rules)
299
# one of each type of rule.
300
compiled_rules = tree._combine_ignore_rules(
301
["rule1", "rule/two", "./three"])[0]
302
# what type *is* the compiled regex to do an isinstance of ?
303
self.assertEqual(3, compiled_rules[0].groups)
305
{0:"rule1",1:"rule/two",2:"./three"},
308
def test__combine_ignore_rules_grouping(self):
309
tree = self.make_branch_and_tree('.')
310
# when there are too many rules, the output is split into groups of 100
312
for index in range(198):
314
self.assertEqual(2, len(tree._combine_ignore_rules(rules)))
316
def test__get_ignore_rules_as_regex(self):
317
tree = self.make_branch_and_tree('.')
318
# Setup the default ignore list to be empty
319
ignores._set_user_ignores([])
321
# some plugins (shelf) modifies the DEFAULT_IGNORE list in memory
322
# which causes this test to fail so force the DEFAULT_IGNORE
324
orig_default = bzrlib.DEFAULT_IGNORE
325
# Also make sure the runtime ignore list is empty
326
orig_runtime = ignores._runtime_ignores
328
bzrlib.DEFAULT_IGNORE = []
329
ignores._runtime_ignores = set()
331
self.build_tree_contents([('.bzrignore', 'CVS\n.hg\n')])
332
reference_output = tree._combine_ignore_rules(
333
set(['CVS', '.hg']))[0]
334
regex_rules = tree._get_ignore_rules_as_regex()[0]
335
self.assertEqual(len(reference_output[1]), regex_rules[0].groups)
336
self.assertEqual(reference_output[1], regex_rules[1])
338
bzrlib.DEFAULT_IGNORE = orig_default
339
ignores._runtime_ignores = orig_runtime
342
334
class InstrumentedTree(object):
343
335
"""A instrumented tree to check the needs_tree_write_lock decorator."""
383
375
self.assertEqual(['t', 'u'], tree._locks)
384
376
self.assertRaises(TypeError, tree.method_that_raises, 'foo')
385
377
self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
380
class TestRevert(TestCaseWithTransport):
382
def test_revert_conflicts_recursive(self):
383
this_tree = self.make_branch_and_tree('this-tree')
384
self.build_tree_contents([('this-tree/foo/',),
385
('this-tree/foo/bar', 'bar')])
386
this_tree.add(['foo', 'foo/bar'])
387
this_tree.commit('created foo/bar')
388
other_tree = this_tree.bzrdir.sprout('other-tree').open_workingtree()
389
self.build_tree_contents([('other-tree/foo/bar', 'baz')])
390
other_tree.commit('changed bar')
391
self.build_tree_contents([('this-tree/foo/bar', 'qux')])
392
this_tree.commit('changed qux')
393
this_tree.merge_from_branch(other_tree.branch)
394
self.assertEqual(1, len(this_tree.conflicts()))
395
this_tree.revert(['foo'])
396
self.assertEqual(0, len(this_tree.conflicts()))
399
class TestAutoResolve(TestCaseWithTransport):
401
def test_auto_resolve(self):
402
base = self.make_branch_and_tree('base')
403
self.build_tree_contents([('base/hello', 'Hello')])
404
base.add('hello', 'hello_id')
406
other = base.bzrdir.sprout('other').open_workingtree()
407
self.build_tree_contents([('other/hello', 'hELLO')])
408
other.commit('Case switch')
409
this = base.bzrdir.sprout('this').open_workingtree()
410
self.assertPathExists('this/hello')
411
self.build_tree_contents([('this/hello', 'Hello World')])
412
this.commit('Add World')
413
this.merge_from_branch(other.branch)
414
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
417
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
419
self.build_tree_contents([('this/hello', '<<<<<<<')])
421
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
423
self.build_tree_contents([('this/hello', '=======')])
425
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
427
self.build_tree_contents([('this/hello', '\n>>>>>>>')])
428
remaining, resolved = this.auto_resolve()
429
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
431
self.assertEqual([], resolved)
432
self.build_tree_contents([('this/hello', 'hELLO wORLD')])
433
remaining, resolved = this.auto_resolve()
434
self.assertEqual([], this.conflicts())
435
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
437
self.assertPathDoesNotExist('this/hello.BASE')
439
def test_auto_resolve_dir(self):
440
tree = self.make_branch_and_tree('tree')
441
self.build_tree(['tree/hello/'])
442
tree.add('hello', 'hello-id')
443
file_conflict = conflicts.TextConflict('file', 'hello-id')
444
tree.set_conflicts(conflicts.ConflictList([file_conflict]))
448
class TestFindTrees(TestCaseWithTransport):
450
def test_find_trees(self):
451
self.make_branch_and_tree('foo')
452
self.make_branch_and_tree('foo/bar')
453
# Sticking a tree inside a control dir is heinous, so let's skip it
454
self.make_branch_and_tree('foo/.bzr/baz')
455
self.make_branch('qux')
456
trees = workingtree.WorkingTree.find_trees('.')
457
self.assertEqual(2, len(list(trees)))