~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/osutils.py

  • Committer: Martin Pool
  • Date: 2005-04-15 02:41:52 UTC
  • Revision ID: mbp@sourcefrog.net-20050415024152-caf2e2f1c3ec6129
- remove atexit() dependency for writing out execution times

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
 
86
88
    ## XXX: Could alternatively read /proc/sys/kernel/random/uuid on
87
89
    ## Linux, but we need something portable for other systems;
88
90
    ## preferably an implementation in Python.
89
 
    bailout('uuids not allowed!')
90
 
    return chomp(os.popen('uuidgen').readline())
 
91
    try:
 
92
        return chomp(file('/proc/sys/kernel/random/uuid').readline())
 
93
    except IOError:
 
94
        return chomp(os.popen('uuidgen').readline())
 
95
 
91
96
 
92
97
def chomp(s):
93
98
    if s and (s[-1] == '\n'):
114
119
 
115
120
 
116
121
 
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
 
 
 
122
def fingerprint_file(f):
 
123
    import sha
 
124
    s = sha.new()
 
125
    b = f.read()
 
126
    s.update(b)
 
127
    size = len(b)
 
128
    return {'size': size,
 
129
            'sha1': s.hexdigest()}
 
130
 
 
131
 
 
132
def config_dir():
 
133
    """Return per-user configuration directory.
 
134
 
 
135
    By default this is ~/.bzr.conf/
 
136
    
 
137
    TODO: Global option --config-dir to override this.
 
138
    """
 
139
    return os.path.expanduser("~/.bzr.conf")
 
140
 
 
141
 
 
142
def _auto_user_id():
 
143
    """Calculate automatic user identification.
 
144
 
 
145
    Returns (realname, email).
 
146
 
 
147
    Only used when none is set in the environment or the id file.
 
148
 
 
149
    This previously used the FQDN as the default domain, but that can
 
150
    be very slow on machines where DNS is broken.  So now we simply
 
151
    use the hostname.
 
152
    """
132
153
    import socket
133
 
    
 
154
 
 
155
    # XXX: Any good way to get real user name on win32?
 
156
 
134
157
    try:
135
158
        import pwd
136
159
        uid = os.getuid()
137
160
        w = pwd.getpwuid(uid)
138
 
        gecos = w.pw_gecos
 
161
        gecos = w.pw_gecos.decode(bzrlib.user_encoding)
 
162
        username = w.pw_name.decode(bzrlib.user_encoding)
139
163
        comma = gecos.find(',')
140
164
        if comma == -1:
141
165
            realname = gecos
142
166
        else:
143
167
            realname = gecos[:comma]
144
 
        return '%s <%s@%s>' % (realname, w.pw_name, socket.getfqdn())
 
168
        if not realname:
 
169
            realname = username
 
170
 
145
171
    except ImportError:
146
 
        pass
147
 
 
148
 
    import getpass, socket
149
 
    return '<%s@%s>' % (getpass.getuser(), socket.getfqdn())
150
 
 
151
 
 
 
172
        import getpass
 
173
        realname = username = getpass.getuser().decode(bzrlib.user_encoding)
 
174
 
 
175
    return realname, (username + '@' + socket.gethostname())
 
176
 
 
177
 
 
178
def _get_user_id():
 
179
    """Return the full user id from a file or environment variable.
 
180
 
 
181
    TODO: Allow taking this from a file in the branch directory too
 
182
    for per-branch ids."""
 
183
    v = os.environ.get('BZREMAIL')
 
184
    if v:
 
185
        return v.decode(bzrlib.user_encoding)
 
186
    
 
187
    try:
 
188
        return (open(os.path.join(config_dir(), "email"))
 
189
                .read()
 
190
                .decode(bzrlib.user_encoding)
 
191
                .rstrip("\r\n"))
 
192
    except IOError, e:
 
193
        if e.errno != errno.ENOENT:
 
194
            raise e
 
