~bzr-pqm/bzr/bzr.dev

2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1540.1.7 by John Arbash Meinel
Added copyright statement to test_fileid_involved, and minor pep8 cleanup.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1540.1.7 by John Arbash Meinel
Added copyright statement to test_fileid_involved, and minor pep8 cleanup.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1540.1.7 by John Arbash Meinel
Added copyright statement to test_fileid_involved, and minor pep8 cleanup.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
16
17
import os
1711.7.29 by John Arbash Meinel
Switch to using TestSkipped for fileid_involved tests.
18
import sys
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
19
1545.2.9 by Aaron Bentley
Moved merge.merge to builtins
20
from bzrlib.builtins import merge
2294.1.2 by John Arbash Meinel
Track down and add tests that all tree.commit() can handle
21
from bzrlib.errors import IllegalPath, NonAsciiRevisionId
1551.2.55 by abentley
Fix fileid involed tests on win32 (by skipping them for unescaped weave formats)
22
from bzrlib.tests import TestSkipped
1534.4.41 by Robert Collins
Branch now uses BzrDir reasonably sanely.
23
from bzrlib.tests.repository_implementations.test_repository import TestCaseWithRepository
1711.7.4 by John Arbash Meinel
Fix test_fileid_involved so it uses TreeTransform to set the executable bits rather than chmod()
24
from bzrlib.transform import TreeTransform
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
25
from bzrlib.workingtree import WorkingTree
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
26
1534.7.154 by Aaron Bentley
Removed changes from bzr.ab 1529..1536
27
1534.4.54 by Robert Collins
Merge from integration.
28
class FileIdInvolvedBase(TestCaseWithRepository):
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
29
2018.5.96 by Andrew Bennetts
Merge from bzr.dev, resolving the worst of the semantic conflicts, but there's
30
    def touch(self, tree, filename):
2381.1.3 by Robert Collins
Review feedback.
31
        # use the trees transport to not depend on the tree's location or type.
2018.5.96 by Andrew Bennetts
Merge from bzr.dev, resolving the worst of the semantic conflicts, but there's
32
        tree.bzrdir.root_transport.append_bytes(filename, "appended line\n")
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
33
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
34
    def compare_tree_fileids(self, branch, old_rev, new_rev):
35
        old_tree = self.branch.repository.revision_tree(old_rev)
36
        new_tree = self.branch.repository.revision_tree(new_rev)
1852.10.3 by Robert Collins
Remove all uses of compare_trees and replace with Tree.changes_from throughout bzrlib.
37
        delta = new_tree.changes_from(old_tree)
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
38
39
        l2 = [id for path, id, kind in delta.added] + \
40
             [id for oldpath, newpath, id, kind, text_modified, \
41
                meta_modified in delta.renamed] + \
42
             [id for path, id, kind, text_modified, meta_modified in \
43
                delta.modified]
44
        return set(l2)
45
46
    
47
class TestFileIdInvolved(FileIdInvolvedBase):
48
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
49
    def setUp(self):
1185.64.9 by Goffredo Baroncelli
renamed test_file_involved -> test_fileid_involved
50
        super(TestFileIdInvolved, self).setUp()
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
51
        # create three branches, and merge it
52
        #
53
        #           /-->J ------>K                (branch2)
54
        #          /              \
55
        #  A ---> B --->C ---->D->G               (main)
56
        #  \           /      /
57
        #   \---> E---/----> F                 (branch1)
58
1694.2.6 by Martin Pool
[merge] bzr.dev
59
        # A changes: 
60
        # B changes: 'a-file-id-2006-01-01-abcd'
61
        # C changes:  Nothing (perfect merge)
62
        # D changes: 'b-file-id-2006-01-01-defg'
63
        # E changes: 'file-d'
64
        # F changes: 'file-d'
65
        # G changes: 'b-file-id-2006-01-01-defg'
66
        # J changes: 'b-file-id-2006-01-01-defg'
67
        # K changes: 'c-funky<file-id> quiji%bo'
68
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
69
        main_wt = self.make_branch_and_tree('main')
70
        main_branch = main_wt.branch
