102
105
mod = os.lstat(filename).st_mode
103
106
if not stat.S_ISLNK(mod):
104
107
mod = mod & 0777555
105
chmod_if_possible(filename, mod)
108
os.chmod(filename, mod)
108
111
def make_writable(filename):
109
112
mod = os.lstat(filename).st_mode
110
113
if not stat.S_ISLNK(mod):
112
chmod_if_possible(filename, mod)
115
def chmod_if_possible(filename, mode):
116
# Set file mode if that can be safely done.
117
# Sometimes even on unix the filesystem won't allow it - see
118
# https://bugs.launchpad.net/bzr/+bug/606537
120
# It is probably faster to just do the chmod, rather than
121
# doing a stat, and then trying to compare
122
os.chmod(filename, mode)
123
except (IOError, OSError),e:
124
# Permission/access denied seems to commonly happen on smbfs; there's
125
# probably no point warning about it.
126
# <https://bugs.launchpad.net/bzr/+bug/606537>
127
if getattr(e, 'errno') in (errno.EPERM, errno.EACCES):
128
trace.mutter("ignore error on chmod of %r: %r" % (
115
os.chmod(filename, mod)
134
118
def minimum_path_selection(paths):
286
270
rename_func(tmp_name, new)
287
271
if failure_exc is not None:
289
raise failure_exc[0], failure_exc[1], failure_exc[2]
272
raise failure_exc[0], failure_exc[1], failure_exc[2]
294
275
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
295
276
# choke on a Unicode string containing a relative path if
296
277
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
279
_fs_enc = sys.getfilesystemencoding() or 'utf-8'
298
280
def _posix_abspath(path):
299
281
# jam 20060426 rather than encoding to fsencoding
300
282
# copy posixpath.abspath, but use os.getcwdu instead
301
283
if not posixpath.isabs(path):
302
284
path = posixpath.join(getcwd(), path)
303
return _posix_normpath(path)
285
return posixpath.normpath(path)
306
288
def _posix_realpath(path):
307
289
return posixpath.realpath(path.encode(_fs_enc)).decode(_fs_enc)
310
def _posix_normpath(path):
311
path = posixpath.normpath(path)
312
# Bug 861008: posixpath.normpath() returns a path normalized according to
313
# the POSIX standard, which stipulates (for compatibility reasons) that two
314
# leading slashes must not be simplified to one, and only if there are 3 or
315
# more should they be simplified as one. So we treat the leading 2 slashes
316
# as a special case here by simply removing the first slash, as we consider
317
# that breaking POSIX compatibility for this obscure feature is acceptable.
318
# This is not a paranoid precaution, as we notably get paths like this when
319
# the repo is hosted at the root of the filesystem, i.e. in "/".
320
if path.startswith('//'):
325
def _posix_path_from_environ(key):
326
"""Get unicode path from `key` in environment or None if not present
328
Note that posix systems use arbitrary byte strings for filesystem objects,
329
so a path that raises BadFilenameEncoding here may still be accessible.
331
val = os.environ.get(key, None)
335
return val.decode(_fs_enc)
336
except UnicodeDecodeError:
337
# GZ 2011-12-12:Ideally want to include `key` in the exception message
338
raise errors.BadFilenameEncoding(val, _fs_enc)
341
def _posix_getuser_unicode():
342
"""Get username from environment or password database as unicode"""
343
name = getpass.getuser()
344
user_encoding = get_user_encoding()
346
return name.decode(user_encoding)
347
except UnicodeDecodeError:
348
raise errors.BzrError("Encoding of username %r is unsupported by %s "
349
"application locale." % (name, user_encoding))
352
292
def _win32_fixdrive(path):
353
293
"""Force drive letters to be consistent.
2056
1973
return get_terminal_encoding()
2059
_message_encoding = None
2062
def get_message_encoding():
2063
"""Return the encoding used for messages
2065
While the message encoding is a general setting it should usually only be
2066
needed for decoding system error strings such as from OSError instances.
2068
global _message_encoding
2069
if _message_encoding is None:
2070
if os.name == "posix":
2072
# This is a process-global setting that can change, but should in
2073
# general just get set once at process startup then be constant.
2074
_message_encoding = locale.getlocale(locale.LC_MESSAGES)[1]
2076
# On windows want the result of GetACP() which this boils down to.
2077
_message_encoding = get_user_encoding()
2078
return _message_encoding or "ascii"
2081
1976
def get_host_name():
2082
1977
"""Return the current unicode host name.
2266
2153
return file_kind_from_stat_mode(mode)
2267
2154
file_kind_from_stat_mode = file_kind_from_stat_mode_thunk
2269
def file_stat(f, _lstat=os.lstat):
2157
def file_kind(f, _lstat=os.lstat):
2159
return file_kind_from_stat_mode(_lstat(f).st_mode)
2273
2160
except OSError, e:
2274
2161
if getattr(e, 'errno', None) in (errno.ENOENT, errno.ENOTDIR):
2275
2162
raise errors.NoSuchFile(f)
2278
def file_kind(f, _lstat=os.lstat):
2279
stat_value = file_stat(f, _lstat)
2280
return file_kind_from_stat_mode(stat_value.st_mode)
2282
2166
def until_no_eintr(f, *a, **kw):
2283
2167
"""Run f(*a, **kw), retrying if an EINTR error occurs.
2343
2227
termios.tcsetattr(fd, termios.TCSADRAIN, settings)
2346
if sys.platform.startswith('linux'):
2231
if sys.platform == 'linux2':
2347
2232
def _local_concurrency():
2349
return os.sysconf('SC_NPROCESSORS_ONLN')
2350
except (ValueError, OSError, AttributeError):
2234
prefix = 'processor'
2235
for line in file('/proc/cpuinfo', 'rb'):
2236
if line.startswith(prefix):
2237
concurrency = int(line[line.find(':')+1:]) + 1
2352
2239
elif sys.platform == 'darwin':
2353
2240
def _local_concurrency():
2354
2241
return subprocess.Popen(['sysctl', '-n', 'hw.availcpu'],
2355
2242
stdout=subprocess.PIPE).communicate()[0]
2356
elif "bsd" in sys.platform:
2243
elif sys.platform[0:7] == 'freebsd':
2357
2244
def _local_concurrency():
2358
2245
return subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
2359
2246
stdout=subprocess.PIPE).communicate()[0]
2387
2274
concurrency = os.environ.get('BZR_CONCURRENCY', None)
2388
2275
if concurrency is None:
2390
import multiprocessing
2391
concurrency = multiprocessing.cpu_count()
2392
except (ImportError, NotImplementedError):
2393
# multiprocessing is only available on Python >= 2.6
2394
# and multiprocessing.cpu_count() isn't implemented on all
2397
concurrency = _local_concurrency()
2398
except (OSError, IOError):
2277
concurrency = _local_concurrency()
2278
except (OSError, IOError):
2401
2281
concurrency = int(concurrency)
2402
2282
except (TypeError, ValueError):
2464
2344
open_file = open
2467
def available_backup_name(base, exists):
2468
"""Find a non-existing backup file name.
2470
This will *not* create anything, this only return a 'free' entry. This
2471
should be used for checking names in a directory below a locked
2472
tree/branch/repo to avoid race conditions. This is LBYL (Look Before You
2473
Leap) and generally discouraged.
2475
:param base: The base name.
2477
:param exists: A callable returning True if the path parameter exists.
2480
name = "%s.~%d~" % (base, counter)
2483
name = "%s.~%d~" % (base, counter)
2487
def set_fd_cloexec(fd):
2488
"""Set a Unix file descriptor's FD_CLOEXEC flag. Do nothing if platform
2489
support for this is not available.
2493
old = fcntl.fcntl(fd, fcntl.F_GETFD)
2494
fcntl.fcntl(fd, fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
2495
except (ImportError, AttributeError):
2496
# Either the fcntl module or specific constants are not present
2500
def find_executable_on_path(name):
2501
"""Finds an executable on the PATH.
2503
On Windows, this will try to append each extension in the PATHEXT
2504
environment variable to the name, if it cannot be found with the name
2507
:param name: The base name of the executable.
2508
:return: The path to the executable found or None.
2510
path = os.environ.get('PATH')
2513
path = path.split(os.pathsep)
2514
if sys.platform == 'win32':
2515
exts = os.environ.get('PATHEXT', '').split(os.pathsep)
2516
exts = [ext.lower() for ext in exts]
2517
base, ext = os.path.splitext(name)
2519
if ext.lower() not in exts:
2527
f = os.path.join(d, name) + ext
2528
if os.access(f, os.X_OK):
2533
def _posix_is_local_pid_dead(pid):
2534
"""True if pid doesn't correspond to live process on this machine"""
2536
# Special meaning of unix kill: just check if it's there.
2539
if e.errno == errno.ESRCH:
2540
# On this machine, and really not found: as sure as we can be
2543
elif e.errno == errno.EPERM:
2544
# exists, though not ours
2547
mutter("os.kill(%d, 0) failed: %s" % (pid, e))
2548
# Don't really know.
2551
# Exists and our process: not dead.
2554
if sys.platform == "win32":
2555
is_local_pid_dead = win32utils.is_local_pid_dead
2557
is_local_pid_dead = _posix_is_local_pid_dead
2560
def fdatasync(fileno):
2561
"""Flush file contents to disk if possible.
2563
:param fileno: Integer OS file handle.
2564
:raises TransportNotPossible: If flushing to disk is not possible.
2566
fn = getattr(os, 'fdatasync', getattr(os, 'fsync', None))
2571
def ensure_empty_directory_exists(path, exception_class):
2572
"""Make sure a local directory exists and is empty.
2574
If it does not exist, it is created. If it exists and is not empty, an
2575
instance of exception_class is raised.
2580
if e.errno != errno.EEXIST:
2582
if os.listdir(path) != []:
2583
raise exception_class(path)
2586
def is_environment_error(evalue):
2587
"""True if exception instance is due to a process environment issue
2589
This includes OSError and IOError, but also other errors that come from
2590
the operating system or core libraries but are not subclasses of those.
2592
if isinstance(evalue, (EnvironmentError, select.error)):
2594
if sys.platform == "win32" and win32utils._is_pywintypes_error(evalue):
2347
def getuser_unicode():
2348
"""Return the username as unicode.
2351
user_encoding = get_user_encoding()
2352
username = getpass.getuser().decode(user_encoding)
2353
except UnicodeDecodeError:
2354
raise errors.BzrError("Can't decode username as %s." % \