/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2009, 2010, 2011 Canonical Ltd
4584.3.21 by Martin Pool
Start adding tests for apport
2
#
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.
7
#
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.
12
#
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
17
"""A collection of commonly used 'Features' to optionally run tests.
18
"""
5241.2.1 by Robert Collins
Merge up from 2.0/2.1:
19
6728.1.2 by Jelmer Vernooij
Sign using python-gpg rather than command-line gpg.
20
from __future__ import absolute_import
21
6803.3.1 by Martin
Use importlib for ModuleAvailableFeature
22
import importlib
5036.3.8 by Parth Malwankar
closed review comments from vila
23
import os
6060.1.1 by John Arbash Meinel
import subprocess in 'bzrlib.tests.features' so that certain features can properly probe.
24
import subprocess
5036.3.8 by Parth Malwankar
closed review comments from vila
25
import stat
5609.47.1 by Alexander Belchenko
Win32Feature
26
import sys
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
27
import tempfile
6760.1.1 by Jelmer Vernooij
Ignore DeprecationWarning/PendingDeprecationWarning during module probes. We can't do anything about these anyway.
28
import warnings
4584.3.21 by Martin Pool
Start adding tests for apport
29
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
30
from .. import (
5321.2.1 by Vincent Ladeuil
Fix style issues, including vertical spaces, lines too long and multi lines imports.
31
    osutils,
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
32
    symbol_versioning,
5321.2.1 by Vincent Ladeuil
Fix style issues, including vertical spaces, lines too long and multi lines imports.
33
    )
4913.2.19 by John Arbash Meinel
Compatibly rename ApportFeature to features.apport.
34
35
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
36
class Feature(object):
37
    """An operating system Feature."""
38
39
    def __init__(self):
40
        self._available = None
41
42
    def available(self):
43
        """Is the feature available?
44
45
        :return: True if the feature is available.
46
        """
47
        if self._available is None:
48
            self._available = self._probe()
49
        return self._available
50
51
    def _probe(self):
52
        """Implement this method in concrete features.
53
54
        :return: True if the feature is available.
55
        """
56
        raise NotImplementedError
57
58
    def __str__(self):
59
        if getattr(self, 'feature_name', None):
60
            return self.feature_name()
61
        return self.__class__.__name__
62
63
64
class _SymlinkFeature(Feature):
65
66
    def _probe(self):
67
        return osutils.has_symlinks()
68
69
    def feature_name(self):
70
        return 'symlinks'
71
7143.15.2 by Jelmer Vernooij
Run autopep8.
72
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
73
SymlinkFeature = _SymlinkFeature()
74
75
76
class _HardlinkFeature(Feature):
77
78
    def _probe(self):
79
        return osutils.has_hardlinks()
80
81
    def feature_name(self):
82
        return 'hardlinks'
83
7143.15.2 by Jelmer Vernooij
Run autopep8.
84
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
85
HardlinkFeature = _HardlinkFeature()
86
87
88
class _OsFifoFeature(Feature):
89
90
    def _probe(self):
91
        return getattr(os, 'mkfifo', None)
92
93
    def feature_name(self):
94
        return 'filesystem fifos'
95
7143.15.2 by Jelmer Vernooij
Run autopep8.
96
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
97
OsFifoFeature = _OsFifoFeature()
98
99
100
class _UnicodeFilenameFeature(Feature):
101
    """Does the filesystem support Unicode filenames?"""
102
103
    def _probe(self):
104
        try:
105
            # Check for character combinations unlikely to be covered by any
106
            # single non-unicode encoding. We use the characters
107
            # - greek small letter alpha (U+03B1) and
108
            # - braille pattern dots-123456 (U+283F).
109
            os.stat(u'\u03b1\u283f')
110
        except UnicodeEncodeError:
111
            return False
112
        except (IOError, OSError):
113
            # The filesystem allows the Unicode filename but the file doesn't
114
            # exist.
115
            return True
116
        else:
117
            # The filesystem allows the Unicode filename and the file exists,