2381.1.3 by Robert Collins
Review feedback.
71
        self.build_tree(["main/a","main/b","main/c"])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
72
73
        main_wt.add(['a', 'b', 'c'], ['a-file-id-2006-01-01-abcd',
1540.1.6 by John Arbash Meinel
fileid_involved needs to unescape the file id and revision id
74
                                 'b-file-id-2006-01-01-defg',
75
                                 'c-funky<file-id> quiji%bo'])
1551.2.55 by abentley
Fix fileid involed tests on win32 (by skipping them for unescaped weave formats)
76
        try:
77
            main_wt.commit("Commit one", rev_id="rev-A")
78
        except IllegalPath:
1711.7.29 by John Arbash Meinel
Switch to using TestSkipped for fileid_involved tests.
79
            # TODO: jam 20060701 Consider raising a different exception
80
            #       newer formats do support this, and nothin can done to 
81
            #       correct this test - its not a bug.
82
            if sys.platform == 'win32':
83
                raise TestSkipped('Old repository formats do not'
84
                                  ' support file ids with <> on win32')
85
            # This is not a known error condition
86
            raise
87
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
88
        #-------- end A -----------
89
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
90
        bt1 = self.make_branch_and_tree('branch1')
91
        bt1.pull(main_branch)
92
        b1 = bt1.branch
2381.1.3 by Robert Collins
Review feedback.
93
        self.build_tree(["branch1/d"])
1694.2.6 by Martin Pool
[merge] bzr.dev
94
        bt1.add(['d'], ['file-d'])
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
95
        bt1.commit("branch1, Commit one", rev_id="rev-E")
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
96
97
        #-------- end E -----------
98
2018.5.96 by Andrew Bennetts
Merge from bzr.dev, resolving the worst of the semantic conflicts, but there's
99
        self.touch(main_wt, "a")
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
100
        main_wt.commit("Commit two", rev_id="rev-B")
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
101
102
        #-------- end B -----------
103
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
104
        bt2 = self.make_branch_and_tree('branch2')
105
        bt2.pull(main_branch)
106
        branch2_branch = bt2.branch
1711.7.4 by John Arbash Meinel
Fix test_fileid_involved so it uses TreeTransform to set the executable bits rather than chmod()
107
        set_executability(bt2, 'b', True)
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
108
        bt2.commit("branch2, Commit one", rev_id="rev-J")
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
109
110
        #-------- end J -----------
111
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
112
        main_wt.merge_from_branch(b1)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
113
        main_wt.commit("merge branch1, rev-11", rev_id="rev-C")
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
114
115
        #-------- end C -----------
116
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
117
        bt1.rename_one("d","e")
118
        bt1.commit("branch1, commit two", rev_id="rev-F")
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
119
120
        #-------- end F -----------
121
2018.5.96 by Andrew Bennetts
Merge from bzr.dev, resolving the worst of the semantic conflicts, but there's
122
        self.touch(bt2, "c")
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
123
        bt2.commit("branch2, commit two", rev_id="rev-K")
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
124
125
        #-------- end K -----------
126
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
127
        main_wt.merge_from_branch(b1)
2018.5.96 by Andrew Bennetts
Merge from bzr.dev, resolving the worst of the semantic conflicts, but there's
128
        self.touch(main_wt, "b")
1540.1.6 by John Arbash Meinel
fileid_involved needs to unescape the file id and revision id
129
        # D gets some funky characters to make sure the unescaping works
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
130
        main_wt.commit("merge branch1, rev-12", rev_id="rev-<D>")
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
131
132
        # end D
133
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
134
        main_wt.merge_from_branch(branch2_branch)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
135
        main_wt.commit("merge branch1, rev-22",  rev_id="rev-G")
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
136
137
        # end G
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
138
        self.branch = main_branch
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
139
1694.2.6 by Martin Pool
[merge] bzr.dev
140
    def test_fileids_altered_between_two_revs(self):
141
        def foo(old, new):
142
            print set(self.branch.repository.get_ancestry(new)).difference(set(self.branch.repository.get_ancestry(old)))
