~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Martin Pool
  • Date: 2005-09-22 13:32:02 UTC
  • Revision ID: mbp@sourcefrog.net-20050922133202-347cfd35d2941dd5
- simple weave-based annotate code (not complete)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Bazaar-NG -- distributed version control
2
 
#
 
2
 
3
3
# Copyright (C) 2005 by Canonical Ltd
4
 
#
 
4
 
5
5
# This program is free software; you can redistribute it and/or modify
6
6
# it under the terms of the GNU General Public License as published by
7
7
# the Free Software Foundation; either version 2 of the License, or
8
8
# (at your option) any later version.
9
 
#
 
9
 
10
10
# This program is distributed in the hope that it will be useful,
11
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
13
# GNU General Public License for more details.
14
 
#
 
14
 
15
15
# You should have received a copy of the GNU General Public License
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
18
18
 
19
 
from shutil import copyfile
20
 
from stat import (S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE,
21
 
                  S_ISCHR, S_ISBLK, S_ISFIFO, S_ISSOCK)
 
19
import os, types, re, time, errno, sys
 
20
import sha
22
21
from cStringIO import StringIO
23
 
import errno
24
 
import os
25
 
import re
26
 
import sha
27
 
import sys
28
 
import time
29
 
import types
30
 
 
31
 
import bzrlib
 
22
 
 
23
from stat import S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE
 
24
 
32
25
from bzrlib.errors import BzrError
33
26
from bzrlib.trace import mutter
34
 
 
 
27
import bzrlib
35
28
 
36
29
def make_readonly(filename):
37
30
    """Make a filename read-only."""
 
31
    # TODO: probably needs to be fixed for windows
38
32
    mod = os.stat(filename).st_mode
39
33
    mod = mod & 0777555
40
34
    os.chmod(filename, mod)
57
51
    # TODO: I'm not really sure this is the best format either.x
58
52
    global _QUOTE_RE
59
53
    if _QUOTE_RE == None:
60
 
        _QUOTE_RE = re.compile(r'([^a-zA-Z0-9.,:/\\_~-])')
 
54
        _QUOTE_RE = re.compile(r'([^a-zA-Z0-9.,:/_~-])')
61
55
        
62
56
    if _QUOTE_RE.search(f):
63
57
        return '"' + f + '"'
73
67
        return 'directory'
74
68
    elif S_ISLNK(mode):
75
69
        return 'symlink'
76
 
    elif S_ISCHR(mode):
77
 
        return 'chardev'
78
 
    elif S_ISBLK(mode):
79
 
        return 'block'
80
 
    elif S_ISFIFO(mode):
81
 
        return 'fifo'
82
 
    elif S_ISSOCK(mode):
83
 
        return 'socket'
84
70
    else:
85
 
        return 'unknown'
 
71
        raise BzrError("can't handle file kind with mode %o of %r" % (mode, f))
86
72
 
87
73
 
88
74
def kind_marker(kind):
96
82
        raise BzrError('invalid file kind %r' % kind)
97
83
 
98
84
 
 
85
 
99
86
def backup_file(fn):
100
87
    """Copy a file to a backup.
101
88
 
119
106
    finally:
120
107
        outf.close()
121
108
 
122
 
if os.name == 'nt':
123
 
    import shutil
124
 
    rename = shutil.move
125
 
else:
126
 
    rename = os.rename
 
109
def rename(path_from, path_to):
 
110
    """Basically the same as os.rename() just special for win32"""
 
111
    if sys.platform == 'win32':
 
112
        try:
 
113
            os.remove(path_to)
 
114
        except OSError, e:
 
115
            if e.errno != e.ENOENT:
 
116
                raise
 
117
    os.rename(path_from, path_to)
 
118
 
 
119
 
 
120
 
127
121
 
128
122
 
129
123
def isdir(f):
134
128
        return False
135
129
 
136
130
 
 
131
 
137
132
def isfile(f):
138
133
    """True if f is a regular file."""
139
134
    try:
152
147
    The empty string as a dir name is taken as top-of-tree and matches 
153
148
    everything.
154
149
    
155
 
    >>> is_inside('src', os.path.join('src', 'foo.c'))
 
150
    >>> is_inside('src', 'src/foo.c')
156
151
    True
157
152
    >>> is_inside('src', 'srccontrol')
158
153
    False
159
 
    >>> is_inside('src', os.path.join('src', 'a', 'a', 'a', 'foo.c'))
 
154
    >>> is_inside('src', 'src/a/a/a/foo.c')
160
155
    True
161
156
    >>> is_inside('foo.c', 'foo.c')
162
157
    True
172
167
    
173
168
    if dir == '':
174
169
        return True
175
 
 
 
170
    
176
171
    if dir[-1] != os.sep:
177
172
        dir += os.sep
178
 
 
 
173
    
179
174
    return fname.startswith(dir)
180
175
 
181
176
 
193
188
    tofile.write(fromfile.read())
194
189
 
195
190
 
 
191
def uuid():
 
192
    """Return a new UUID"""
 
193
    try:
 
194
        return file('/proc/sys/kernel/random/uuid').readline().rstrip('\n')
 
195
    except IOError:
 
196
        return chomp(os.popen('uuidgen').readline())
 
197
 
 
198
 
196
199
def sha_file(f):
197
200
    if hasattr(f, 'tell'):
198
201
        assert f.tell() == 0
220
223
    return s.hexdigest()
221
224
 
222
225
 
 
226
 
223
227
def fingerprint_file(f):
224
228
    s = sha.new()
225
229
    b = f.read()
236
240
    
237
241
    TODO: Global option --config-dir to override this.
238
242
    """
