~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Martin Pool
  • Date: 2005-05-10 08:15:58 UTC
  • Revision ID: mbp@sourcefrog.net-20050510081558-9a38e2c46ba4ebc4
- Patch from Fredrik Lundh to check Python version and 
  try to find a better one if it's too old.

  Patched to try to prevent infinite loops in wierd configurations,
  and to log to stderr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
import os, types, re, time, types
 
19
import os, types, re, time, errno
20
20
from stat import S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE
21
21
 
22
 
from errors import bailout
 
22
from errors import bailout, BzrError
 
23
from trace import mutter
 
24
import bzrlib
23
25
 
24
26
def make_readonly(filename):
25
27
    """Make a filename read-only."""
54
56
    elif S_ISLNK(mode):
55
57
        return 'symlink'
56
58
    else:
57
 
        bailout("can't handle file kind with mode %o of %r" % (mode, f)) 
 
59
        raise BzrError("can't handle file kind with mode %o of %r" % (mode, f)) 
58
60
 
59
61
 
60
62
 
82
84
 
83
85
def uuid():
84
86
    """Return a new UUID"""
85
 
    
86
 
    ## XXX: Could alternatively read /proc/sys/kernel/random/uuid on
87
 
    ## Linux, but we need something portable for other systems;
88
 
    ## preferably an implementation in Python.
89
87
    try:
90
 
        return chomp(file('/proc/sys/kernel/random/uuid').readline())
 
88
        return file('/proc/sys/kernel/random/uuid').readline().rstrip('\n')
91
89
    except IOError:
92
90
        return chomp(os.popen('uuidgen').readline())
93
91
 
94
92
 
95
 
def chomp(s):
96
 
    if s and (s[-1] == '\n'):
97
 
        return s[:-1]
98
 
    else:
99
 
        return s
100
 
 
101
 
 
102
93
def sha_file(f):
103
94
    import sha
104
 
    ## TODO: Maybe read in chunks to handle big files
105
95
    if hasattr(f, 'tell'):
106
96
        assert f.tell() == 0
107
97
    s = sha.new()
108
 
    s.update(f.read())
 
98
    BUFSIZE = 128<<10
 
99
    while True:
 
100
        b = f.read(BUFSIZE)
 
101
        if not b:
 
102
            break
 
103
        s.update(b)
109
104
    return s.hexdigest()
110
105
 
111
106
 
117
112
 
118
113
 
119
114
 
120
 
def username():
121
 
    """Return email-style username.
122
 
 
123
 
    Something similar to 'Martin Pool <mbp@sourcefrog.net>'
124
 
 
125
 
    :todo: Check it's reasonably well-formed.
126
 
 
127
 
    :todo: Allow taking it from a dotfile to help people on windows
128
 
           who can't easily set variables.
129
 
 
130
 
    :todo: Cope without pwd module, which is only on unix. 
131
 
    """
132
 
    e = os.environ.get('BZREMAIL') or os.environ.get('EMAIL')
133
 
    if e: return e
134
 
 
 
115
def fingerprint_file(f):
 
116
    import sha
 
117
    s = sha.new()
 
118
    b = f.read()
 
119
    s.update(b)
 
120
    size = len(b)
 
121
    return {'size': size,
 
122
            'sha1': s.hexdigest()}
 
123
 
 
124
 
 
125
def config_dir():
 
126
    """Return per-user configuration directory.
 
127
 
 
128
    By default this is ~/.bzr.conf/
 
129
    
 
130
    TODO: Global option --config-dir to override this.
 
131
    """
 
132
    return os.path.expanduser("~/.bzr.conf")
 
133
 
 
134
 
 
135
def _auto_user_id():
 
136
    """Calculate automatic user identification.
 
137
 
 
138
    Returns (realname, email).
 
139
 
 
140
    Only used when none is set in the environment or the id file.
 
141
 
 
142
    This previously used the FQDN as the default domain, but that can
 
143
    be very slow on machines where DNS is broken.  So now we simply
 
144
    use the hostname.
 
145
    """
135
146
    import socket
136
 
    
 
147
 
 
148
    # XXX: Any good way to get real user name on win32?
 
149
 
137
150
    try:
138
151
        import pwd
139
152
        uid = os.getuid()
140
153
        w = pwd.getpwuid(uid)
141
 
        gecos = w.pw_gecos
 
154
        gecos = w.pw_gecos.decode(bzrlib.user_encoding)
 
155
        username = w.pw_name.decode(bzrlib.user_encoding)
142
156
        comma = gecos.find(',')
143
157
        if comma == -1:
144
158
            realname = gecos
145
159
        else:
146
160
            realname = gecos[:comma]
147
 
        return '%s <%s@%s>' % (realname, w.pw_name, socket.getfqdn())
 
161
        if not realname:
 
162
            realname = username
 
163
 
148
164
    except ImportError:
149
 
        pass
150
 
 
151
 
    import getpass, socket
152
 
    return '<%s@%s>' % (getpass.getuser(), socket.getfqdn())
