16
16
# along with this program; if not, write to the Free Software
17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
from shutil import copyfile
20
19
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
21
20
S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
22
from cStringIO import StringIO
33
from bzrlib.errors import BzrError, NotBranchError
30
from bzrlib.errors import BzrError
34
31
from bzrlib.trace import mutter
97
94
raise BzrError('invalid file kind %r' % kind)
101
if hasattr(os, 'lstat'):
107
if e.errno == errno.ENOENT:
110
raise BzrError("lstat/stat of (%r): %r" % (f, e))
112
def normalizepath(f):
113
if hasattr(os.path, 'realpath'):
117
[p,e] = os.path.split(f)
118
if e == "" or e == "." or e == "..":
121
return os.path.join(F(p), e)
123
if os.name == "posix":
124
# In Python 2.4.2 and older, os.path.abspath and os.path.realpath
125
# choke on a Unicode string containing a relative path if
126
# os.getcwd() returns a non-sys.getdefaultencoding()-encoded
128
_fs_enc = sys.getfilesystemencoding()
130
return os.path.abspath(path.encode(_fs_enc)).decode(_fs_enc)
132
return os.path.realpath(path.encode(_fs_enc)).decode(_fs_enc)
134
# We need to use the Unicode-aware os.path.abspath and
135
# os.path.realpath on Windows systems.
136
abspath = os.path.abspath
137
realpath = os.path.realpath
139
97
def backup_file(fn):
140
98
"""Copy a file to a backup.
279
219
'sha1': s.hexdigest()}
223
"""Return per-user configuration directory.
225
By default this is ~/.bzr.conf/
227
TODO: Global option --config-dir to override this.
229
return os.path.join(os.path.expanduser("~"), ".bzr.conf")
233
"""Calculate automatic user identification.
235
Returns (realname, email).
237
Only used when none is set in the environment or the id file.
239
This previously used the FQDN as the default domain, but that can
240
be very slow on machines where DNS is broken. So now we simply
245
# XXX: Any good way to get real user name on win32?
250
w = pwd.getpwuid(uid)
251
gecos = w.pw_gecos.decode(bzrlib.user_encoding)
252
username = w.pw_name.decode(bzrlib.user_encoding)
253
comma = gecos.find(',')
257
realname = gecos[:comma]
263
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
265
return realname, (username + '@' + socket.gethostname())
268
def _get_user_id(branch):
269
"""Return the full user id from a file or environment variable.
271
e.g. "John Hacker <jhacker@foo.org>"
274
A branch to use for a per-branch configuration, or None.
276
The following are searched in order:
279
2. .bzr/email for this branch.
283
v = os.environ.get('BZREMAIL')
285
return v.decode(bzrlib.user_encoding)
289
return (branch.controlfile("email", "r")
291
.decode(bzrlib.user_encoding)
294
if e.errno != errno.ENOENT:
300
return (open(os.path.join(config_dir(), "email"))
302
.decode(bzrlib.user_encoding)
305
if e.errno != errno.ENOENT:
308
v = os.environ.get('EMAIL')
310
return v.decode(bzrlib.user_encoding)
315
def username(branch):
316
"""Return email-style username.
318
Something similar to 'Martin Pool <mbp@sourcefrog.net>'
320
TODO: Check it's reasonably well-formed.
322
v = _get_user_id(branch)
326
name, email = _auto_user_id()
328
return '%s <%s>' % (name, email)
333
def user_email(branch):
334
"""Return just the email component of a username."""
335
e = _get_user_id(branch)
337
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
339
raise BzrError("%r doesn't seem to contain "
340
"a reasonable email address" % e)
343
return _auto_user_id()[1]
282
346
def compare_files(a, b):
283
347
"""Returns true if equal in contents"""
303
367
return -time.timezone
306
def format_date(t, offset=0, timezone='original', date_fmt=None,
370
def format_date(t, offset=0, timezone='original'):
308
371
## TODO: Perhaps a global option to use either universal or local time?
309
372
## Or perhaps just let people set $TZ?
310
373
assert isinstance(t, float)
323
386
raise BzrError("unsupported timezone format %r" % timezone,
324
387
['options are "utc", "original", "local"'])
326
date_fmt = "%a %Y-%m-%d %H:%M:%S"
328
offset_str = ' %+03d%02d' % (offset / 3600, (offset / 60) % 60)
331
return (time.strftime(date_fmt, tt) + offset_str)
389
return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
390
+ ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
334
393
def compact_date(when):
412
471
return os.path.join(p1, p2)
416
"""Split s into lines, but without removing the newline characters."""
417
return StringIO(s).readlines()
420
def hardlinks_good():
421
return sys.platform not in ('win32', 'cygwin', 'darwin')
424
def link_or_copy(src, dest):
425
"""Hardlink a file, or copy it if it can't be hardlinked."""
426
if not hardlinks_good():
474
def extern_command(cmd, ignore_errors = False):
475
mutter('external command: %s' % `cmd`)
477
if not ignore_errors:
478
raise BzrError('command failed')
481
def _read_config_value(name):
482
"""Read a config value from the file ~/.bzr.conf/<name>
483
Return None if the file does not exist"""
431
except (OSError, IOError), e:
432
if e.errno != errno.EXDEV:
438
if hasattr(os, 'symlink'):
444
def contains_whitespace(s):
445
"""True if there are any whitespace characters in s."""
446
for ch in string.whitespace:
453
def contains_linebreaks(s):
454
"""True if there is any vertical whitespace in s."""
462
def relpath(base, path):
463
"""Return path relative to base, or raise exception.
465
The path may be either an absolute path or a path relative to the
466
current working directory.
468
os.path.commonprefix (python2.4) has a bad bug that it works just
469
on string prefixes, assuming that '/u' is a prefix of '/u2'. This
470
avoids that problem."""
475
while len(head) >= len(base):
478
head, tail = os.path.split(head)
482
# XXX This should raise a NotChildPath exception, as its not tied
484
raise NotBranchError("path %r is not within branch %r" % (rp, base))
486
return os.sep.join(s)
485
f = file(os.path.join(config_dir(), name), "r")
486
return f.read().decode(bzrlib.user_encoding).rstrip("\r\n")
488
if e.errno == errno.ENOENT: