/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1 by mbp at sourcefrog
import from baz patch-364
1
# Bazaar-NG -- distributed version control
2
3
# Copyright (C) 2005 by Canonical Ltd
4
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
19
import os, types, re, time, errno
20 by mbp at sourcefrog
don't abort on trees that happen to contain symlinks
20
from stat import S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE
1 by mbp at sourcefrog
import from baz patch-364
21
183 by mbp at sourcefrog
pychecker fixups
22
from errors import bailout, BzrError
23
from trace import mutter
251 by mbp at sourcefrog
- factor out locale.getpreferredencoding()
24
import bzrlib
1 by mbp at sourcefrog
import from baz patch-364
25
26
def make_readonly(filename):
27
    """Make a filename read-only."""
28
    # TODO: probably needs to be fixed for windows
29
    mod = os.stat(filename).st_mode
30
    mod = mod & 0777555
31
    os.chmod(filename, mod)
32
33
34
def make_writable(filename):
35
    mod = os.stat(filename).st_mode
36
    mod = mod | 0200
37
    os.chmod(filename, mod)
38
39
40
_QUOTE_RE = re.compile(r'([^a-zA-Z0-9.,:/_~-])')
41
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
48
49
50
def file_kind(f):
51
    mode = os.lstat(f)[ST_MODE]
52
    if S_ISREG(mode):
53
        return 'file'
54
    elif S_ISDIR(mode):
55
        return 'directory'
20 by mbp at sourcefrog
don't abort on trees that happen to contain symlinks
56
    elif S_ISLNK(mode):
57
        return 'symlink'
1 by mbp at sourcefrog
import from baz patch-364
58
    else:
183 by mbp at sourcefrog
pychecker fixups
59
        raise BzrError("can't handle file kind with mode %o of %r" % (mode, f)) 
1 by mbp at sourcefrog
import from baz patch-364
60
61
62
63
def isdir(f):
64
    """True if f is an accessible directory."""
65
    try:
66
        return S_ISDIR(os.lstat(f)[ST_MODE])
67
    except OSError:
68
        return False
69
70
71
72
def isfile(f):
73
    """True if f is a regular file."""
74
    try:
75
        return S_ISREG(os.lstat(f)[ST_MODE])
76
    except OSError:
77
        return False
78
79
80
def pumpfile(fromfile, tofile):
81
    """Copy contents of one file to another."""
82
    tofile.write(fromfile.read())
83
84
85
def uuid():
86
    """Return a new UUID"""
87
    
88
    ## XXX: Could alternatively read /proc/sys/kernel/random/uuid on
89
    ## Linux, but we need something portable for other systems;
90
    ## preferably an implementation in Python.
63 by mbp at sourcefrog
fix up uuid command
91
    try:
92
        return chomp(file('/proc/sys/kernel/random/uuid').readline())
93
    except IOError:
94
        return chomp(os.popen('uuidgen').readline())
95
1 by mbp at sourcefrog
import from baz patch-364
96
97
def chomp(s):
98
    if s and (s[-1] == '\n'):
99
        return s[:-1]
100
    else:
101
        return s
102
103
104
def sha_file(f):
105
    import sha
106
    ## TODO: Maybe read in chunks to handle big files
107
    if hasattr(f, 'tell'):
108
        assert f.tell() == 0
109
    s = sha.new()
110
    s.update(f.read())
111
    return s.hexdigest()
112
113
114
def sha_string(f):
115
    import sha
116
    s = sha.new()
117
    s.update(f)
118
    return s.hexdigest()
119
120
121
124 by mbp at sourcefrog
- check file text for past revisions is correct
122
def fingerprint_file(f):
123
    import sha
124
    s = sha.new()
126 by mbp at sourcefrog
Use just one big read to fingerprint files
125
    b = f.read()
126
    s.update(b)
127
    size = len(b)
124 by mbp at sourcefrog
- check file text for past revisions is correct
128
    return {'size': size,
129
            'sha1': s.hexdigest()}
130
131
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
132
def _auto_user_id():
246 by mbp at sourcefrog
- unicode decoding in getting email and userid strings
133
    """Calculate automatic user identification.
134
135
    Returns (realname, email).
136
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
137
    Only used when none is set in the environment or the id file.
246 by mbp at sourcefrog
- unicode decoding in getting email and userid strings
138
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
139
    This previously used the FQDN as the default domain, but that can
140
    be very slow on machines where DNS is broken.  So now we simply
141
    use the hostname.
1 by mbp at sourcefrog
import from baz patch-364
142
    """
251 by mbp at sourcefrog
- factor out locale.getpreferredencoding()
143
    import socket