153
 
 
154
 
 
 
165
        import getpass
 
166
        realname = username = getpass.getuser().decode(bzrlib.user_encoding)
 
167
 
 
168
    return realname, (username + '@' + socket.gethostname())
 
169
 
 
170
 
 
171
def _get_user_id():
 
172
    """Return the full user id from a file or environment variable.
 
173
 
 
174
    TODO: Allow taking this from a file in the branch directory too
 
175
    for per-branch ids."""
 
176
    v = os.environ.get('BZREMAIL')
 
177
    if v:
 
178
        return v.decode(bzrlib.user_encoding)
 
179
    
 
180
    try:
 
181
        return (open(os.path.join(config_dir(), "email"))
 
182
                .read()
 
183
                .decode(bzrlib.user_encoding)
 
184
                .rstrip("\r\n"))
 
185
    except IOError, e:
 
186
        if e.errno != errno.ENOENT:
 
187
            raise e
 
188
 
 
189
    v = os.environ.get('EMAIL')
 
190
    if v:
 
191
        return v.decode(bzrlib.user_encoding)
 
192
    else:    
 
193
        return None
 
194
 
 
195
 
 
196
def username():
 
197
    """Return email-style username.
 
198
 
 
199
    Something similar to 'Martin Pool <mbp@sourcefrog.net>'
 
200
 
 
201
    TODO: Check it's reasonably well-formed.
 
202
    """
 
203
    v = _get_user_id()
 
204
    if v:
 
205
        return v
 
206
    
 
207
    name, email = _auto_user_id()
 
208
    if name:
 
209
        return '%s <%s>' % (name, email)
 
210
    else:
 
211
        return email
 
212
 
 
213
 
 
214
_EMAIL_RE = re.compile(r'[\w+.-]+@[\w+.-]+')
155
215
def user_email():
156
216
    """Return just the email component of a username."""
157
 
    e = os.environ.get('BZREMAIL') or os.environ.get('EMAIL')
 
217
    e = _get_user_id()
158
218
    if e:
159
 
        import re
160
 
        m = re.search(r'[\w+.-]+@[\w+.-]+', e)
 
219
        m = _EMAIL_RE.search(e)
161
220
        if not m:
162
 
            bailout('%r is not a reasonable email address' % e)
 
221
            bailout("%r doesn't seem to contain a reasonable email address" % e)
163
222
        return m.group(0)
164
223
 
165
 
 
166
 
    import getpass, socket
167
 
    return '%s@%s' % (getpass.getuser(), socket.getfqdn())
168
 
 
 
224
    return _auto_user_id()[1]
169
225
    
170
226
 
171
227
 
172
228
def compare_files(a, b):
173
229
    """Returns true if equal in contents"""
174
 
    # TODO: don't read the whole thing in one go.
175
230
    BUFSIZE = 4096
176
231
    while True:
177
232
        ai = a.read(BUFSIZE)
186
241
def local_time_offset(t=None):
187
242
    """Return offset of local zone from GMT, either at present or at time t."""
188
243
    # python2.3 localtime() can't take None
189
 
    if t is None:
 
244
    if t == None:
190
245
        t = time.time()
191
246
        
192
247
    if time.localtime(t).tm_isdst and time.daylight:
198
253
def format_date(t, offset=0, timezone='original'):
199
254
    ## TODO: Perhaps a global option to use either universal or local time?
200
255
    ## Or perhaps just let people set $TZ?
201
 
    import time
202
 
    
203
256
    assert isinstance(t, float)
204
257
    
205
258
    if timezone == 'utc':
258
311
    BzrError: ("sorry, '..' not allowed in path", [])
259
312
    """
260
313
    assert isinstance(p, types.StringTypes)
261
 
    ps = [f for f in p.split('/') if f != '.']
 
314
 
 
315
    # split on either delimiter because people might use either on
 
316
    # Windows
 
317
    ps = re.split(r'[\\/]', p)
 
318
 
 
319
    rps = []
262
320
    for f in ps:
263
321
        if f == '..':
264
322
            bailout("sorry, %r not allowed in path" % f)
265
 
    return ps
 
323
        elif (f == '.') or (f == ''):
 
324
            pass
 
325
        else:
 
326
            rps.append(f)
 
327
    return rps
266
328
 
267
329
def joinpath(p):
268
330
    assert isinstance(p, list)
269
331
    for f in p:
270
 
        if (f == '..') or (f is None) or (f == ''):
 
332
        if (f == '..') or (f == None) or (f == ''):
271
333
            bailout("sorry, %r not allowed in path" % f)
272
 
    return '/'.join(p)
 
334
    return os.path.join(*p)
273
335
 
274
336
 
275
337
def appendpath(p1, p2):
276
338
    if p1 == '':
277
339
        return p2
278
340
    else:
279
 
        return p1 + '/' + p2
 
341
        return os.path.join(p1, p2)
280
342
    
281
343
 
282
344
def extern_command(cmd, ignore_errors = False):