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
import os, types, re, time, errno, sys
19
import os, types, re, time, errno
20
20
from stat import S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE
22
from bzrlib.errors import BzrError
23
from bzrlib.trace import mutter
22
from errors import bailout, BzrError
23
from trace import mutter
26
26
def make_readonly(filename):
121
def is_inside(dir, fname):
122
"""True if fname is inside dir.
124
return os.path.commonprefix([dir, fname]) == dir
127
def is_inside_any(dir_list, fname):
128
"""True if fname is inside any of given dirs."""
129
# quick scan for perfect match
130
if fname in dir_list:
133
for dirname in dir_list:
134
if is_inside(dirname, fname):
140
80
def pumpfile(fromfile, tofile):
141
81
"""Copy contents of one file to another."""
142
82
tofile.write(fromfile.read())
220
157
realname = gecos[:comma]
224
159
except ImportError:
226
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
162
username = getpass.getuser().decode(bzrlib.user_encoding)
228
return realname, (username + '@' + socket.gethostname())
164
return realname, (username + '@' + os.gethostname())
231
167
def _get_user_id():
232
"""Return the full user id from a file or environment variable.
234
TODO: Allow taking this from a file in the branch directory too
235
for per-branch ids."""
236
168
v = os.environ.get('BZREMAIL')
238
170
return v.decode(bzrlib.user_encoding)
241
return (open(os.path.join(config_dir(), "email"))
173
return (open(os.path.expanduser("~/.bzr.email"))
243
175
.decode(bzrlib.user_encoding)
246
if e.errno != errno.ENOENT:
178
if e.errno != ENOENT:
249
181
v = os.environ.get('EMAIL')
346
282
if hasattr(os, 'urandom'): # python 2.4 and later
347
283
rand_bytes = os.urandom
348
elif sys.platform == 'linux2':
349
rand_bytes = file('/dev/urandom', 'rb').read
351
# not well seeded, but better than nothing
356
s += chr(random.randint(0, 255))
285
# FIXME: No good on non-Linux
286
_rand_file = file('/dev/urandom', 'rb')
287
rand_bytes = _rand_file.read
361
290
## TODO: We could later have path objects that remember their list
375
304
>>> splitpath('a/../b')
376
305
Traceback (most recent call last):
378
BzrError: sorry, '..' not allowed in path
307
BzrError: ("sorry, '..' not allowed in path", [])
380
309
assert isinstance(p, types.StringTypes)
382
# split on either delimiter because people might use either on
384
ps = re.split(r'[\\/]', p)
310
ps = [f for f in p.split('/') if (f != '.' and f != '')]
389
raise BzrError("sorry, %r not allowed in path" % f)
390
elif (f == '.') or (f == ''):
313
bailout("sorry, %r not allowed in path" % f)
397
317
assert isinstance(p, list)
399
319
if (f == '..') or (f == None) or (f == ''):
400
raise BzrError("sorry, %r not allowed in path" % f)
401
return os.path.join(*p)
320
bailout("sorry, %r not allowed in path" % f)
404
324
def appendpath(p1, p2):
408
return os.path.join(p1, p2)
411
331
def extern_command(cmd, ignore_errors = False):
412
332
mutter('external command: %s' % `cmd`)
413
333
if os.system(cmd):
414
334
if not ignore_errors:
415
raise BzrError('command failed')
418
def _read_config_value(name):
419
"""Read a config value from the file ~/.bzr.conf/<name>
420
Return None if the file does not exist"""
422
f = file(os.path.join(config_dir(), name), "r")
423
return f.read().decode(bzrlib.user_encoding).rstrip("\r\n")
425
if e.errno == errno.ENOENT:
431
"""Return a sequence of possible editor binaries for the current platform"""
432
e = _read_config_value("editor")
436
if os.name == "windows":
438
elif os.name == "posix":
440
yield os.environ["EDITOR"]
445
def _run_editor(filename):
446
"""Try to execute an editor to edit the commit message. Returns True on success,
448
for e in _get_editor():
449
x = os.spawnvp(os.P_WAIT, e, (e, filename))
456
raise BzrError("Could not start any editor. Please specify $EDITOR or use ~/.bzr.conf/editor")
460
def get_text_message(infotext, ignoreline = "default"):
463
if ignoreline == "default":
464
ignoreline = "-- This line and the following will be ignored --"
467
tmp_fileno, msgfilename = tempfile.mkstemp()
468
msgfile = os.close(tmp_fileno)
469
if infotext is not None and infotext != "":
471
msgfile = file(msgfilename, "w")
472
msgfile.write("\n\n%s\n\n%s" % (ignoreline, infotext))
477
if not _run_editor(msgfilename):
482
lastline, nlines = 0, 0
483
for line in file(msgfilename, "r"):
484
stripped_line = line.strip()
485
# strip empty line before the log message starts
487
if stripped_line != "":
491
# check for the ignore line only if there
492
# is additional information at the end
493
if hasinfo and stripped_line == ignoreline:
496
# keep track of the last line that had some content
497
if stripped_line != "":
503
# delete empty lines at the end
505
# add a newline at the end, if needed
506
if not msg[-1].endswith("\n"):
507
return "%s%s" % ("".join(msg), "\n")
511
# delete the msg file in any case
512
try: os.unlink(msgfilename)
335
bailout('command failed')