~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Martin Pool
  • Date: 2005-05-11 06:20:05 UTC
  • Revision ID: mbp@sourcefrog.net-20050511062005-297af3451635dae0
- Don't lose first line of command help!

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
import os, types, re, time, errno, sys
20
20
from stat import S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE
21
21
 
22
 
from bzrlib.errors import BzrError
23
 
from bzrlib.trace import mutter
 
22
from errors import bailout, BzrError
 
23
from trace import mutter
24
24
import bzrlib
25
25
 
26
26
def make_readonly(filename):
56
56
    elif S_ISLNK(mode):
57
57
        return 'symlink'
58
58
    else:
59
 
        raise BzrError("can't handle file kind with mode %o of %r" % (mode, f))
60
 
 
61
 
 
62
 
def kind_marker(kind):
63
 
    if kind == 'file':
64
 
        return ''
65
 
    elif kind == 'directory':
66
 
        return '/'
67
 
    elif kind == 'symlink':
68
 
        return '@'
69
 
    else:
70
 
        raise BzrError('invalid file kind %r' % kind)
 
59
        raise BzrError("can't handle file kind with mode %o of %r" % (mode, f)) 
71
60
 
72
61
 
73
62
 
88
77
        return False
89
78
 
90
79
 
91
 
def is_inside(dir, fname):
92
 
    """True if fname is inside dir.
93
 
    """
94
 
    return os.path.commonprefix([dir, fname]) == dir
95
 
 
96
 
 
97
 
def is_inside_any(dir_list, fname):
98
 
    """True if fname is inside any of given dirs."""
99
 
    # quick scan for perfect match
100
 
    if fname in dir_list:
101
 
        return True
102
 
    
103
 
    for dirname in dir_list:
104
 
        if is_inside(dirname, fname):
105
 
            return True
106
 
    else:
107
 
        return False
108
 
 
109
 
 
110
80
def pumpfile(fromfile, tofile):
111
81
    """Copy contents of one file to another."""
112
82
    tofile.write(fromfile.read())
248
218
    if e:
249
219
        m = _EMAIL_RE.search(e)
250
220
        if not m:
251
 
            raise BzrError("%r doesn't seem to contain a reasonable email address" % e)
 
221
            bailout("%r doesn't seem to contain a reasonable email address" % e)
252
222
        return m.group(0)
253
223
 
254
224
    return _auto_user_id()[1]
296
266
        tt = time.localtime(t)
297
267
        offset = local_time_offset(t)
298
268
    else:
299
 
        raise BzrError("unsupported timezone format %r",
 
269
        bailout("unsupported timezone format %r",
300
270
                ['options are "utc", "original", "local"'])
301
271
 
302
272
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
345
315
    >>> splitpath('a/../b')
346
316
    Traceback (most recent call last):
347
317
    ...
348
 
    BzrError: sorry, '..' not allowed in path
 
318
    BzrError: ("sorry, '..' not allowed in path", [])
349
319
    """
350
320
    assert isinstance(p, types.StringTypes)
351
321
 
356
326
    rps = []
357
327
    for f in ps:
358
328
        if f == '..':
359
 
            raise BzrError("sorry, %r not allowed in path" % f)
 
329
            bailout("sorry, %r not allowed in path" % f)
360
330
        elif (f == '.') or (f == ''):
361
331
            pass
362
332
        else:
367
337
    assert isinstance(p, list)
368
338
    for f in p:
369
339
        if (f == '..') or (f == None) or (f == ''):
370
 
            raise BzrError("sorry, %r not allowed in path" % f)
 
340
            bailout("sorry, %r not allowed in path" % f)
371
341
    return os.path.join(*p)
372
342
 
373
343
 
382
352
    mutter('external command: %s' % `cmd`)
383
353
    if os.system(cmd):
384
354
        if not ignore_errors:
385
 
            raise BzrError('command failed')
386
 
 
387
 
 
388
 
def _read_config_value(name):
389
 
    """Read a config value from the file ~/.bzr.conf/<name>
390
 
    Return None if the file does not exist"""
391
 
    try:
392
 
        f = file(os.path.join(config_dir(), name), "r")
393
 
        return f.read().decode(bzrlib.user_encoding).rstrip("\r\n")
394
 
    except IOError, e:
395
 
        if e.errno == errno.ENOENT:
396
 
            return None
397
 
        raise
398
 
 
399
 
 
400
 
def _get_editor():
401
 
    """Return a sequence of possible editor binaries for the current platform"""
402
 
    e = _read_config_value("editor")
403
 
    if e is not None:
404
 
        yield e
405
 
        
406
 
    if os.name == "windows":
407
 
        yield "notepad.exe"
408
 
    elif os.name == "posix":
409
 
        try:
410
 
            yield os.environ["EDITOR"]
411
 
        except KeyError:
412
 
            yield "/usr/bin/vi"
413
 
 
414
 
 
415
 
def _run_editor(filename):
416
 
    """Try to execute an editor to edit the commit message. Returns True on success,
417
 
    False on failure"""
418
 
    for e in _get_editor():
419
 
        x = os.spawnvp(os.P_WAIT, e, (e, filename))
420
 
        if x == 0:
421
 
            return True
422
 
        elif x == 127:
423
 
            continue
424
 
        else:
425
 
            break
426
 
    raise BzrError("Could not start any editor. Please specify $EDITOR or use ~/.bzr.conf/editor")
427
 
    return False
428
 
                          
429
 
 
430
 
def get_text_message(infotext, ignoreline = "default"):
431
 
    import tempfile
432
 
    
433
 
    if ignoreline == "default":
434
 
        ignoreline = "-- This line and the following will be ignored --"
435
 
        
436
 
    try:
437
 
        tmp_fileno, msgfilename = tempfile.mkstemp()
438
 
        msgfile = os.close(tmp_fileno)
439
 
        if infotext is not None and infotext != "":
440
 
            hasinfo = True
441
 
            msgfile = file(msgfilename, "w")
442
 
            msgfile.write("\n\n%s\n\n%s" % (ignoreline, infotext))
443
 
            msgfile.close()
444
 
        else:
445
 
            hasinfo = False
446
 
 
447
 
        if not _run_editor(msgfilename):
448
 
            return None
449
 
        
450
 
        started = False
451
 
        msg = []
452
 
        lastline, nlines = 0, 0
453
 
        for line in file(msgfilename, "r"):
454
 
            stripped_line = line.strip()
455
 
            # strip empty line before the log message starts
456
 
            if not started:
457
 
                if stripped_line != "":
458
 
                    started = True
459
 
                else:
460
 
                    continue
461
 
            # check for the ignore line only if there
462
 
            # is additional information at the end
463
 
            if hasinfo and stripped_line == ignoreline:
464
 
                break
465
 
            nlines += 1
466
 
            # keep track of the last line that had some content
467
 
            if stripped_line != "":
468
 
                lastline = nlines
469
 
            msg.append(line)
470
 
            
471
 
        if len(msg) == 0:
472
 
            return None
473
 
        # delete empty lines at the end
474
 
        del msg[lastline:]
475
 
        # add a newline at the end, if needed
476
 
        if not msg[-1].endswith("\n"):
477
 
            return "%s%s" % ("".join(msg), "\n")
478
 
        else:
479
 
            return "".join(msg)
480
 
    finally:
481
 
        # delete the msg file in any case
482
 
        try: os.unlink(msgfilename)
483
 
        except IOError: pass
 
355
            bailout('command failed')
 
356