~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 00:47:18 UTC
  • Revision ID: mbp@sourcefrog.net-20050510004718-5f45d2d22fd94532
Doc

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
 
    bailout('uuids not allowed!')
90
 
    return chomp(os.popen('uuidgen').readline())
91
 
 
92
 
def chomp(s):
93
 
    if s and (s[-1] == '\n'):
94
 
        return s[:-1]
95
 
    else:
96
 
        return s
 
87
    try:
 
88
        return file('/proc/sys/kernel/random/uuid').readline().rstrip('\n')
 
89
    except IOError:
 
90
        return chomp(os.popen('uuidgen').readline())
97
91
 
98
92
 
99
93
def sha_file(f):
100
94
    import sha
101
 
    ## TODO: Maybe read in chunks to handle big files
102
95
    if hasattr(f, 'tell'):
103
96
        assert f.tell() == 0
104
97
    s = sha.new()
105
 
    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)
106
104
    return s.hexdigest()
107
105
 
108
106
 
114
112
 
115
113
 
116
114
 
117
 
def username():
118
 
    """Return email-style username.
119
 
 
120
 
    Something similar to 'Martin Pool <mbp@sourcefrog.net>'
121
 
 
122
 
    :todo: Check it's reasonably well-formed.
123
 
 
124
 
    :todo: Allow taking it from a dotfile to help people on windows
125
 
           who can't easily set variables.
126
 
 
127
 
    :todo: Cope without pwd module, which is only on unix. 
128
 
    """
129
 
    e = os.environ.get('BZREMAIL') or os.environ.get('EMAIL')
130
 
    if e: return e
131
 
 
 
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
    """
132
146
    import socket
133
 
    
 
147
 
 
148
    # XXX: Any good way to get real user name on win32?
 
149
 
134
150
    try:
135
151
        import pwd
136
152
        uid = os.getuid()
137
153
        w = pwd.getpwuid(uid)
138
 
        gecos = w.pw_gecos
 
154
        gecos = w.pw_gecos.decode(bzrlib.user_encoding)
 
155
        username = w.pw_name.decode(bzrlib.user_encoding)
139
156
        comma = gecos.find(',')
140
157
        if comma == -1:
141
158
            realname = gecos
142
159
        else:
143
160
            realname = gecos[:comma]
144
 
        return '%s <%s@%s>' % (realname, w.pw_name, socket.getfqdn())
 
161
        if not realname:
 
162
            realname = username
 
163
 
145
164
    except ImportError:
146
 
        pass
147
 
 
148
 
    import getpass, socket
149
 
    return '<%s@%s>' % (getpass.getuser(), socket.getfqdn())
150
 
 
151
 
 
 
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+.-]+')
152
215
def user_email():
153
216
    """Return just the email component of a username."""
154
 
    e = os.environ.get('BZREMAIL') or os.environ.get('EMAIL')
 
217
    e = _get_user_id()
155
218
    if e:
156
 
        import re
157
 
        m = re.search(r'[\w+.-]+@[\w+.-]+', e)
 
219
        m = _EMAIL_RE.search(e)
158
220
        if not m:
159
 
            bailout('%r is not a reasonable email address' % e)
 
221
            bailout("%r doesn't seem to contain a reasonable email address" % e)
160
222
        return m.group(0)
161
223
 
162
 
 
163
 
    import getpass, socket
164
 
    return '%s@%s' % (getpass.getuser(), socket.getfqdn())
165
 
 
 
224
    return _auto_user_id()[1]
166
225
    
167
226
 
168
227
 
169
228
def compare_files(a, b):
170
229
    """Returns true if equal in contents"""
171
 
    # TODO: don't read the whole thing in one go.
172
 
    result = a.read() == b.read()
173
 
    return result
174
 
 
175
 
 
176
 
 
177
 
def local_time_offset():
178
 
    if time.daylight:
 
230
    BUFSIZE = 4096
 
231
    while True:
 
232
        ai = a.read(BUFSIZE)
 
233
        bi = b.read(BUFSIZE)
 
234
        if ai != bi:
 
235
            return False
 
236
        if ai == '':
 
237
            return True
 
238
 
 
239
 
 
240
 
 
241
def local_time_offset(t=None):
 
242
    """Return offset of local zone from GMT, either at present or at time t."""
 
243
    # python2.3 localtime() can't take None
 
244
    if t == None:
 
245
        t = time.time()
 
246
        
 
247
    if time.localtime(t).tm_isdst and time.daylight:
179
248
        return -time.altzone
180
249
    else:
181
250
        return -time.timezone
184
253
def format_date(t, offset=0, timezone='original'):
185
254
    ## TODO: Perhaps a global option to use either universal or local time?
186
255
    ## Or perhaps just let people set $TZ?
187
 
    import time
188
 
    
189
256
    assert isinstance(t, float)
190
257
    
191
258
    if timezone == 'utc':
197
264
        tt = time.gmtime(t + offset)
198
265
    elif timezone == 'local':
199
266
        tt = time.localtime(t)
200
 
        offset = local_time_offset()
 
267
        offset = local_time_offset(t)
201
268
    else:
202
269
        bailout("unsupported timezone format %r",
203
270
                ['options are "utc", "original", "local"'])
244
311
    BzrError: ("sorry, '..' not allowed in path", [])
245
312
    """
246
313
    assert isinstance(p, types.StringTypes)
247
 
    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 = []
248
320
    for f in ps:
249
321
        if f == '..':
250
322
            bailout("sorry, %r not allowed in path" % f)
251
 
    return ps
 
323
        elif (f == '.') or (f == ''):
 
324
            pass
 
325
        else:
 
326
            rps.append(f)
 
327
    return rps
252
328
 
253
329
def joinpath(p):
254
330
    assert isinstance(p, list)
255
331
    for f in p:
256
 
        if (f == '..') or (f is None) or (f == ''):
 
332
        if (f == '..') or (f == None) or (f == ''):
257
333
            bailout("sorry, %r not allowed in path" % f)
258
 
    return '/'.join(p)
 
334
    return os.path.join(*p)
259
335
 
260
336
 
261
337
def appendpath(p1, p2):
262
338
    if p1 == '':
263
339
        return p2
264
340
    else:
265
 
        return p1 + '/' + p2
 
341
        return os.path.join(p1, p2)
266
342
    
267
343
 
268
344
def extern_command(cmd, ignore_errors = False):