246 by mbp at sourcefrog
- unicode decoding in getting email and userid strings
144
145
    # XXX: Any good way to get real user name on win32?
146
1 by mbp at sourcefrog
import from baz patch-364
147
    try:
148
        import pwd
149
        uid = os.getuid()
150
        w = pwd.getpwuid(uid)
251 by mbp at sourcefrog
- factor out locale.getpreferredencoding()
151
        gecos = w.pw_gecos.decode(bzrlib.user_encoding)
152
        username = w.pw_name.decode(bzrlib.user_encoding)
25 by Martin Pool
cope when gecos field doesn't have a comma
153
        comma = gecos.find(',')
154
        if comma == -1:
155
            realname = gecos
156
        else:
157
            realname = gecos[:comma]
256 by Martin Pool
- More handling of auto-username case
158
        if not realname:
159
            realname = username
246 by mbp at sourcefrog
- unicode decoding in getting email and userid strings
160
1 by mbp at sourcefrog
import from baz patch-364
161
    except ImportError:
246 by mbp at sourcefrog
- unicode decoding in getting email and userid strings
162
        import getpass
256 by Martin Pool
- More handling of auto-username case
163
        realname = username = getpass.getuser().decode(bzrlib.user_encoding)
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
164
256 by Martin Pool
- More handling of auto-username case
165
    return realname, (username + '@' + socket.gethostname())
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
166
167
168
def _get_user_id():
169
    v = os.environ.get('BZREMAIL')
170
    if v:
171
        return v.decode(bzrlib.user_encoding)
172
    
173
    try:
174
        return (open(os.path.expanduser("~/.bzr.email"))
175
                .read()
176
                .decode(bzrlib.user_encoding)
177
                .rstrip("\r\n"))
256 by Martin Pool
- More handling of auto-username case
178
    except IOError, e:
179
        if e.errno != errno.ENOENT:
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
180
            raise e
181
182
    v = os.environ.get('EMAIL')
183
    if v:
184
        return v.decode(bzrlib.user_encoding)
185
    else:    
186
        return None
246 by mbp at sourcefrog
- unicode decoding in getting email and userid strings
187
188
189
def username():
190
    """Return email-style username.
191
192
    Something similar to 'Martin Pool <mbp@sourcefrog.net>'
193
254 by Martin Pool
- Doc cleanups from Magnus Therning
194
    TODO: Check it's reasonably well-formed.
246 by mbp at sourcefrog
- unicode decoding in getting email and userid strings
195
254 by Martin Pool
- Doc cleanups from Magnus Therning
196
    TODO: Allow taking it from a dotfile to help people on windows
246 by mbp at sourcefrog
- unicode decoding in getting email and userid strings
197
           who can't easily set variables.
198
    """
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
199
    v = _get_user_id()
200
    if v:
201
        return v
202
    
203
    name, email = _auto_user_id()
246 by mbp at sourcefrog
- unicode decoding in getting email and userid strings
204
    if name:
205
        return '%s <%s>' % (name, email)
206
    else:
207
        return email
1 by mbp at sourcefrog
import from baz patch-364
208
209
183 by mbp at sourcefrog
pychecker fixups
210
_EMAIL_RE = re.compile(r'[\w+.-]+@[\w+.-]+')
1 by mbp at sourcefrog
import from baz patch-364
211
def user_email():
212
    """Return just the email component of a username."""
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
213
    e = _get_user_id()
1 by mbp at sourcefrog
import from baz patch-364
214
    if e:
183 by mbp at sourcefrog
pychecker fixups
215
        m = _EMAIL_RE.search(e)
1 by mbp at sourcefrog
import from baz patch-364
216
        if not m:
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
217
            bailout("%r doesn't seem to contain a reasonable email address" % e)
1 by mbp at sourcefrog
import from baz patch-364
218
        return m.group(0)
219
252 by Martin Pool
- Don't use host fqdn for default user name, because DNS tends
220
    return _auto_user_id()[1]
1 by mbp at sourcefrog
import from baz patch-364
221
    
222
223
224
def compare_files(a, b):
225
    """Returns true if equal in contents"""
226
    # TODO: don't read the whole thing in one go.
74 by mbp at sourcefrog
compare_files: read in one page at a time rather than
227
    BUFSIZE = 4096
228
    while True:
229
        ai = a.read(BUFSIZE)
230
        bi = b.read(BUFSIZE)
231
        if ai != bi:
232
            return False
233
        if ai == '':
234
            return True
1 by mbp at sourcefrog
import from baz patch-364
235
236
237
49 by mbp at sourcefrog
fix local-time-offset calculation
238
def local_time_offset(t=None):
239
    """Return offset of local zone from GMT, either at present or at time t."""