118
            # for some reason.
119
            return True
120
7143.15.2 by Jelmer Vernooij
Run autopep8.
121
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
122
UnicodeFilenameFeature = _UnicodeFilenameFeature()
123
124
125
class _CompatabilityThunkFeature(Feature):
126
    """This feature is just a thunk to another feature.
127
128
    It issues a deprecation warning if it is accessed, to let you know that you
129
    should really use a different feature.
130
    """
131
132
    def __init__(self, dep_version, module, name,
133
                 replacement_name, replacement_module=None):
134
        super(_CompatabilityThunkFeature, self).__init__()
135
        self._module = module
136
        if replacement_module is None:
137
            replacement_module = module
138
        self._replacement_module = replacement_module
139
        self._name = name
140
        self._replacement_name = replacement_name
141
        self._dep_version = dep_version
142
        self._feature = None
143
144
    def _ensure(self):
145
        if self._feature is None:
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
146
            from breezy import pyutils
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
147
            depr_msg = self._dep_version % ('%s.%s'
148
                                            % (self._module, self._name))
149
            use_msg = ' Use %s.%s instead.' % (self._replacement_module,
150
                                               self._replacement_name)
6325.3.1 by Vincent Ladeuil
Give meaningful deprecation warnings for deprecated test features
151
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning,
152
                                   stacklevel=5)
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
153
            # Import the new feature and use it as a replacement for the
154
            # deprecated one.
155
            self._feature = pyutils.get_named_object(
156
                self._replacement_module, self._replacement_name)
157
158
    def _probe(self):
159
        self._ensure()
160
        return self._feature._probe()
161
162
163
class ModuleAvailableFeature(Feature):
164
    """This is a feature than describes a module we want to be available.
165
166
    Declare the name of the module in __init__(), and then after probing, the
167
    module will be available as 'self.module'.
168
169
    :ivar module: The module if it is available, else None.
170
    """
171
6760.1.1 by Jelmer Vernooij
Ignore DeprecationWarning/PendingDeprecationWarning during module probes. We can't do anything about these anyway.
172
    def __init__(self, module_name, ignore_warnings=None):
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
173
        super(ModuleAvailableFeature, self).__init__()
174
        self.module_name = module_name
6760.1.3 by Jelmer Vernooij
Martin's review comments.
175
        if ignore_warnings is None:
176
            ignore_warnings = ()
6760.1.1 by Jelmer Vernooij
Ignore DeprecationWarning/PendingDeprecationWarning during module probes. We can't do anything about these anyway.
177
        self.ignore_warnings = ignore_warnings
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
178
179
    def _probe(self):
5642.4.3 by Vincent Ladeuil
Rework the fix taking mgz remarks into account and rebasing against trunk.
180
        sentinel = object()
181
        module = sys.modules.get(self.module_name, sentinel)
182
        if module is sentinel:
6760.1.1 by Jelmer Vernooij
Ignore DeprecationWarning/PendingDeprecationWarning during module probes. We can't do anything about these anyway.
183
            with warnings.catch_warnings():
6760.1.3 by Jelmer Vernooij
Martin's review comments.
184
                for warning_category in self.ignore_warnings:
6760.1.1 by Jelmer Vernooij
Ignore DeprecationWarning/PendingDeprecationWarning during module probes. We can't do anything about these anyway.
185
                    warnings.simplefilter('ignore', warning_category)
186
                try:
6803.3.1 by Martin
Use importlib for ModuleAvailableFeature
187
                    self._module = importlib.import_module(self.module_name)
6760.1.1 by Jelmer Vernooij
Ignore DeprecationWarning/PendingDeprecationWarning during module probes. We can't do anything about these anyway.
188
                except ImportError:
189
                    return False
6760.1.3 by Jelmer Vernooij
Martin's review comments.
190
                return True
5642.4.3 by Vincent Ladeuil
Rework the fix taking mgz remarks into account and rebasing against trunk.
191
        else:
192
            self._module = module
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
193
            return True
