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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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
28
27
from bzrlib.lockdir import LockDir
29
28
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
30
31
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
32
from bzrlib.trace import mutter
33
from bzrlib.transport import get_transport
31
34
from bzrlib.workingtree import (
39
42
class TestTreeDirectory(TestCaseWithTransport):
41
44
def test_kind_character(self):
63
66
class TestDefaultFormat(TestCaseWithTransport):
65
68
def test_get_set_default_format(self):
66
old_format = workingtree.format_registry.get_default()
68
self.assertTrue(isinstance(old_format, workingtree_4.WorkingTreeFormat6))
69
workingtree.format_registry.set_default(SampleTreeFormat())
71
# the default branch format is used by the meta dir format
72
# which is not the default bzrdir format at this point
73
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
74
dir.create_repository()
76
result = dir.create_workingtree()
77
self.assertEqual(result, 'A tree')
79
workingtree.format_registry.set_default(old_format)
80
self.assertEqual(old_format, workingtree.format_registry.get_default())
82
def test_get_set_default_format_by_key(self):
83
old_format = workingtree.format_registry.get_default()
85
format = SampleTreeFormat()
86
workingtree.format_registry.register(format)
87
self.addCleanup(workingtree.format_registry.remove, format)
88
self.assertTrue(isinstance(old_format, workingtree_4.WorkingTreeFormat6))
89
workingtree.format_registry.set_default_key(format.get_format_string())
91
# the default branch format is used by the meta dir format
92
# which is not the default bzrdir format at this point
93
dir = bzrdir.BzrDirMetaFormat1().initialize('.')
94
dir.create_repository()
96
result = dir.create_workingtree()
97
self.assertEqual(result, 'A tree')
99
workingtree.format_registry.set_default_key(
100
old_format.get_format_string())
101
self.assertEqual(old_format, workingtree.format_registry.get_default())
104
tree = self.make_branch_and_tree('.')
105
open_direct = workingtree.WorkingTree.open('.')
106
self.assertEqual(tree.basedir, open_direct.basedir)
107
open_no_args = workingtree.WorkingTree.open()
108
self.assertEqual(tree.basedir, open_no_args.basedir)
110
def test_open_containing(self):
111
tree = self.make_branch_and_tree('.')
112
open_direct, relpath = workingtree.WorkingTree.open_containing('.')
113
self.assertEqual(tree.basedir, open_direct.basedir)
114
self.assertEqual('', relpath)
115
open_no_args, relpath = workingtree.WorkingTree.open_containing()
116
self.assertEqual(tree.basedir, open_no_args.basedir)
117
self.assertEqual('', relpath)
118
open_subdir, relpath = workingtree.WorkingTree.open_containing('subdir')
119
self.assertEqual(tree.basedir, open_subdir.basedir)
120
self.assertEqual('subdir', relpath)
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())
123
86
class SampleTreeFormat(workingtree.WorkingTreeFormat):
124
87
"""A sample format
126
this format is initializable, unsupported to aid in testing the
89
this format is initializable, unsupported to aid in testing the
127
90
open and open_downlevel routines.
145
107
return "opened tree."
148
class SampleExtraTreeFormat(workingtree.WorkingTreeFormat):
149
"""A sample format that does not support use in a metadir.
153
def get_format_string(self):
154
# Not usable in a metadir, so no format string
157
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
158
accelerator_tree=None, hardlink=False):
159
raise NotImplementedError(self.initialize)
161
def is_supported(self):
164
def open(self, transport, _found=False):
165
raise NotImplementedError(self.open)
168
110
class TestWorkingTreeFormat(TestCaseWithTransport):
169
111
"""Tests for the WorkingTreeFormat facility."""
171
def test_find_format_string(self):
172
# is the right format object found for a working tree?
173
branch = self.make_branch('branch')
174
self.assertRaises(errors.NoWorkingTree,
175
workingtree.WorkingTreeFormat.find_format_string, branch.bzrdir)
176
transport = branch.bzrdir.get_workingtree_transport(None)
178
transport.put_bytes("format", "some format name")
179
# The format does not have to be known by Bazaar,
180
# find_format_string just retrieves the name
181
self.assertEquals("some format name",
182
workingtree.WorkingTreeFormat.find_format_string(branch.bzrdir))
184
113
def test_find_format(self):
185
114
# is the right format object found for a working tree?
186
115
# create a branch with a few known format objects.
220
149
format.initialize(dir)
221
150
# register a format for it.
222
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
223
workingtree.WorkingTreeFormat.register_format, format)
224
self.assertTrue(format in
225
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
226
workingtree.WorkingTreeFormat.get_formats))
151
workingtree.WorkingTreeFormat.register_format(format)
227
152
# which branch.Open will refuse (not supported)
228
153
self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
229
154
# but open_downlevel will work
230
155
self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
231
156
# unregister the format
232
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
233
workingtree.WorkingTreeFormat.unregister_format, format)
234
self.assertFalse(format in
235
self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
236
workingtree.WorkingTreeFormat.get_formats))
239
class TestWorkingTreeIterEntriesByDir_wSubtrees(TestCaseWithTransport):
241
def make_simple_tree(self):
242
tree = self.make_branch_and_tree('tree', format='development-subtree')
243
self.build_tree(['tree/a/', 'tree/a/b/', 'tree/a/b/c'])
244
tree.set_root_id('root-id')
245
tree.add(['a', 'a/b', 'a/b/c'], ['a-id', 'b-id', 'c-id'])
246
tree.commit('initial')
249
def test_just_directory(self):
250
tree = self.make_simple_tree()
251
self.assertEqual([('directory', 'root-id'),
252
('directory', 'a-id'),
253
('directory', 'b-id'),
255
[(ie.kind, ie.file_id)
256
for path, ie in tree.iter_entries_by_dir()])
257
subtree = self.make_branch_and_tree('tree/a/b')
258
self.assertEqual([('tree-reference', 'b-id')],
259
[(ie.kind, ie.file_id)
260
for path, ie in tree.iter_entries_by_dir(['b-id'])])
262
def test_direct_subtree(self):
263
tree = self.make_simple_tree()
264
subtree = self.make_branch_and_tree('tree/a/b')
265
self.assertEqual([('directory', 'root-id'),
266
('directory', 'a-id'),
267
('tree-reference', 'b-id')],
268
[(ie.kind, ie.file_id)
269
for path, ie in tree.iter_entries_by_dir()])
271
def test_indirect_subtree(self):
272
tree = self.make_simple_tree()
273
subtree = self.make_branch_and_tree('tree/a')
274
self.assertEqual([('directory', 'root-id'),
275
('tree-reference', 'a-id')],
276
[(ie.kind, ie.file_id)
277
for path, ie in tree.iter_entries_by_dir()])
280
class TestWorkingTreeFormatRegistry(TestCase):
283
super(TestWorkingTreeFormatRegistry, self).setUp()
284
self.registry = workingtree.WorkingTreeFormatRegistry()
286
def test_register_unregister_format(self):
287
format = SampleTreeFormat()
288
self.registry.register(format)
289
self.assertEquals(format, self.registry.get("Sample tree format."))
290
self.registry.remove(format)
291
self.assertRaises(KeyError, self.registry.get, "Sample tree format.")
293
def test_get_all(self):
294
format = SampleTreeFormat()
295
self.assertEquals([], self.registry._get_all())
296
self.registry.register(format)
297
self.assertEquals([format], self.registry._get_all())
299
def test_register_extra(self):
300
format = SampleExtraTreeFormat()
301
self.assertEquals([], self.registry._get_all())
302
self.registry.register_extra(format)
303
self.assertEquals([format], self.registry._get_all())
305
def test_register_extra_lazy(self):
306
self.assertEquals([], self.registry._get_all())
307
self.registry.register_extra_lazy("bzrlib.tests.test_workingtree",
308
"SampleExtraTreeFormat")
309
formats = self.registry._get_all()
310
self.assertEquals(1, len(formats))
311
self.assertIsInstance(formats[0], SampleExtraTreeFormat)
157
workingtree.WorkingTreeFormat.unregister_format(format)
314
160
class TestWorkingTreeFormat3(TestCaseWithTransport):
369
221
control = bzrdir.BzrDirMetaFormat1().initialize(self.get_url())
370
222
control.create_repository()
371
223
control.create_branch()
372
tree = workingtree_3.WorkingTreeFormat3().initialize(control)
373
tree._transport.delete("pending-merges")
224
tree = workingtree.WorkingTreeFormat3().initialize(control)
225
tree._control_files._transport.delete("pending-merges")
374
226
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
377
342
class InstrumentedTree(object):
378
343
"""A instrumented tree to check the needs_tree_write_lock decorator."""
418
383
self.assertEqual(['t', 'u'], tree._locks)
419
384
self.assertRaises(TypeError, tree.method_that_raises, 'foo')
420
385
self.assertEqual(['t', 'u', 't', 'u'], tree._locks)
423
class TestRevert(TestCaseWithTransport):
425
def test_revert_conflicts_recursive(self):
426
this_tree = self.make_branch_and_tree('this-tree')
427
self.build_tree_contents([('this-tree/foo/',),
428
('this-tree/foo/bar', 'bar')])
429
this_tree.add(['foo', 'foo/bar'])
430
this_tree.commit('created foo/bar')
431
other_tree = this_tree.bzrdir.sprout('other-tree').open_workingtree()
432
self.build_tree_contents([('other-tree/foo/bar', 'baz')])
433
other_tree.commit('changed bar')
434
self.build_tree_contents([('this-tree/foo/bar', 'qux')])
435
this_tree.commit('changed qux')
436
this_tree.merge_from_branch(other_tree.branch)
437
self.assertEqual(1, len(this_tree.conflicts()))
438
this_tree.revert(['foo'])
439
self.assertEqual(0, len(this_tree.conflicts()))
442
class TestAutoResolve(TestCaseWithTransport):
444
def test_auto_resolve(self):
445
base = self.make_branch_and_tree('base')
446
self.build_tree_contents([('base/hello', 'Hello')])
447
base.add('hello', 'hello_id')
449
other = base.bzrdir.sprout('other').open_workingtree()
450
self.build_tree_contents([('other/hello', 'hELLO')])
451
other.commit('Case switch')
452
this = base.bzrdir.sprout('this').open_workingtree()
453
self.assertPathExists('this/hello')
454
self.build_tree_contents([('this/hello', 'Hello World')])
455
this.commit('Add World')
456
this.merge_from_branch(other.branch)
457
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
460
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
462
self.build_tree_contents([('this/hello', '<<<<<<<')])
464
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
466
self.build_tree_contents([('this/hello', '=======')])
468
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
470
self.build_tree_contents([('this/hello', '\n>>>>>>>')])
471
remaining, resolved = this.auto_resolve()
472
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
474
self.assertEqual([], resolved)
475
self.build_tree_contents([('this/hello', 'hELLO wORLD')])
476
remaining, resolved = this.auto_resolve()
477
self.assertEqual([], this.conflicts())
478
self.assertEqual([conflicts.TextConflict('hello', 'hello_id')],
480
self.assertPathDoesNotExist('this/hello.BASE')
482
def test_auto_resolve_dir(self):
483
tree = self.make_branch_and_tree('tree')
484
self.build_tree(['tree/hello/'])
485
tree.add('hello', 'hello-id')
486
file_conflict = conflicts.TextConflict('file', 'hello-id')
487
tree.set_conflicts(conflicts.ConflictList([file_conflict]))
491
class TestFindTrees(TestCaseWithTransport):
493
def test_find_trees(self):
494
self.make_branch_and_tree('foo')
495
self.make_branch_and_tree('foo/bar')
496
# Sticking a tree inside a control dir is heinous, so let's skip it
497
self.make_branch_and_tree('foo/.bzr/baz')
498
self.make_branch('qux')
499
trees = workingtree.WorkingTree.find_trees('.')
500
self.assertEqual(2, len(list(trees)))