73 by mbp at sourcefrog
fix time.localtime call for python 2.3
240
    # python2.3 localtime() can't take None
183 by mbp at sourcefrog
pychecker fixups
241
    if t == None:
73 by mbp at sourcefrog
fix time.localtime call for python 2.3
242
        t = time.time()
243
        
49 by mbp at sourcefrog
fix local-time-offset calculation
244
    if time.localtime(t).tm_isdst and time.daylight:
8 by mbp at sourcefrog
store committer's timezone in revision and show
245
        return -time.altzone
246
    else:
247
        return -time.timezone
248
249
    
250
def format_date(t, offset=0, timezone='original'):
1 by mbp at sourcefrog
import from baz patch-364
251
    ## TODO: Perhaps a global option to use either universal or local time?
252
    ## Or perhaps just let people set $TZ?
253
    assert isinstance(t, float)
254
    
8 by mbp at sourcefrog
store committer's timezone in revision and show
255
    if timezone == 'utc':
1 by mbp at sourcefrog
import from baz patch-364
256
        tt = time.gmtime(t)
257
        offset = 0
8 by mbp at sourcefrog
store committer's timezone in revision and show
258
    elif timezone == 'original':
23 by mbp at sourcefrog
format_date: handle revisions with no timezone offset
259
        if offset == None:
260
            offset = 0
16 by mbp at sourcefrog
fix inverted calculation for original timezone -> utc
261
        tt = time.gmtime(t + offset)
12 by mbp at sourcefrog
new --timezone option for bzr log
262
    elif timezone == 'local':
1 by mbp at sourcefrog
import from baz patch-364
263
        tt = time.localtime(t)
49 by mbp at sourcefrog
fix local-time-offset calculation
264
        offset = local_time_offset(t)
12 by mbp at sourcefrog
new --timezone option for bzr log
265
    else:
266
        bailout("unsupported timezone format %r",
267
                ['options are "utc", "original", "local"'])
8 by mbp at sourcefrog
store committer's timezone in revision and show
268
1 by mbp at sourcefrog
import from baz patch-364
269
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
8 by mbp at sourcefrog
store committer's timezone in revision and show
270
            + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
1 by mbp at sourcefrog
import from baz patch-364
271
272
273
def compact_date(when):
274
    return time.strftime('%Y%m%d%H%M%S', time.gmtime(when))
275
    
276
277
278
def filesize(f):
279
    """Return size of given open file."""
280
    return os.fstat(f.fileno())[ST_SIZE]
281
282
283
if hasattr(os, 'urandom'): # python 2.4 and later
284
    rand_bytes = os.urandom
285
else:
286
    # FIXME: No good on non-Linux
287
    _rand_file = file('/dev/urandom', 'rb')
288
    rand_bytes = _rand_file.read
289
290
291
## TODO: We could later have path objects that remember their list
292
## decomposition (might be too tricksy though.)
293
294
def splitpath(p):
295
    """Turn string into list of parts.
296
297
    >>> splitpath('a')
298
    ['a']
299
    >>> splitpath('a/b')
300
    ['a', 'b']
301
    >>> splitpath('a/./b')
302
    ['a', 'b']
303
    >>> splitpath('a/.b')
304
    ['a', '.b']
305
    >>> splitpath('a/../b')
184 by mbp at sourcefrog
pychecker fixups
306
    Traceback (most recent call last):
1 by mbp at sourcefrog
import from baz patch-364
307
    ...
308
    BzrError: ("sorry, '..' not allowed in path", [])
309
    """
310
    assert isinstance(p, types.StringTypes)
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
311
    ps = [f for f in p.split('/') if (f != '.' and f != '')]
1 by mbp at sourcefrog
import from baz patch-364
312
    for f in ps:
313
        if f == '..':
314
            bailout("sorry, %r not allowed in path" % f)
315
    return ps
316
317
def joinpath(p):
318
    assert isinstance(p, list)
319
    for f in p:
183 by mbp at sourcefrog
pychecker fixups
320
        if (f == '..') or (f == None) or (f == ''):
1 by mbp at sourcefrog
import from baz patch-364
321
            bailout("sorry, %r not allowed in path" % f)
322
    return '/'.join(p)
323
324
325
def appendpath(p1, p2):
326
    if p1 == '':
327
        return p2
328
    else:
329
        return p1 + '/' + p2
330
    
331
332
def extern_command(cmd, ignore_errors = False):
333
    mutter('external command: %s' % `cmd`)
334
    if os.system(cmd):
335
        if not ignore_errors:
336
            bailout('command failed')
337