194
195
    @property
196
    def module(self):
197
        if self.available():
198
            return self._module
199
        return None
200
201
    def feature_name(self):
202
        return self.module_name
203
204
6703.1.1 by Jelmer Vernooij
Add a ``PluginLoadedFeature``.
205
class PluginLoadedFeature(Feature):
206
    """Check whether a plugin with specific name is loaded.
207
208
    This is different from ModuleAvailableFeature, because
209
    plugins can be available but explicitly disabled
210
    (e.g. through BRZ_DISABLE_PLUGINS=blah).
211
212
    :ivar plugin_name: The name of the plugin
213
    """
214
215
    def __init__(self, plugin_name):
216
        super(PluginLoadedFeature, self).__init__()
217
        self.plugin_name = plugin_name
218
219
    def _probe(self):
6759.4.3 by Jelmer Vernooij
Avoid accessing global state.
220
        from breezy.plugin import get_loaded_plugin
221
        return (get_loaded_plugin(self.plugin_name) is not None)
6703.1.1 by Jelmer Vernooij
Add a ``PluginLoadedFeature``.
222
223
    @property
224
    def plugin(self):
6759.4.3 by Jelmer Vernooij
Avoid accessing global state.
225
        from breezy.plugin import get_loaded_plugin
226
        return get_loaded_plugin(self.plugin_name)
6703.1.1 by Jelmer Vernooij
Add a ``PluginLoadedFeature``.
227
228
    def feature_name(self):
6703.1.2 by Jelmer Vernooij
Change feature name to '... plugin'.
229
        return '%s plugin' % self.plugin_name
6703.1.1 by Jelmer Vernooij
Add a ``PluginLoadedFeature``.
230
231
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
232
class _HTTPSServerFeature(Feature):
233
    """Some tests want an https Server, check if one is available.
234
235
    Right now, the only way this is available is under python2.6 which provides
236
    an ssl module.
237
    """
238
239
    def _probe(self):
240
        try:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
241
            import ssl  # noqa: F401
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
242
            return True
243
        except ImportError:
244
            return False
245
246
    def feature_name(self):
247
        return 'HTTPSServer'
248
249
250
HTTPSServerFeature = _HTTPSServerFeature()
251
252
253
class _ByteStringNamedFilesystem(Feature):
254
    """Is the filesystem based on bytes?"""
255
256
    def _probe(self):
257
        if os.name == "posix":
258
            return True
259
        return False
260
7143.15.2 by Jelmer Vernooij
Run autopep8.
261
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
262
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
263
264
265
class _UTF8Filesystem(Feature):
266
    """Is the filesystem UTF-8?"""
267
268
    def _probe(self):
269
        if osutils._fs_enc.upper() in ('UTF-8', 'UTF8'):
270
            return True
271
        return False
272
7143.15.2 by Jelmer Vernooij
Run autopep8.
273
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
274
UTF8Filesystem = _UTF8Filesystem()
275
276
277
class _BreakinFeature(Feature):
278
    """Does this platform support the breakin feature?"""
279
280
    def _probe(self):
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
281
        from breezy import breakin
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
282
        if breakin.determine_signal() is None:
283
            return False
284
        if sys.platform == 'win32':
285
            # Windows doesn't have os.kill, and we catch the SIGBREAK signal.
286
            # We trigger SIGBREAK via a Console api so we need ctypes to
287
            # access the function
288
            try:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
289
                import ctypes  # noqa: F401
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
290
            except OSError:
291
                return False
292
        return True
293
294
    def feature_name(self):
295
        return "SIGQUIT or SIGBREAK w/ctypes on win32"
296
297
298
BreakinFeature = _BreakinFeature()
299
300
301
class _CaseInsCasePresFilenameFeature(Feature):
302
    """Is the file-system case insensitive, but case-preserving?"""
303
304
    def _probe(self):
305
        fileno, name = tempfile.mkstemp(prefix='MixedCase')
306
        try:
307
            # first check truly case-preserving for created files, then check