143
1711.7.16 by John Arbash Meinel
remove assertDictsEqual
144
        self.assertEqual(
1694.2.6 by Martin Pool
[merge] bzr.dev
145
            {'b-file-id-2006-01-01-defg':set(['rev-J']),
146
             'c-funky<file-id> quiji%bo':set(['rev-K'])
147
             },
148
            self.branch.repository.fileids_altered_by_revision_ids(["rev-J","rev-K"]))
149
1711.7.16 by John Arbash Meinel
remove assertDictsEqual
150
        self.assertEqual(
1694.2.6 by Martin Pool
[merge] bzr.dev
151
            {'b-file-id-2006-01-01-defg': set(['rev-<D>']),
152
             'file-d': set(['rev-F']),
153
             },
154
            self.branch.repository.fileids_altered_by_revision_ids(['rev-<D>', 'rev-F']))
155
1711.7.16 by John Arbash Meinel
remove assertDictsEqual
156
        self.assertEqual(
1694.2.6 by Martin Pool
[merge] bzr.dev
157
            {
158
             'b-file-id-2006-01-01-defg': set(['rev-<D>', 'rev-G', 'rev-J']), 
159
             'c-funky<file-id> quiji%bo': set(['rev-K']),
160
             'file-d': set(['rev-F']), 
161
             },
162
            self.branch.repository.fileids_altered_by_revision_ids(
163
                ['rev-<D>', 'rev-G', 'rev-F', 'rev-K', 'rev-J']))
164
1711.7.16 by John Arbash Meinel
remove assertDictsEqual
165
        self.assertEqual(
1694.2.6 by Martin Pool
[merge] bzr.dev
166
            {'a-file-id-2006-01-01-abcd': set(['rev-B']),
167
             'b-file-id-2006-01-01-defg': set(['rev-<D>', 'rev-G', 'rev-J']),
168
             'c-funky<file-id> quiji%bo': set(['rev-K']),
169
             'file-d': set(['rev-F']),
170
             },
171
            self.branch.repository.fileids_altered_by_revision_ids(
172
                ['rev-G', 'rev-F', 'rev-C', 'rev-B', 'rev-<D>', 'rev-K', 'rev-J']))
173
1910.2.24 by Aaron Bentley
Got intra-repository fetch working between model1 and 2 for all types
174
    def fileids_altered_by_revision_ids(self, revision_ids):
175
        """This is a wrapper to strip TREE_ROOT if it occurs"""
176
        repo = self.branch.repository
1731.1.49 by Aaron Bentley
Merge bzr.dev
177
        root_id = self.branch.basis_tree().inventory.root.file_id
1910.2.24 by Aaron Bentley
Got intra-repository fetch working between model1 and 2 for all types
178
        result = repo.fileids_altered_by_revision_ids(revision_ids)
1731.1.49 by Aaron Bentley
Merge bzr.dev
179
        if root_id in result:
180
            del result[root_id]
1910.2.24 by Aaron Bentley
Got intra-repository fetch working between model1 and 2 for all types
181
        return result
182
1694.2.6 by Martin Pool
[merge] bzr.dev
183
    def test_fileids_altered_by_revision_ids(self):
1711.7.16 by John Arbash Meinel
remove assertDictsEqual
184
        self.assertEqual(
1694.2.6 by Martin Pool
[merge] bzr.dev
185
            {'a-file-id-2006-01-01-abcd':set(['rev-A']),
186
             'b-file-id-2006-01-01-defg': set(['rev-A']),
187
             'c-funky<file-id> quiji%bo': set(['rev-A']),
188
             }, 
1910.2.24 by Aaron Bentley
Got intra-repository fetch working between model1 and 2 for all types
189
            self.fileids_altered_by_revision_ids(["rev-A"]))
1711.7.16 by John Arbash Meinel
remove assertDictsEqual
190
        self.assertEqual(
1694.2.6 by Martin Pool
[merge] bzr.dev
191
            {'a-file-id-2006-01-01-abcd':set(['rev-B'])
192
             }, 
193
            self.branch.repository.fileids_altered_by_revision_ids(["rev-B"]))