195
 
 
196
    v = os.environ.get('EMAIL')
 
197
    if v:
 
198
        return v.decode(bzrlib.user_encoding)
 
199
    else:    
 
200
        return None
 
201
 
 
202
 
 
203
def username():
 
204
    """Return email-style username.
 
205
 
 
206
    Something similar to 'Martin Pool <mbp@sourcefrog.net>'
 
207
 
 
208
    TODO: Check it's reasonably well-formed.
 
209
    """
 
210
    v = _get_user_id()
 
211
    if v:
 
212
        return v
 
213
    
 
214
    name, email = _auto_user_id()
 
215
    if name:
 
216
        return '%s <%s>' % (name, email)
 
217
    else:
 
218
        return email
 
219
 
 
220
 
 
221
_EMAIL_RE = re.compile(r'[\w+.-]+@[\w+.-]+')
152
222
def user_email():
153
223
    """Return just the email component of a username."""
154
 
    e = os.environ.get('BZREMAIL') or os.environ.get('EMAIL')
 
224
    e = _get_user_id()
155
225
    if e:
156
 
        import re
157
 
        m = re.search(r'[\w+.-]+@[\w+.-]+', e)
 
226
        m = _EMAIL_RE.search(e)
158
227
        if not m:
159
 
            bailout('%r is not a reasonable email address' % e)
 
228
            bailout("%r doesn't seem to contain a reasonable email address" % e)
160
229
        return m.group(0)
161
230
 
162
 
 
163
 
    import getpass, socket
164
 
    return '%s@%s' % (getpass.getuser(), socket.getfqdn())
165
 
 
 
231
    return _auto_user_id()[1]
166
232
    
167
233
 
168
234
 
169
235
def compare_files(a, b):
170
236
    """Returns true if equal in contents"""
171
237
    # 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:
 
238
    BUFSIZE = 4096
 
239
    while True:
 
240
        ai = a.read(BUFSIZE)
 
241
        bi = b.read(BUFSIZE)
 
242
        if ai != bi:
 
243
            return False
 
244
        if ai == '':
 
245
            return True
 
246
 
 
247
 
 
248
 
 
249
def local_time_offset(t=None):
 
250
    """Return offset of local zone from GMT, either at present or at time t."""
 
251
    # python2.3 localtime() can't take None
 
252
    if t == None:
 
253
        t = time.time()
 
254
        
 
255
    if time.localtime(t).tm_isdst and time.daylight:
179
256
        return -time.altzone
180
257
    else:
181
258
        return -time.timezone
184
261
def format_date(t, offset=0, timezone='original'):
185
262
    ## TODO: Perhaps a global option to use either universal or local time?
186
263
    ## Or perhaps just let people set $TZ?
187
 
    import time
188
 
    
189
264
    assert isinstance(t, float)
190
265
    
191
266
    if timezone == 'utc':
197
272
        tt = time.gmtime(t + offset)
198
273
    elif timezone == 'local':
199
274
        tt = time.localtime(t)
200
 
        offset = local_time_offset()
 
275
        offset = local_time_offset(t)
201
276
    else:
202
277
        bailout("unsupported timezone format %r",
203
278
                ['options are "utc", "original", "local"'])
244
319
    BzrError: ("sorry, '..' not allowed in path", [])
245
320
    """
246
321
    assert isinstance(p, types.StringTypes)
247
 
    ps = [f for f in p.split('/') if f != '.']
 
322
    ps = [f for f in p.split('/') if (f != '.' and f != '')]
248
323
    for f in ps:
249
324
        if f == '..':
250
325
            bailout("sorry, %r not allowed in path" % f)
253
328
def joinpath(p):
254
329
    assert isinstance(p, list)
255
330
    for f in p:
256
 
        if (f == '..') or (f is None) or (f == ''):
 
331
        if (f == '..') or (f == None) or (f == ''):
257
332
            bailout("sorry, %r not allowed in path" % f)
258
333
    return '/'.join(p)
259
334