~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: aaron.bentley at utoronto
  • Date: 2005-09-04 02:59:56 UTC
  • mfrom: (1172)
  • mto: (1185.3.4)
  • mto: This revision was merged to the branch mainline in revision 1178.
  • Revision ID: aaron.bentley@utoronto.ca-20050904025956-776ba4f07de97700
Merged mpool's latest changes (~0.0.7)

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
    os.chmod(filename, mod)
38
38
 
39
39
 
40
 
_QUOTE_RE = re.compile(r'([^a-zA-Z0-9.,:/_~-])')
 
40
_QUOTE_RE = None
 
41
 
 
42
 
41
43
def quotefn(f):
42
 
    """Return shell-quoted filename"""
43
 
    ## We could be a bit more terse by using double-quotes etc
44
 
    f = _QUOTE_RE.sub(r'\\\1', f)
45
 
    if f[0] == '~':
46
 
        f[0:1] = r'\~' 
47
 
    return f
 
44
    """Return a quoted filename filename
 
45
 
 
46
    This previously used backslash quoting, but that works poorly on
 
47
    Windows."""
 
48
    # TODO: I'm not really sure this is the best format either.x
 
49
    global _QUOTE_RE
 
50
    if _QUOTE_RE == None:
 
51
        _QUOTE_RE = re.compile(r'([^a-zA-Z0-9.,:/_~-])')
 
52
        
 
53
    if _QUOTE_RE.search(f):
 
54
        return '"' + f + '"'
 
55
    else:
 
56
        return f
48
57
 
49
58
 
50
59
def file_kind(f):
71
80
 
72
81
 
73
82
 
 
83
def backup_file(fn):
 
84
    """Copy a file to a backup.
 
85
 
 
86
    Backups are named in GNU-style, with a ~ suffix.
 
87
 
 
88
    If the file is already a backup, it's not copied.
 
89
    """
 
90
    import os
 
91
    if fn[-1] == '~':
 
92
        return
 
93
    bfn = fn + '~'
 
94
 
 
95
    inf = file(fn, 'rb')
 
96
    try:
 
97
        content = inf.read()
 
98
    finally:
 
99
        inf.close()
 
100
    
 
101
    outf = file(bfn, 'wb')
 
102
    try:
 
103
        outf.write(content)
 
104
    finally:
 
105
        outf.close()
 
106
 
 
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
 
 
119
 
 
120
 
74
121
def isdir(f):
75
122
    """True if f is an accessible directory."""
76
123
    try:
90
137
 
91
138
def is_inside(dir, fname):
92
139
    """True if fname is inside dir.
 
140
    
 
141
    The parameters should typically be passed to os.path.normpath first, so
 
142
    that . and .. and repeated slashes are eliminated, and the separators
 
143
    are canonical for the platform.
 
144
    
 
145
    The empty string as a dir name is taken as top-of-tree and matches 
 
146
    everything.
 
147
    
 
148
    >>> is_inside('src', 'src/foo.c')
 
149
    True
 
150
    >>> is_inside('src', 'srccontrol')
 
151
    False
 
152
    >>> is_inside('src', 'src/a/a/a/foo.c')
 
153
    True
 
154
    >>> is_inside('foo.c', 'foo.c')
 
155
    True
 
156
    >>> is_inside('foo.c', '')
 
157
    False
 
158
    >>> is_inside('', 'foo.c')
 
159
    True
93
160
    """
94
 
    return os.path.commonprefix([dir, fname]) == dir
 
161
    # XXX: Most callers of this can actually do something smarter by 
 
162
    # looking at the inventory
 
163
    if dir == fname:
 
164
        return True
 
165
    
 
166
    if dir == '':
 
167
        return True
 
168
    
 
169
    if dir[-1] != os.sep:
 
170
        dir += os.sep
 
171
    
 
172
    return fname.startswith(dir)
95
173
 
96
174
 
97
175
def is_inside_any(dir_list, fname):
98
176
    """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
177
    for dirname in dir_list:
104
178
        if is_inside(dirname, fname):
105
179
            return True
198
272
    return realname, (username + '@' + socket.gethostname())
199
273
 
200
274
 
201
 
def _get_user_id():
 
275
def _get_user_id(branch):
202
276
    """Return the full user id from a file or environment variable.
203
277
 
204
 
    TODO: Allow taking this from a file in the branch directory too
205
 
    for per-branch ids."""
 
278
    e.g. "John Hacker <jhacker@foo.org>"
 
279
 
 
280
    branch
 
281
        A branch to use for a per-branch configuration, or None.
 
282
 
 
283
    The following are searched in order:
 
284
 
 
285
    1. $BZREMAIL
 
286
    2. .bzr/email for this branch.
 
287
    3. ~/.bzr.conf/email
 
288
    4. $EMAIL
 
289
    """
206
290
    v = os.environ.get('BZREMAIL')
207
291
    if v:
208
292
        return v.decode(bzrlib.user_encoding)
 
293
 
 
294
    if branch:
 
295
        try:
 
296
            return (branch.controlfile("email", "r") 
 
297
                    .read()
 
298
                    .decode(bzrlib.user_encoding)
 
299
                    .rstrip("\r\n"))
 
300
        except IOError, e:
 
301
            if e.errno != errno.ENOENT:
 
302
                raise
 
303
        except BzrError, e:
 
304
            pass
209
305
    
210
306
    try:
211
307
        return (open(os.path.join(config_dir(), "email"))
223
319
        return None
224
320
 
225
321
 
226
 
def username():
 
322
def username(branch):
227
323
    """Return email-style username.
228
324
 
229
325
    Something similar to 'Martin Pool <mbp@sourcefrog.net>'
230
326
 
231
327
    TODO: Check it's reasonably well-formed.
232
328
    """
233
 
    v = _get_user_id()
 
329
    v = _get_user_id(branch)
234
330
    if v:
235
331
        return v
236
332
    
241
337
        return email
242
338
 
243
339
 
244
 
_EMAIL_RE = re.compile(r'[\w+.-]+@[\w+.-]+')
245
 
def user_email():
 
340
def user_email(branch):
246
341
    """Return just the email component of a username."""
247
 
    e = _get_user_id()
 
342
    e = _get_user_id(branch)
248
343
    if e:
249
 
        m = _EMAIL_RE.search(e)
 
344
        m = re.search(r'[\w+.-]+@[\w+.-]+', e)
250
345
        if not m:
251
346
            raise BzrError("%r doesn't seem to contain a reasonable email address" % e)
252
347
        return m.group(0)
296
391
        tt = time.localtime(t)
297
392
        offset = local_time_offset(t)
298
393
    else:
299
 
        raise BzrError("unsupported timezone format %r",
300
 
                ['options are "utc", "original", "local"'])
 
394
        raise BzrError("unsupported timezone format %r" % timezone,
 
395
                       ['options are "utc", "original", "local"'])
301
396
 
302
397
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
303
398
            + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
384
479
        if not ignore_errors:
385
480
            raise BzrError('command failed')
386
481
 
 
482
 
 
483
def _read_config_value(name):
 
484
    """Read a config value from the file ~/.bzr.conf/<name>
 
485
    Return None if the file does not exist"""
 
486
    try:
 
487
        f = file(os.path.join(config_dir(), name), "r")
 
488
        return f.read().decode(bzrlib.user_encoding).rstrip("\r\n")
 
489
    except IOError, e:
 
490
        if e.errno == errno.ENOENT:
 
491
            return None
 
492
        raise
 
493
 
 
494