1711.7.16 by John Arbash Meinel
remove assertDictsEqual
194
        self.assertEqual(
1694.2.6 by Martin Pool
[merge] bzr.dev
195
            {'b-file-id-2006-01-01-defg':set(['rev-<D>'])
196
             },
197
            self.branch.repository.fileids_altered_by_revision_ids(["rev-<D>"]))
198
199
    def test_fileids_involved_full_compare(self):
200
        # this tests that the result of each fileid_involved calculation 
201
        # along a revision history selects only the fileids selected by
202
        # comparing the trees - no less, and no more. This is correct 
203
        # because in our sample data we do not revert any file ids along
204
        # the revision history.
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
205
        pp=[]
206
        history = self.branch.revision_history( )
207
208
        if len(history) < 2: return
209
210
        for start in range(0,len(history)-1):
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
211
            start_id = history[start]
1185.64.7 by Goffredo Baroncelli
added test for function fileid_involved
212
            for end in range(start+1,len(history)):
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
213
                end_id = history[end]
1694.2.6 by Martin Pool
[merge] bzr.dev
214
                old_revs = set(self.branch.repository.get_ancestry(start_id))
215
                new_revs = set(self.branch.repository.get_ancestry(end_id))
216
                l1 = self.branch.repository.fileids_altered_by_revision_ids(
217
                    new_revs.difference(old_revs))
218
                l1 = set(l1.keys())
219
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
220
                l2 = self.compare_tree_fileids(self.branch, start_id, end_id)
221
                self.assertEquals(l1, l2)
222
223
2294.1.2 by John Arbash Meinel
Track down and add tests that all tree.commit() can handle
224
class TestFileIdInvolvedNonAscii(FileIdInvolvedBase):
225
226
    def test_utf8_file_ids_and_revision_ids(self):
227
        main_wt = self.make_branch_and_tree('main')
228
        main_branch = main_wt.branch
2381.1.3 by Robert Collins
Review feedback.
229
        self.build_tree(["main/a"])
2294.1.2 by John Arbash Meinel
Track down and add tests that all tree.commit() can handle
230
2294.1.10 by John Arbash Meinel
Switch all apis over to utf8 file ids. All tests pass
231
        file_id = u'a-f\xedle-id'.encode('utf8')
2294.1.2 by John Arbash Meinel
Track down and add tests that all tree.commit() can handle
232
        main_wt.add(['a'], [file_id])
233
        revision_id = u'r\xe9v-a'.encode('utf8')
234
        try:
235
            main_wt.commit('a', rev_id=revision_id)
236
        except NonAsciiRevisionId:
237
            raise TestSkipped('non-ascii revision ids not supported by %s'
238
                              % self.repository_format)
239
240
        repo = main_wt.branch.repository
241
        file_ids = repo.fileids_altered_by_revision_ids([revision_id])
2255.7.43 by Robert Collins
Fix fileid_involved tests to not access inventories when not needed.
242
        root_id = main_wt.basis_tree().path2id('')
2294.1.2 by John Arbash Meinel
Track down and add tests that all tree.commit() can handle
243
        if root_id in file_ids:
244
            self.assertEqual({file_id:set([revision_id]),
245
                              root_id:set([revision_id])
246
                             }, file_ids)
247
        else:
248
            self.assertEqual({file_id:set([revision_id])}, file_ids)
249
250
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
251
class TestFileIdInvolvedSuperset(FileIdInvolvedBase):
252
253
    def setUp(self):
254
        super(TestFileIdInvolvedSuperset, self).setUp()
255
1711.7.4 by John Arbash Meinel
Fix test_fileid_involved so it uses TreeTransform to set the executable bits rather than chmod()
256
        self.branch = None
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
257
        main_wt = self.make_branch_and_tree('main')
258
        main_branch = main_wt.branch
2381.1.3 by Robert Collins
Review feedback.
259
        self.build_tree(["main/a","main/b","main/c"])
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
260
261
        main_wt.add(['a', 'b', 'c'], ['a-file-id-2006-01-01-abcd',
262
                                 'b-file-id-2006-01-01-defg',
1843.2.3 by Aaron Bentley
Add test case for fileid_involved
263
                                 'c-funky<file-id> quiji\'"%bo'])
