~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Martin Pool
  • Date: 2005-09-12 09:50:44 UTC
  • Revision ID: mbp@sourcefrog.net-20050912095044-6acfdb5611729987
- no tests in bzrlib.fetch anymore

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)
22
 
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
 
19
import os, types, re, time, errno, sys
 
20
from stat import S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE
30
21
 
31
 
import bzrlib
32
22
from bzrlib.errors import BzrError
33
23
from bzrlib.trace import mutter
34
 
 
 
24
import bzrlib
35
25
 
36
26
def make_readonly(filename):
37
27
    """Make a filename read-only."""
 
28
    # TODO: probably needs to be fixed for windows
38
29
    mod = os.stat(filename).st_mode
39
30
    mod = mod & 0777555
40
31
    os.chmod(filename, mod)
57
48
    # TODO: I'm not really sure this is the best format either.x
58
49
    global _QUOTE_RE
59
50
    if _QUOTE_RE == None:
60
 
        _QUOTE_RE = re.compile(r'([^a-zA-Z0-9.,:/\\_~-])')
 
51
        _QUOTE_RE = re.compile(r'([^a-zA-Z0-9.,:/_~-])')
61
52
        
62
53
    if _QUOTE_RE.search(f):
63
54
        return '"' + f + '"'
73
64
        return 'directory'
74
65
    elif S_ISLNK(mode):
75
66
        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
67
    else:
85
 
        return 'unknown'
 
68
        raise BzrError("can't handle file kind with mode %o of %r" % (mode, f))
86
69
 
87
70
 
88
71
def kind_marker(kind):
95
78
    else:
96
79
        raise BzrError('invalid file kind %r' % kind)
97
80
 
98
 
def lexists(f):
99
 
    try:
100
 
        if hasattr(os, 'lstat'):
101
 
            os.lstat(f)
102
 
        else:
103
 
            os.stat(f)
104
 
        return True
105
 
    except OSError,e:
106
 
        if e.errno == errno.ENOENT:
107
 
            return False;
108
 
        else:
109
 
            raise BzrError("lstat/stat of (%r): %r" % (f, e))
110
81
 
111
 
def normalizepath(f):
112
 
    if hasattr(os.path, 'realpath'):
113
 
        F = os.path.realpath
114
 
    else:
115
 
        F = os.path.abspath
116
 
    [p,e] = os.path.split(f)
117
 
    if e == "" or e == "." or e == "..":
118
 
        return F(f)
119
 
    else:
120
 
        return os.path.join(F(p), e)
121
 
    
122
82
 
123
83
def backup_file(fn):
124
84
    """Copy a file to a backup.
127
87
 
128
88
    If the file is already a backup, it's not copied.
129
89
    """
 
90
    import os
130
91
    if fn[-1] == '~':
131
92
        return
132
93
    bfn = fn + '~'
143
104
    finally:
144
105
        outf.close()
145
106
 
146
 
if os.name == 'nt':
147
 
    import shutil
148
 
    rename = shutil.move
149
 
else:
150
 
    rename = os.rename
 
107
def rename(path_from, path_to):
 
108
    """Basically the same as os.rename() just special for win32"""
 
109
    if sys.platform == 'win32':
 
110
        try:
 
111
            os.remove(path_to)
 
112
        except OSError, e:
 
113
            if e.errno != e.ENOENT:
 
114
                raise
 
115
    os.rename(path_from, path_to)
 
116
 
 
117
 
 
118
 
151
119
 
152
120
 
153
121
def isdir(f):
158
126
        return False
159
127
 
160
128
 
 
129
 
161
130
def isfile(f):
162
131
    """True if f is a regular file."""
163
132
    try:
165
134
    except OSError:
166
135
        return False
167
136
 
168
 
def islink(f):
169
 
    """True if f is a symlink."""
170
 
    try:
171
 
        return S_ISLNK(os.lstat(f)[ST_MODE])
172
 
    except OSError:
173
 
        return False
174
137
 
175
138
def is_inside(dir, fname):
176
139
    """True if fname is inside dir.
182
145
    The empty string as a dir name is taken as top-of-tree and matches 
183
146
    everything.
184
147
    
185
 
    >>> is_inside('src', os.path.join('src', 'foo.c'))
 
148
    >>> is_inside('src', 'src/foo.c')
186
149
    True
187
150
    >>> is_inside('src', 'srccontrol')
188
151
    False
189
 
    >>> is_inside('src', os.path.join('src', 'a', 'a', 'a', 'foo.c'))
 
152
    >>> is_inside('src', 'src/a/a/a/foo.c')
190
153
    True
191
154
    >>> is_inside('foo.c', 'foo.c')
192
155
    True
202
165
    
203
166
    if dir == '':
204
167
        return True
205
 
 
 
168
    
206
169
    if dir[-1] != os.sep:
207
170
        dir += os.sep
208
 
 
 
171
    
209
172
    return fname.startswith(dir)
210
173
 
211
174
 
223
186
    tofile.write(fromfile.read())
224
187
 
225
188
 
 
189
def uuid():
 
190
    """Return a new UUID"""
 
191
    try:
 
192
        return file('/proc/sys/kernel/random/uuid').readline().rstrip('\n')
 
193
    except IOError:
 
194
        return chomp(os.popen('uuidgen').readline())
 
195
 
 
196
 
226
197
def sha_file(f):
 
198
    import sha
227
199
    if hasattr(f, 'tell'):
228
200
        assert f.tell() == 0
229
201
    s = sha.new()
236
208
    return s.hexdigest()
237
209
 
238
210
 
239
 
 
240
 
def sha_strings(strings):
241
 
    """Return the sha-1 of concatenation of strings"""
242
 
    s = sha.new()
243
 
    map(s.update, strings)
244
 
    return s.hexdigest()
245
 
 
246
 
 
247
211
def sha_string(f):
 
212
    import sha
248
213
    s = sha.new()
249
214
    s.update(f)
250
215
    return s.hexdigest()
251
216
 
252
217
 
 
218
 
253
219
def fingerprint_file(f):
 
220
    import sha
254
221
    s = sha.new()
255
222
    b = f.read()
256
223
    s.update(b)
266
233
    
267
234
    TODO: Global option --config-dir to override this.
268
235
    """
