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