1551.2.55 by abentley
Fix fileid involed tests on win32 (by skipping them for unescaped weave formats)
264
        try:
265
            main_wt.commit("Commit one", rev_id="rev-A")
1694.2.6 by Martin Pool
[merge] bzr.dev
266
        except IllegalPath: 
1711.7.29 by John Arbash Meinel
Switch to using TestSkipped for fileid_involved tests.
267
            # TODO: jam 20060701 Consider raising a different exception
268
            #       newer formats do support this, and nothin can done to 
269
            #       correct this test - its not a bug.
270
            if sys.platform == 'win32':
271
                raise TestSkipped('Old repository formats do not'
272
                                  ' support file ids with <> on win32')
273
            # This is not a known error condition
274
            raise
1910.2.29 by Aaron Bentley
Fix up sprout, nuke workaround
275
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
276
        branch2_wt = self.make_branch_and_tree('branch2')
277
        branch2_wt.pull(main_branch)
278
        branch2_bzrdir = branch2_wt.bzrdir
1534.5.3 by Robert Collins
Make format 4/5/6 branches share a single LockableFiles instance across wt/branch/repository.
279
        branch2_branch = branch2_bzrdir.open_branch()
1711.7.4 by John Arbash Meinel
Fix test_fileid_involved so it uses TreeTransform to set the executable bits rather than chmod()
280
        set_executability(branch2_wt, 'b', True)
1534.5.3 by Robert Collins
Make format 4/5/6 branches share a single LockableFiles instance across wt/branch/repository.
281
        branch2_wt.commit("branch2, Commit one", rev_id="rev-J")
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
282
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
283
        main_wt.merge_from_branch(branch2_branch)
1711.7.15 by John Arbash Meinel
Properly handle the case when you want to turn off executability.
284
        set_executability(main_wt, 'b', False)
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
285
        main_wt.commit("merge branch1, rev-22",  rev_id="rev-G")
286
287
        # end G
288
        self.branch = main_branch
289
290
    def test_fileid_involved_full_compare2(self):
1694.2.6 by Martin Pool
[merge] bzr.dev
291
        # this tests that fileids_alteted_by_revision_ids returns 
292
        # more information than compare_tree can, because it 
293
        # sees each change rather than the aggregate delta.
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
294
        history = self.branch.revision_history()
295
        old_rev = history[0]
296
        new_rev = history[1]
1694.2.6 by Martin Pool
[merge] bzr.dev
297
        old_revs = set(self.branch.repository.get_ancestry(old_rev))
298
        new_revs = set(self.branch.repository.get_ancestry(new_rev))
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
299
1694.2.6 by Martin Pool
[merge] bzr.dev
300
        l1 = self.branch.repository.fileids_altered_by_revision_ids(
301
            new_revs.difference(old_revs))
302
        l1 = set(l1.keys())
1551.2.7 by Aaron Bentley
Test case for discrepancy between fileid_involved and compare_tree [recommit]
303
304
        l2 = self.compare_tree_fileids(self.branch, old_rev, new_rev)
305
        self.assertNotEqual(l2, l1)
1553.5.28 by Martin Pool
[merge] from bzr.dev before integration
306
        self.assertSubset(l2, l1)
1711.7.4 by John Arbash Meinel
Fix test_fileid_involved so it uses TreeTransform to set the executable bits rather than chmod()
307
308
309
def set_executability(wt, path, executable=True):
310
    """Set the executable bit for the file at path in the working tree
311
312
    os.chmod() doesn't work on windows. But TreeTransform can mark or
313
    unmark a file as executable.
314
    """
315
    file_id = wt.path2id(path)
316
    tt = TreeTransform(wt)
1711.7.5 by John Arbash Meinel
Call finalize() though it doesn't help to release resources to allow cleanup.
317
    try:
1711.7.15 by John Arbash Meinel
Properly handle the case when you want to turn off executability.
318
        tt.set_executability(executable, tt.trans_id_tree_file_id(file_id))
1711.7.5 by John Arbash Meinel
Call finalize() though it doesn't help to release resources to allow cleanup.
319
        tt.apply()
320
    finally:
321
        tt.finalize()