269
 
    return os.path.join(os.path.expanduser("~"), ".bzr.conf")
 
236
    return os.path.expanduser("~/.bzr.conf")
270
237
 
271
238
 
272
239
def _auto_user_id():
376
343
    if e:
377
344
        m = re.search(r'[\w+.-]+@[\w+.-]+', e)
378
345
        if not m:
379
 
            raise BzrError("%r doesn't seem to contain "
380
 
                           "a reasonable email address" % e)
 
346
            raise BzrError("%r doesn't seem to contain a reasonable email address" % e)
381
347
        return m.group(0)
382
348
 
383
349
    return _auto_user_id()[1]
 
350
    
384
351
 
385
352
 
386
353
def compare_files(a, b):
395
362
            return True
396
363
 
397
364
 
 
365
 
398
366
def local_time_offset(t=None):
399
367
    """Return offset of local zone from GMT, either at present or at time t."""
400
368
    # python2.3 localtime() can't take None
439
407
    """Return size of given open file."""
440
408
    return os.fstat(f.fileno())[ST_SIZE]
441
409
 
442
 
# Define rand_bytes based on platform.
443
 
try:
444
 
    # Python 2.4 and later have os.urandom,
445
 
    # but it doesn't work on some arches
446
 
    os.urandom(1)
 
410
 
 
411
if hasattr(os, 'urandom'): # python 2.4 and later
447
412
    rand_bytes = os.urandom
448
 
except (NotImplementedError, AttributeError):
449
 
    # If python doesn't have os.urandom, or it doesn't work,
450
 
    # then try to first pull random data from /dev/urandom
451
 
    if os.path.exists("/dev/urandom"):
452
 
        rand_bytes = file('/dev/urandom', 'rb').read
453
 
    # Otherwise, use this hack as a last resort
454
 
    else:
455
 
        # not well seeded, but better than nothing
456
 
        def rand_bytes(n):
457
 
            import random
458
 
            s = ''
459
 
            while n:
460
 
                s += chr(random.randint(0, 255))
461
 
                n -= 1
462
 
            return s
 
413
elif sys.platform == 'linux2':
 
414
    rand_bytes = file('/dev/urandom', 'rb').read
 
415
else:
 
416
    # not well seeded, but better than nothing
 
417
    def rand_bytes(n):
 
418
        import random
 
419
        s = ''
 
420
        while n:
 
421
            s += chr(random.randint(0, 255))
 
422
            n -= 1
 
423
        return s
 
424
 
463
425
 
464
426
## TODO: We could later have path objects that remember their list
465
427
## decomposition (might be too tricksy though.)
511
473
        return os.path.join(p1, p2)
512
474
    
513
475
 
 
476
def extern_command(cmd, ignore_errors = False):
 
477
    mutter('external command: %s' % `cmd`)
 
478
    if os.system(cmd):
 
479
        if not ignore_errors:
 
480
            raise BzrError('command failed')
 
481
 
 
482
 
514
483
def _read_config_value(name):
515
484
    """Read a config value from the file ~/.bzr.conf/<name>
516
485
    Return None if the file does not exist"""
523
492
        raise
524
493
 
525
494
 
526
 
def split_lines(s):
527
 
    """Split s into lines, but without removing the newline characters."""
528
 
    return StringIO(s).readlines()
529
 
 
530
 
 
531
 
def hardlinks_good():
532
 
    return sys.platform not in ('win32', 'cygwin', 'darwin')
533
 
 
534
 
 
535
 
def link_or_copy(src, dest):
536
 
    """Hardlink a file, or copy it if it can't be hardlinked."""
537
 
    if not hardlinks_good():
538
 
        copyfile(src, dest)
539
 
        return
540
 
    try:
541
 
        os.link(src, dest)
542
 
    except (OSError, IOError), e:
543
 
        if e.errno != errno.EXDEV:
544
 
            raise
545
 
        copyfile(src, dest)
546
 
 
547
 
 
548
 
def has_symlinks():
549
 
    if hasattr(os, 'symlink'):
550
 
        return True
551
 
    else:
552
 
        return False