~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/per_repository_vf/test_fileid_involved.py

  • Committer: Vincent Ladeuil
  • Date: 2011-10-04 11:38:49 UTC
  • mfrom: (6184 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6185.
  • Revision ID: v.ladeuil+lp@free.fr-20111004113849-9os4pc4swnvdklxk
Merge trunk to resolve conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
import time
18
18
 
19
19
from bzrlib import (
 
20
    errors,
20
21
    inventory,
21
22
    remote,
22
23
    revision as _mod_revision,
23
24
    tests,
 
25
    transform,
24
26
    )
25
27
from bzrlib.tests.scenarios import load_tests_apply_scenarios
26
28
from bzrlib.tests.per_repository_vf import (
113
115
        if stacked.repository.supports_rich_root():
114
116
            keys['root-id'] = set(['A-id'])
115
117
        self.assertEqual(keys, repo.fileids_altered_by_revision_ids(['A-id']))
 
118
 
 
119
 
 
120
class FileIdInvolvedBase(TestCaseWithRepository):
 
121
 
 
122
    def touch(self, tree, filename):
 
123
        # use the trees transport to not depend on the tree's location or type.
 
124
        tree.bzrdir.root_transport.append_bytes(filename, "appended line\n")
 
125
 
 
126
    def compare_tree_fileids(self, branch, old_rev, new_rev):
 
127
        old_tree = self.branch.repository.revision_tree(old_rev)
 
128
        new_tree = self.branch.repository.revision_tree(new_rev)
 
129
        delta = new_tree.changes_from(old_tree)
 
130
 
 
131
        l2 = [id for path, id, kind in delta.added] + \
 
132
             [id for oldpath, newpath, id, kind, text_modified, \
 
133
                meta_modified in delta.renamed] + \
 
134
             [id for path, id, kind, text_modified, meta_modified in \
 
135
                delta.modified]
 
136
        return set(l2)
 
137
 
 
138
 
 
139
class TestFileIdInvolved(FileIdInvolvedBase):
 
140
 
 
141
    scenarios = all_repository_vf_format_scenarios()
 
142
 
 
143
    def setUp(self):
 
144
        super(TestFileIdInvolved, self).setUp()
 
145
        # create three branches, and merge it
 
146
        #
 
147
        #          ,-->J------>K                (branch2)
 
148
        #         /             \
 
149
        #  A --->B --->C---->D-->G              (main)
 
150
        #  \          /     /
 
151
        #   '--->E---+---->F                    (branch1)
 
152
 
 
153
        # A changes:
 
154
        # B changes: 'a-file-id-2006-01-01-abcd'
 
155
        # C changes:  Nothing (perfect merge)
 
156
        # D changes: 'b-file-id-2006-01-01-defg'
 
157
        # E changes: 'file-d'
 
158
        # F changes: 'file-d'
 
159
        # G changes: 'b-file-id-2006-01-01-defg'
 
160
        # J changes: 'b-file-id-2006-01-01-defg'
 
161
        # K changes: 'c-funky<file-id>quiji%bo'
 
162
 
 
163
        main_wt = self.make_branch_and_tree('main')
 
164
        main_branch = main_wt.branch
 
165
        self.build_tree(["main/a","main/b","main/c"])
 
166
 
 
167
        main_wt.add(['a', 'b', 'c'], ['a-file-id-2006-01-01-abcd',
 
168
                                 'b-file-id-2006-01-01-defg',
 
169
                                 'c-funky<file-id>quiji%bo'])
 
170
        try:
 
171
            main_wt.commit("Commit one", rev_id="rev-A")
 
172
        except errors.IllegalPath:
 
173
            # TODO: jam 20060701 Consider raising a different exception
 
174
            #       newer formats do support this, and nothin can done to
 
175
            #       correct this test - its not a bug.
 
176
            if sys.platform == 'win32':
 
177
                raise tests.TestSkipped('Old repository formats do not'
 
178
                                        ' support file ids with <> on win32')
 
179
            # This is not a known error condition
 
180
            raise
 
181
 
 
182
        #-------- end A -----------
 
183
 
 
184
        bt1 = self.make_branch_and_tree('branch1')
 
185
        bt1.pull(main_branch)
 
186
        b1 = bt1.branch
 
187
        self.build_tree(["branch1/d"])
 
188
        bt1.add(['d'], ['file-d'])
 
189
        bt1.commit("branch1, Commit one", rev_id="rev-E")
 
190
 
 
191
        #-------- end E -----------
 
192
 
 
193
        self.touch(main_wt, "a")
 
194
        main_wt.commit("Commit two", rev_id="rev-B")
 
195
 
 
196
        #-------- end B -----------
 
197
 
 
198
        bt2 = self.make_branch_and_tree('branch2')
 
199
        bt2.pull(main_branch)
 
200
        branch2_branch = bt2.branch
 
201
        set_executability(bt2, 'b', True)
 
202
        bt2.commit("branch2, Commit one", rev_id="rev-J")
 
203
 
 
204
        #-------- end J -----------
 
205
 
 
206
        main_wt.merge_from_branch(b1)
 
207
        main_wt.commit("merge branch1, rev-11", rev_id="rev-C")
 
208
 
 
209
        #-------- end C -----------
 
210
 
 
211
        bt1.rename_one("d","e")
 
212
        bt1.commit("branch1, commit two", rev_id="rev-F")
 
213
 
 
214
        #-------- end F -----------
 
215
 
 
216
        self.touch(bt2, "c")
 
217
        bt2.commit("branch2, commit two", rev_id="rev-K")
 
218
 
 
219
        #-------- end K -----------
 
220
 
 
221
        main_wt.merge_from_branch(b1)
 
222
        self.touch(main_wt, "b")
 
223
        # D gets some funky characters to make sure the unescaping works
 
224
        main_wt.commit("merge branch1, rev-12", rev_id="rev-<D>")
 
225
 
 
226
        # end D
 
227
 
 
228
        main_wt.merge_from_branch(branch2_branch)
 
229
        main_wt.commit("merge branch1, rev-22",  rev_id="rev-G")
 
230
 
 
231
        # end G
 
232
        self.branch = main_branch
 
233
 
 
234
    def test_fileids_altered_between_two_revs(self):
 
235
        self.branch.lock_read()
 
236
        self.addCleanup(self.branch.unlock)
 
237
        self.branch.repository.fileids_altered_by_revision_ids(["rev-J","rev-K"])
 
238
        self.assertEqual(
 
239
            {'b-file-id-2006-01-01-defg':set(['rev-J']),
 
240
             'c-funky<file-id>quiji%bo':set(['rev-K'])
 
241
             },
 
242
            self.branch.repository.fileids_altered_by_revision_ids(["rev-J","rev-K"]))
 
243
 
 
244
        self.assertEqual(
 
245
            {'b-file-id-2006-01-01-defg': set(['rev-<D>']),
 
246
             'file-d': set(['rev-F']),
 
247
             },
 
248
            self.branch.repository.fileids_altered_by_revision_ids(['rev-<D>', 'rev-F']))
 
249
 
 
250
        self.assertEqual(
 
251
            {
 
252
             'b-file-id-2006-01-01-defg': set(['rev-<D>', 'rev-G', 'rev-J']),
 
253
             'c-funky<file-id>quiji%bo': set(['rev-K']),
 
254
             'file-d': set(['rev-F']),
 
255
             },
 
256
            self.branch.repository.fileids_altered_by_revision_ids(
 
257
                ['rev-<D>', 'rev-G', 'rev-F', 'rev-K', 'rev-J']))
 
258
 
 
259
        self.assertEqual(
 
260
            {'a-file-id-2006-01-01-abcd': set(['rev-B']),
 
261
             'b-file-id-2006-01-01-defg': set(['rev-<D>', 'rev-G', 'rev-J']),
 
262
             'c-funky<file-id>quiji%bo': set(['rev-K']),
 
263
             'file-d': set(['rev-F']),
 
264
             },
 
265
            self.branch.repository.fileids_altered_by_revision_ids(
 
266
                ['rev-G', 'rev-F', 'rev-C', 'rev-B', 'rev-<D>', 'rev-K', 'rev-J']))
 
267
 
 
268
    def fileids_altered_by_revision_ids(self, revision_ids):
 
269
        """This is a wrapper to strip TREE_ROOT if it occurs"""
 
270
        repo = self.branch.repository
 
271
        root_id = self.branch.basis_tree().get_root_id()
 
272
        result = repo.fileids_altered_by_revision_ids(revision_ids)
 
273
        if root_id in result:
 
274
            del result[root_id]
 
275
        return result
 
276
 
 
277
    def test_fileids_altered_by_revision_ids(self):
 
278
        self.branch.lock_read()
 
279
        self.addCleanup(self.branch.unlock)
 
280
        self.assertEqual(
 
281
            {'a-file-id-2006-01-01-abcd':set(['rev-A']),
 
282
             'b-file-id-2006-01-01-defg': set(['rev-A']),
 
283
             'c-funky<file-id>quiji%bo': set(['rev-A']),
 
284
             },
 
285
            self.fileids_altered_by_revision_ids(["rev-A"]))
 
286
        self.assertEqual(
 
287
            {'a-file-id-2006-01-01-abcd':set(['rev-B'])
 
288
             },
 
289
            self.branch.repository.fileids_altered_by_revision_ids(["rev-B"]))
 
290
        self.assertEqual(
 
291
            {'b-file-id-2006-01-01-defg':set(['rev-<D>'])
 
292
             },
 
293
            self.branch.repository.fileids_altered_by_revision_ids(["rev-<D>"]))
 
294
 
 
295
    def test_fileids_involved_full_compare(self):
 
296
        # this tests that the result of each fileid_involved calculation
 
297
        # along a revision history selects only the fileids selected by
 
298
        # comparing the trees - no less, and no more. This is correct
 
299
        # because in our sample data we do not revert any file ids along
 
300
        # the revision history.
 
301
        self.branch.lock_read()
 
302
        self.addCleanup(self.branch.unlock)
 
303
        pp=[]
 
304
        history = self.branch.revision_history( )
 
305
 
 
306
        if len(history) < 2: return
 
307
 
 
308
        graph = self.branch.repository.get_graph()
 
309
        for start in range(0,len(history)-1):
 
310
            start_id = history[start]
 
311
            for end in range(start+1,len(history)):
 
312
                end_id = history[end]
 
313
                unique_revs = graph.find_unique_ancestors(end_id, [start_id])
 
314
                l1 = self.branch.repository.fileids_altered_by_revision_ids(
 
315
                    unique_revs)
 
316
                l1 = set(l1.keys())
 
317
                l2 = self.compare_tree_fileids(self.branch, start_id, end_id)
 
318
                self.assertEquals(l1, l2)
 
319
 
 
320
 
 
321
class TestFileIdInvolvedNonAscii(FileIdInvolvedBase):
 
322
 
 
323
    scenarios = all_repository_vf_format_scenarios()
 
324
 
 
325
    def test_utf8_file_ids_and_revision_ids(self):
 
326
        main_wt = self.make_branch_and_tree('main')
 
327
        main_branch = main_wt.branch
 
328
        self.build_tree(["main/a"])
 
329
 
 
330
        file_id = u'a-f\xedle-id'.encode('utf8')
 
331
        main_wt.add(['a'], [file_id])
 
332
        revision_id = u'r\xe9v-a'.encode('utf8')
 
333
        try:
 
334
            main_wt.commit('a', rev_id=revision_id)
 
335
        except errors.NonAsciiRevisionId:
 
336
            raise tests.TestSkipped('non-ascii revision ids not supported by %s'
 
337
                                    % self.repository_format)
 
338
 
 
339
        repo = main_wt.branch.repository
 
340
        repo.lock_read()
 
341
        self.addCleanup(repo.unlock)
 
342
        file_ids = repo.fileids_altered_by_revision_ids([revision_id])
 
343
        root_id = main_wt.basis_tree().get_root_id()
 
344
        if root_id in file_ids:
 
345
            self.assertEqual({file_id:set([revision_id]),
 
346
                              root_id:set([revision_id])
 
347
                             }, file_ids)
 
348
        else:
 
349
            self.assertEqual({file_id:set([revision_id])}, file_ids)
 
350
 
 
351
 
 
352
class TestFileIdInvolvedSuperset(FileIdInvolvedBase):
 
353
 
 
354
    scenarios = all_repository_vf_format_scenarios()
 
355
 
 
356
    def setUp(self):
 
357
        super(TestFileIdInvolvedSuperset, self).setUp()
 
358
 
 
359
        self.branch = None
 
360
        main_wt = self.make_branch_and_tree('main')
 
361
        main_branch = main_wt.branch
 
362
        self.build_tree(["main/a","main/b","main/c"])
 
363
 
 
364
        main_wt.add(['a', 'b', 'c'], ['a-file-id-2006-01-01-abcd',
 
365
                                 'b-file-id-2006-01-01-defg',
 
366
                                 'c-funky<file-id>quiji\'"%bo'])
 
367
        try:
 
368
            main_wt.commit("Commit one", rev_id="rev-A")
 
369
        except errors.IllegalPath:
 
370
            # TODO: jam 20060701 Consider raising a different exception
 
371
            #       newer formats do support this, and nothin can done to
 
372
            #       correct this test - its not a bug.
 
373
            if sys.platform == 'win32':
 
374
                raise tests.TestSkipped('Old repository formats do not'
 
375
                                        ' support file ids with <> on win32')
 
376
            # This is not a known error condition
 
377
            raise
 
378
 
 
379
        branch2_wt = self.make_branch_and_tree('branch2')
 
380
        branch2_wt.pull(main_branch)
 
381
        branch2_bzrdir = branch2_wt.bzrdir
 
382
        branch2_branch = branch2_bzrdir.open_branch()
 
383
        set_executability(branch2_wt, 'b', True)
 
384
        branch2_wt.commit("branch2, Commit one", rev_id="rev-J")
 
385
 
 
386
        main_wt.merge_from_branch(branch2_branch)
 
387
        set_executability(main_wt, 'b', False)
 
388
        main_wt.commit("merge branch1, rev-22",  rev_id="rev-G")
 
389
 
 
390
        # end G
 
391
        self.branch = main_branch
 
392
 
 
393
    def test_fileid_involved_full_compare2(self):
 
394
        # this tests that fileids_altered_by_revision_ids returns
 
395
        # more information than compare_tree can, because it
 
396
        # sees each change rather than the aggregate delta.
 
397
        self.branch.lock_read()
 
398
        self.addCleanup(self.branch.unlock)
 
399
        history = self.branch.revision_history()
 
400
        old_rev = history[0]
 
401
        new_rev = history[1]
 
402
        graph = self.branch.repository.get_graph()
 
403
        unique_revs = graph.find_unique_ancestors(new_rev, [old_rev])
 
404
 
 
405
        l1 = self.branch.repository.fileids_altered_by_revision_ids(
 
406
            unique_revs)
 
407
        l1 = set(l1.keys())
 
408
 
 
409
        l2 = self.compare_tree_fileids(self.branch, old_rev, new_rev)
 
410
        self.assertNotEqual(l2, l1)
 
411
        self.assertSubset(l2, l1)
 
412
 
 
413
 
 
414
def set_executability(wt, path, executable=True):
 
415
    """Set the executable bit for the file at path in the working tree
 
416
 
 
417
    os.chmod() doesn't work on windows. But TreeTransform can mark or
 
418
    unmark a file as executable.
 
419
    """
 
420
    file_id = wt.path2id(path)
 
421
    tt = transform.TreeTransform(wt)
 
422
    try:
 
423
        tt.set_executability(executable, tt.trans_id_tree_file_id(file_id))
 
424
        tt.apply()
 
425
    finally:
 
426
        tt.finalize()