Merge lp:~jelmer/bzr/per-wt-executable into lp:bzr

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merged at revision: 6388
Proposed branch: lp:~jelmer/bzr/per-wt-executable
Merge into: lp:bzr
Diff against target: 196 lines (+51/-37)
6 files modified
bzrlib/tests/per_tree/test_path_content_summary.py (+1/-4)
bzrlib/tests/per_workingtree/test_executable.py (+4/-6)
bzrlib/tests/per_workingtree/test_workingtree.py (+18/-0)
bzrlib/transform.py (+7/-2)
bzrlib/workingtree.py (+15/-11)
bzrlib/workingtree_4.py (+6/-14)
To merge this branch: bzr merge lp:~jelmer/bzr/per-wt-executable
Reviewer Review Type Date Requested Status
Martin Pool Approve
Review via email: mp+86097@code.launchpad.net

Commit message

Make the check to see whether executable bits are supported per-workingtree, rather than global.

Description of the change

Make the check to see whether executable bits are supported per-workingtree, rather than global.

This is the first step towards supporting file systems without support for the
executable bit (NTFS, FAT) properly when running on POSIX (bug 248333)

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

  vote approve

review: Approve
Revision history for this message
Jelmer Vernooij (jelmer) 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 'bzrlib/tests/per_tree/test_path_content_summary.py'
2--- bzrlib/tests/per_tree/test_path_content_summary.py 2011-06-14 01:26:41 +0000
3+++ bzrlib/tests/per_tree/test_path_content_summary.py 2011-12-19 17:09:23 +0000
4@@ -133,10 +133,7 @@
5 self.assertEqual('file', summary[0])
6 self.check_content_summary_size(tree, summary, 22)
7 # not executable
8- if osutils.supports_executable:
9- self.assertEqual(False, summary[2])
10- else:
11- self.assertEqual(None, summary[2])
12+ self.assertEqual(False, summary[2])
13 # may have hash,
14 self.assertSubset((summary[3],),
15 (None, '0c352290ae1c26ca7f97d5b2906c4624784abd60'))
16
17=== modified file 'bzrlib/tests/per_workingtree/test_executable.py'
18--- bzrlib/tests/per_workingtree/test_executable.py 2011-05-13 12:51:05 +0000
19+++ bzrlib/tests/per_workingtree/test_executable.py 2011-12-19 17:09:23 +0000
20@@ -189,9 +189,7 @@
21 self.assertFalse(b_executable)
22
23 def test_use_exec_from_basis(self):
24- if osutils.supports_executable():
25- self.assertEqual(self.wt._is_executable_from_path_and_stat_from_stat,
26- self.wt._is_executable_from_path_and_stat)
27- else:
28- self.assertEqual(self.wt._is_executable_from_path_and_stat_from_basis,
29- self.wt._is_executable_from_path_and_stat)
30+ self.wt._supports_executable = lambda: False
31+ self.addCleanup(self.wt.lock_read().unlock)
32+ self.assertTrue(self.wt.is_executable(self.a_id))
33+ self.assertFalse(self.wt.is_executable(self.b_id))
34
35=== modified file 'bzrlib/tests/per_workingtree/test_workingtree.py'
36--- bzrlib/tests/per_workingtree/test_workingtree.py 2011-11-08 19:09:55 +0000
37+++ bzrlib/tests/per_workingtree/test_workingtree.py 2011-12-19 17:09:23 +0000
38@@ -960,6 +960,24 @@
39 tree = tree.bzrdir.open_workingtree()
40 self.assertFalse(tree.case_sensitive)
41
42+ def test_supports_executable(self):
43+ self.build_tree(['filename'])
44+ tree = self.make_branch_and_tree('.')
45+ tree.add('filename')
46+ self.assertIsInstance(tree._supports_executable(), bool)
47+ if tree._supports_executable():
48+ tree.lock_read()
49+ try:
50+ self.assertFalse(tree.is_executable(tree.path2id('filename')))
51+ finally:
52+ tree.unlock()
53+ os.chmod('filename', 0755)
54+ self.addCleanup(tree.lock_read().unlock)
55+ self.assertTrue(tree.is_executable(tree.path2id('filename')))
56+ else:
57+ self.addCleanup(tree.lock_read().unlock)
58+ self.assertFalse(tree.is_executable(tree.path2id('filename')))
59+
60 def test_all_file_ids_with_missing(self):
61 tree = self.make_branch_and_tree('tree')
62 tree.lock_write()
63
64=== modified file 'bzrlib/transform.py'
65--- bzrlib/transform.py 2011-12-18 12:46:49 +0000
66+++ bzrlib/transform.py 2011-12-19 17:09:23 +0000
67@@ -763,7 +763,7 @@
68
69 def _set_executability(self, path, trans_id):
70 """Set the executability of versioned files """
71- if supports_executable():
72+ if self._tree._supports_executable():
73 new_executability = self._new_executability[trans_id]
74 abspath = self._tree.abspath(path)
75 current_mode = os.stat(abspath).st_mode
76@@ -1233,6 +1233,11 @@
77 finally:
78 TreeTransformBase.finalize(self)
79
80+ def _limbo_supports_executable(self):
81+ """Check if the limbo path supports the executable bit."""
82+ # FIXME: Check actual file system capabilities of limbodir
83+ return osutils.supports_executable()
84+
85 def _limbo_name(self, trans_id):
86 """Generate the limbo name of a file"""
87 limbo_name = self._limbo_files.get(trans_id)
88@@ -2321,7 +2326,7 @@
89 if kind == 'file':
90 statval = os.lstat(limbo_name)
91 size = statval.st_size
92- if not supports_executable():
93+ if not tt._limbo_supports_executable():
94 executable = False
95 else:
96 executable = statval.st_mode & S_IEXEC
97
98=== modified file 'bzrlib/workingtree.py'
99--- bzrlib/workingtree.py 2011-12-19 13:23:58 +0000
100+++ bzrlib/workingtree.py 2011-12-19 17:09:23 +0000
101@@ -89,7 +89,6 @@
102 realpath,
103 safe_unicode,
104 splitpath,
105- supports_executable,
106 )
107 from bzrlib.trace import mutter, note
108 from bzrlib.revision import CURRENT_REVISION
109@@ -233,6 +232,12 @@
110 """See `Tree.has_versioned_directories`."""
111 return self._format.supports_versioned_directories
112
113+ def _supports_executable(self):
114+ if sys.platform == 'win32':
115+ return False
116+ # FIXME: Ideally this should check the file system
117+ return True
118+
119 def break_lock(self):
120 """Break a lock if one is present from another instance.
121
122@@ -1117,7 +1122,7 @@
123 else:
124 mode = stat_value.st_mode
125 kind = osutils.file_kind_from_stat_mode(mode)
126- if not supports_executable():
127+ if not self._supports_executable():
128 executable = entry is not None and entry.executable
129 else:
130 executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
131@@ -2192,21 +2197,20 @@
132 mode = stat_result.st_mode
133 return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
134
135- if not supports_executable():
136- def is_executable(self, file_id, path=None):
137+ def is_executable(self, file_id, path=None):
138+ if not self._supports_executable():
139 return self._inventory[file_id].executable
140-
141- _is_executable_from_path_and_stat = \
142- _is_executable_from_path_and_stat_from_basis
143- else:
144- def is_executable(self, file_id, path=None):
145+ else:
146 if not path:
147 path = self.id2path(file_id)
148 mode = os.lstat(self.abspath(path)).st_mode
149 return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
150
151- _is_executable_from_path_and_stat = \
152- _is_executable_from_path_and_stat_from_stat
153+ def _is_executable_from_path_and_stat(self, path, stat_result):
154+ if not self._supports_executable():
155+ return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
156+ else:
157+ return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
158
159 @needs_tree_write_lock
160 def _add(self, files, ids, kinds):
161
162=== modified file 'bzrlib/workingtree_4.py'
163--- bzrlib/workingtree_4.py 2011-12-19 13:23:58 +0000
164+++ bzrlib/workingtree_4.py 2011-12-19 17:09:23 +0000
165@@ -478,25 +478,17 @@
166 return False # Missing entries are not executable
167 return entry[1][0][3] # Executable?
168
169- if not osutils.supports_executable():
170- def is_executable(self, file_id, path=None):
171- """Test if a file is executable or not.
172+ def is_executable(self, file_id, path=None):
173+ """Test if a file is executable or not.
174
175- Note: The caller is expected to take a read-lock before calling this.
176- """
177+ Note: The caller is expected to take a read-lock before calling this.
178+ """
179+ if not self._supports_executable():
180 entry = self._get_entry(file_id=file_id, path=path)
181 if entry == (None, None):
182 return False
183 return entry[1][0][3]
184-
185- _is_executable_from_path_and_stat = \
186- _is_executable_from_path_and_stat_from_basis
187- else:
188- def is_executable(self, file_id, path=None):
189- """Test if a file is executable or not.
190-
191- Note: The caller is expected to take a read-lock before calling this.
192- """
193+ else:
194 self._must_be_locked()
195 if not path:
196 path = self.id2path(file_id)