308
            # case insensitive when opening existing files.
309
            name = osutils.normpath(name)
310
            base, rel = osutils.split(name)
311
            found_rel = osutils.canonical_relpath(base, name)
7143.15.2 by Jelmer Vernooij
Run autopep8.
312
            return (found_rel == rel and
313
                    os.path.isfile(name.upper()) and
314
                    os.path.isfile(name.lower()))
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
315
        finally:
316
            os.close(fileno)
317
            os.remove(name)
318
319
    def feature_name(self):
320
        return "case-insensitive case-preserving filesystem"
321
7143.15.2 by Jelmer Vernooij
Run autopep8.
322
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
323
CaseInsCasePresFilenameFeature = _CaseInsCasePresFilenameFeature()
324
325
326
class _CaseInsensitiveFilesystemFeature(Feature):
327
    """Check if underlying filesystem is case-insensitive but *not* case
328
    preserving.
329
    """
330
    # Note that on Windows, Cygwin, MacOS etc, the file-systems are far
331
    # more likely to be case preserving, so this case is rare.
332
333
    def _probe(self):
334
        if CaseInsCasePresFilenameFeature.available():
335
            return False
336
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
337
        from breezy import tests
6280.1.1 by Martin Pool
Restore old name for bzrlib.tests.feature to unbreak bzr fastimport etc
338
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
339
        if tests.TestCaseWithMemoryTransport.TEST_ROOT is None:
340
            root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
341
            tests.TestCaseWithMemoryTransport.TEST_ROOT = root
342
        else:
343
            root = tests.TestCaseWithMemoryTransport.TEST_ROOT
344
        tdir = osutils.mkdtemp(prefix='case-sensitive-probe-', suffix='',
7143.15.2 by Jelmer Vernooij
Run autopep8.
345
                               dir=root)
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
346
        name_a = osutils.pathjoin(tdir, 'a')
347
        name_A = osutils.pathjoin(tdir, 'A')
348
        os.mkdir(name_a)
349
        result = osutils.isdir(name_A)
6280.1.2 by Martin Pool
Fix NameError
350
        tests._rmtree_temp_dir(tdir)
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
351
        return result
352
353
    def feature_name(self):
354
        return 'case-insensitive filesystem'
355
7143.15.2 by Jelmer Vernooij
Run autopep8.
356
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
357
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
358
359
360
class _CaseSensitiveFilesystemFeature(Feature):
361
362
    def _probe(self):
363
        if CaseInsCasePresFilenameFeature.available():
364
            return False
365
        elif CaseInsensitiveFilesystemFeature.available():
366
            return False
367
        else:
368
            return True
369
370
    def feature_name(self):
371
        return 'case-sensitive filesystem'
372
7143.15.2 by Jelmer Vernooij
Run autopep8.
373
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
374
# new coding style is for feature instances to be lowercase
375
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
376
377
378
class _NotRunningAsRoot(Feature):
4797.70.1 by Vincent Ladeuil
Skip chmodbits dependent tests when running as root
379
380
    def _probe(self):
381
        try:
382
            uid = os.getuid()
383
        except AttributeError:
384
            # If there is no uid, chances are there is no root either
385
            return True
386
        return uid != 0
387
388
    def feature_name(self):
389
        return 'Not running as root'
390
391
392
not_running_as_root = _NotRunningAsRoot()
5448.5.9 by Vincent Ladeuil
Make the test depends on a feature so it's skipped if meliae is not installed
393
6760.1.2 by Jelmer Vernooij
Add note.
394
# Apport uses deprecated imp module on python3.
6760.1.1 by Jelmer Vernooij
Ignore DeprecationWarning/PendingDeprecationWarning during module probes. We can't do anything about these anyway.
395
apport = ModuleAvailableFeature(
396
    'apport.report',
397
    ignore_warnings=[DeprecationWarning, PendingDeprecationWarning])