239
 
    return os.path.join(os.path.expanduser("~"), ".bzr.conf")
 
243
    return os.path.expanduser("~/.bzr.conf")
240
244
 
241
245
 
242
246
def _auto_user_id():
346
350
    if e:
347
351
        m = re.search(r'[\w+.-]+@[\w+.-]+', e)
348
352
        if not m:
349
 
            raise BzrError("%r doesn't seem to contain "
350
 
                           "a reasonable email address" % e)
 
353
            raise BzrError("%r doesn't seem to contain a reasonable email address" % e)
351
354
        return m.group(0)
352
355
 
353
356
    return _auto_user_id()[1]
 
357
    
354
358
 
355
359
 
356
360
def compare_files(a, b):
365
369
            return True
366
370
 
367
371
 
 
372
 
368
373
def local_time_offset(t=None):
369
374
    """Return offset of local zone from GMT, either at present or at time t."""
370
375
    # python2.3 localtime() can't take None
409
414
    """Return size of given open file."""
410
415
    return os.fstat(f.fileno())[ST_SIZE]
411
416
 
412
 
# Define rand_bytes based on platform.
413
 
try:
414
 
    # Python 2.4 and later have os.urandom,
415
 
    # but it doesn't work on some arches
416
 
    os.urandom(1)
 
417
 
 
418
if hasattr(os, 'urandom'): # python 2.4 and later
417
419
    rand_bytes = os.urandom
418
 
except (NotImplementedError, AttributeError):
419
 
    # If python doesn't have os.urandom, or it doesn't work,
420
 
    # then try to first pull random data from /dev/urandom
421
 
    if os.path.exists("/dev/urandom"):
422
 
        rand_bytes = file('/dev/urandom', 'rb').read
423
 
    # Otherwise, use this hack as a last resort
424
 
    else:
425
 
        # not well seeded, but better than nothing
426
 
        def rand_bytes(n):
427
 
            import random
428
 
            s = ''
429
 
            while n:
430
 
                s += chr(random.randint(0, 255))
431
 
                n -= 1
432
 
            return s
 
420
elif sys.platform == 'linux2':
 
421
    rand_bytes = file('/dev/urandom', 'rb').read
 
422
else:
 
423
    # not well seeded, but better than nothing
 
424
    def rand_bytes(n):
 
425
        import random
 
426
        s = ''
 
427
        while n:
 
428
            s += chr(random.randint(0, 255))
 
429
            n -= 1
 
430
        return s
 
431
 
433
432
 
434
433
## TODO: We could later have path objects that remember their list
435
434
## decomposition (might be too tricksy though.)
481
480
        return os.path.join(p1, p2)
482
481
    
483
482
 
 
483
def extern_command(cmd, ignore_errors = False):
 
484
    mutter('external command: %s' % `cmd`)
 
485
    if os.system(cmd):
 
486
        if not ignore_errors:
 
487
            raise BzrError('command failed')
 
488
 
 
489
 
484
490
def _read_config_value(name):
485
491
    """Read a config value from the file ~/.bzr.conf/<name>
486
492
    Return None if the file does not exist"""
493
499
        raise
494
500
 
495
501
 
 
502
 
496
503
def split_lines(s):
497
504
    """Split s into lines, but without removing the newline characters."""
498
505
    return StringIO(s).readlines()
499
 
 
500
 
 
501
 
def hardlinks_good():
502
 
    return sys.platform not in ('win32', 'cygwin', 'darwin')
503
 
 
504
 
 
505
 
def link_or_copy(src, dest):
506
 
    """Hardlink a file, or copy it if it can't be hardlinked."""
507
 
    if not hardlinks_good():
508
 
        copyfile(src, dest)
509
 
        return
510
 
    try:
511
 
        os.link(src, dest)
512
 
    except (OSError, IOError), e:
513
 
        if e.errno != errno.EXDEV:
514
 
            raise
515
 
        copyfile(src, dest)
 
506