6728.1.1 by Jelmer Vernooij
Use python-gpg rather than python-gpgme.
398
gpg = ModuleAvailableFeature('gpg')
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
399
lzma = ModuleAvailableFeature('lzma')
6091.2.2 by Max Bowsher
Per jam's review comments, get rid of features.meliae_feature, which is new in
400
meliae = ModuleAvailableFeature('meliae.scanner')
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
401
paramiko = ModuleAvailableFeature('paramiko')
402
pywintypes = ModuleAvailableFeature('pywintypes')
403
subunit = ModuleAvailableFeature('subunit')
5967.12.3 by Martin Pool
Unify duplicated UnicodeFilename and _PosixPermissionsFeature
404
testtools = ModuleAvailableFeature('testtools')
7167.1.4 by Jelmer Vernooij
Test for flake8.api.legacy.
405
flake8 = ModuleAvailableFeature('flake8.api.legacy')
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
406
407
compiled_patiencediff_feature = ModuleAvailableFeature(
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
408
    'breezy._patiencediff_c')
409
lsprof_feature = ModuleAvailableFeature('breezy.lsprof')
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
410
411
412
class _BackslashDirSeparatorFeature(Feature):
5241.2.1 by Robert Collins
Merge up from 2.0/2.1:
413
414
    def _probe(self):
415
        try:
416
            os.lstat(os.getcwd() + '\\')
417
        except OSError:
418
            return False
419
        else:
420
            return True
421
422
    def feature_name(self):
423
        return "Filesystem treats '\\' as a directory separator."
424
7143.15.2 by Jelmer Vernooij
Run autopep8.
425
5241.2.1 by Robert Collins
Merge up from 2.0/2.1:
426
backslashdir_feature = _BackslashDirSeparatorFeature()
427
428
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
429
class _ChownFeature(Feature):
5051.4.10 by Parth Malwankar
moved ChownFeature to tests/features.py
430
    """os.chown is supported"""
431
432
    def _probe(self):
433
        return os.name == 'posix' and hasattr(os, 'chown')
434
7143.15.2 by Jelmer Vernooij
Run autopep8.
435
5051.4.11 by Parth Malwankar
closed Martins review comments.
436
chown_feature = _ChownFeature()
5051.4.10 by Parth Malwankar
moved ChownFeature to tests/features.py
437
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
438
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
439
class ExecutableFeature(Feature):
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
440
    """Feature testing whether an executable of a given name is on the PATH."""
441
442
    def __init__(self, name):
443
        super(ExecutableFeature, self).__init__()
444
        self.name = name
5147.5.23 by Martin von Gagern
Have ExecutableFeature implement and use _probe.
445
        self._path = None
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
446
447
    @property
448
    def path(self):
5147.5.23 by Martin von Gagern
Have ExecutableFeature implement and use _probe.
449
        # This is a property, so accessing path ensures _probe was called
450
        self.available()
451
        return self._path
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
452
5147.5.23 by Martin von Gagern
Have ExecutableFeature implement and use _probe.
453
    def _probe(self):
5321.1.82 by Gordon Tyler
Changed ExecutableFeature to use osutils.find_executable_on_path.
454
        self._path = osutils.find_executable_on_path(self.name)
455
        return self._path is not None
5147.5.20 by Martin von Gagern
Move ExecutableFeature class from bash_completion plugin to bzrlib tests.
456
457
    def feature_name(self):
458
        return '%s executable' % self.name
5147.5.24 by Martin von Gagern
Move ExecutableFeature instances to tests.features module.
459
460
461
bash_feature = ExecutableFeature('bash')
6282.3.1 by Vincent Ladeuil
First cut at a working plugin to avoid conflicts in .po files by shelling out to msgmerge.
462
diff_feature = ExecutableFeature('diff')
5147.5.24 by Martin von Gagern
Move ExecutableFeature instances to tests.features module.
463
sed_feature = ExecutableFeature('sed')
6282.3.1 by Vincent Ladeuil
First cut at a working plugin to avoid conflicts in .po files by shelling out to msgmerge.
464
msgmerge_feature = ExecutableFeature('msgmerge')
5609.47.1 by Alexander Belchenko
Win32Feature
465
466
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
467
class _PosixPermissionsFeature(Feature):
468
469
    def _probe(self):
470
        def has_perms():
471
            # Create temporary file and check if specified perms are
472
            # maintained.
473
            write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
474
            f = tempfile.mkstemp(prefix='bzr_perms_chk_')
475
            fd, name = f
476
            os.close(fd)
6344.1.1 by Martin Packman
Merge 2.4 into bzr.dev
477
            osutils.chmod_if_possible(name, write_perms)
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
478
6619.3.14 by Jelmer Vernooij
Convert some octal numbers to new notations.
479
            read_perms = os.stat(name).st_mode & 0o777
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
480
            os.unlink(name)
481
            return (write_perms == read_perms)
482
483
        return (os.name == 'posix') and has_perms()
484
485
    def feature_name(self):
486
        return 'POSIX permissions support'
487
488
489
posix_permissions_feature = _PosixPermissionsFeature()
490
491
492
class _StraceFeature(Feature):
493
494
    def _probe(self):
495
        try:
496
            proc = subprocess.Popen(['strace'],
7143.15.2 by Jelmer Vernooij
Run autopep8.
497
                                    stderr=subprocess.PIPE,
498
                                    stdout=subprocess.PIPE)
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
499
            proc.communicate()
500
            return True
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
501
        except OSError as e:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
502
            import errno
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
503
            if e.errno == errno.ENOENT:
504
                # strace is not installed
505
                return False
506
            else:
507
                raise
508
509
    def feature_name(self):
510
        return 'strace'
511
512
513
strace_feature = _StraceFeature()
514
515
516
class _AttribFeature(Feature):
517
518
    def _probe(self):
519
        if (sys.platform not in ('cygwin', 'win32')):
520
            return False
521
        try:
522
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
523
        except OSError:
5967.12.1 by Martin Pool
Move all test features into bzrlib.tests.features
524
            return False
525
        return (0 == proc.wait())
526
527
    def feature_name(self):
528
        return 'attrib Windows command-line tool'
529
530
531
AttribFeature = _AttribFeature()
5967.12.2 by Martin Pool
Move all features to bzrlib.tests.features in 2.5
532
533
5967.12.3 by Martin Pool
Unify duplicated UnicodeFilename and _PosixPermissionsFeature
534
class Win32Feature(Feature):
5609.47.1 by Alexander Belchenko
Win32Feature
535
    """Feature testing whether we're running selftest on Windows
5609.47.4 by Alexander Belchenko
fixed typo
536
    or Windows-like platform.
5609.47.1 by Alexander Belchenko
Win32Feature
537
    """
538
539
    def _probe(self):
540
        return sys.platform == 'win32'
541
542
    def feature_name(self):
543
        return "win32 platform"
544
5967.12.4 by Martin Pool
Support (but deprecated) old feature names
545
5609.47.1 by Alexander Belchenko
Win32Feature
546
win32_feature = Win32Feature()
6478.3.1 by Jelmer Vernooij
Add backslashfilenamefeature.
547
548
549
class _BackslashFilenameFeature(Feature):
550
    """Does the filesystem support backslashes in filenames?"""
551
552
    def _probe(self):
6478.3.4 by Jelmer Vernooij
Merge trunk.
553
6478.3.1 by Jelmer Vernooij
Add backslashfilenamefeature.
554
        try:
555
            fileno, name = tempfile.mkstemp(prefix='bzr\\prefix')
556
        except (IOError, OSError):
557
            return False
558
        else:
559
            try:
560
                os.stat(name)
561
            except (IOError, OSError):
562
                # mkstemp succeeded but the file wasn't actually created
563
                return False
564
            os.close(fileno)
565
            os.remove(name)
566
            return True
567
6478.3.4 by Jelmer Vernooij
Merge trunk.
568
6478.3.1 by Jelmer Vernooij
Add backslashfilenamefeature.
569
BackslashFilenameFeature = _BackslashFilenameFeature()