/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
183 by mbp at sourcefrog
pychecker fixups
19
import os, types, re, time
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
1 by mbp at sourcefrog
import from baz patch-364
24
25
def make_readonly(filename):
26
    """Make a filename read-only."""
27
    # TODO: probably needs to be fixed for windows
28
    mod = os.stat(filename).st_mode
29
    mod = mod & 0777555
30
    os.chmod(filename, mod)
31
32
33
def make_writable(filename):
34
    mod = os.stat(filename).st_mode
35
    mod = mod | 0200
36
    os.chmod(filename, mod)
37
38
39
_QUOTE_RE = re.compile(r'([^a-zA-Z0-9.,:/_~-])')
40
def quotefn(f):
41
    """Return shell-quoted filename"""
42
    ## We could be a bit more terse by using double-quotes etc
43
    f = _QUOTE_RE.sub(r'\\\1', f)
44
    if f[0] == '~':
45
        f[0:1] = r'\~' 
46
    return f
47
48
49
def file_kind(f):
50
    mode = os.lstat(f)[ST_MODE]
51
    if S_ISREG(mode):
52
        return 'file'
53
    elif S_ISDIR(mode):
54
        return 'directory'
20 by mbp at sourcefrog
don't abort on trees that happen to contain symlinks
55
    elif S_ISLNK(mode):
56
        return 'symlink'
1 by mbp at sourcefrog
import from baz patch-364
57
    else:
183 by mbp at sourcefrog
pychecker fixups
58
        raise BzrError("can't handle file kind with mode %o of %r" % (mode, f)) 
1 by mbp at sourcefrog
import from baz patch-364
59
60
61
62
def isdir(f):
63
    """True if f is an accessible directory."""
64
    try:
65
        return S_ISDIR(os.lstat(f)[ST_MODE])
66
    except OSError:
67
        return False
68
69
70
71
def isfile(f):
72
    """True if f is a regular file."""
73
    try:
74
        return S_ISREG(os.lstat(f)[ST_MODE])
75
    except OSError:
76
        return False
77
78
79
def pumpfile(fromfile, tofile):
80
    """Copy contents of one file to another."""
81
    tofile.write(fromfile.read())
82
83
84
def uuid():
85
    """Return a new UUID"""
86
    
87
    ## XXX: Could alternatively read /proc/sys/kernel/random/uuid on
88
    ## Linux, but we need something portable for other systems;
89
    ## preferably an implementation in Python.
63 by mbp at sourcefrog
fix up uuid command
90
    try:
91
        return chomp(file('/proc/sys/kernel/random/uuid').readline())
92
    except IOError:
93
        return chomp(os.popen('uuidgen').readline())
94
1 by mbp at sourcefrog
import from baz patch-364
95
96
def chomp(s):
97
    if s and (s[-1] == '\n'):
98
        return s[:-1]
99
    else:
100
        return s
101
102
103
def sha_file(f):
104
    import sha
105
    ## TODO: Maybe read in chunks to handle big files
106
    if hasattr(f, 'tell'):
107
        assert f.tell() == 0
108
    s = sha.new()
109
    s.update(f.read())
110
    return s.hexdigest()
111
112
113
def sha_string(f):
114
    import sha
115
    s = sha.new()
116
    s.update(f)
117
    return s.hexdigest()
118
119
120
124 by mbp at sourcefrog
- check file text for past revisions is correct
121
def fingerprint_file(f):
122
    import sha
123
    s = sha.new()
126 by mbp at sourcefrog
Use just one big read to fingerprint files
124
    b = f.read()
125
    s.update(b)
126
    size = len(b)
124 by mbp at sourcefrog
- check file text for past revisions is correct
127
    return {'size': size,
128
            'sha1': s.hexdigest()}
129
130
131
1 by mbp at sourcefrog
import from baz patch-364
132
def username():
133
    """Return email-style username.
134
135
    Something similar to 'Martin Pool <mbp@sourcefrog.net>'
136
137
    :todo: Check it's reasonably well-formed.
138
139
    :todo: Allow taking it from a dotfile to help people on windows
140
           who can't easily set variables.
141
142
    :todo: Cope without pwd module, which is only on unix. 
143
    """
144
    e = os.environ.get('BZREMAIL') or os.environ.get('EMAIL')
145
    if e: return e
146
147
    import socket
148
    
149
    try:
150
        import pwd
151
        uid = os.getuid()
152
        w = pwd.getpwuid(uid)
25 by Martin Pool
cope when gecos field doesn't have a comma
153
        gecos = w.pw_gecos
154
        comma = gecos.find(',')
155
        if comma == -1:
156
            realname = gecos
157
        else:
158
            realname = gecos[:comma]
1 by mbp at sourcefrog
import from baz patch-364
159
        return '%s <%s@%s>' % (realname, w.pw_name, socket.getfqdn())
160
    except ImportError:
161
        pass
162
163
    import getpass, socket
164
    return '<%s@%s>' % (getpass.getuser(), socket.getfqdn())
165
166
183 by mbp at sourcefrog
pychecker fixups
167
_EMAIL_RE = re.compile(r'[\w+.-]+@[\w+.-]+')
1 by mbp at sourcefrog
import from baz patch-364
168
def user_email():
169
    """Return just the email component of a username."""
170
    e = os.environ.get('BZREMAIL') or os.environ.get('EMAIL')
171
    if e:
183 by mbp at sourcefrog
pychecker fixups
172
        m = _EMAIL_RE.search(e)
1 by mbp at sourcefrog
import from baz patch-364
173
        if not m:
174
            bailout('%r is not a reasonable email address' % e)
175
        return m.group(0)
176
177
178
    import getpass, socket
179
    return '%s@%s' % (getpass.getuser(), socket.getfqdn())
180
181
    
182
183
184
def compare_files(a, b):
185
    """Returns true if equal in contents"""
186
    # 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
187
    BUFSIZE = 4096
188
    while True:
189
        ai = a.read(BUFSIZE)
190
        bi = b.read(BUFSIZE)
191
        if ai != bi:
192
            return False
193
        if ai == '':
194
            return True
1 by mbp at sourcefrog
import from baz patch-364
195
196
197
49 by mbp at sourcefrog
fix local-time-offset calculation
198
def local_time_offset(t=None):
199
    """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
200
    # python2.3 localtime() can't take None
183 by mbp at sourcefrog
pychecker fixups
201
    if t == None:
73 by mbp at sourcefrog
fix time.localtime call for python 2.3
202
        t = time.time()
203
        
49 by mbp at sourcefrog
fix local-time-offset calculation
204
    if time.localtime(t).tm_isdst and time.daylight:
8 by mbp at sourcefrog
store committer's timezone in revision and show
205
        return -time.altzone
206
    else:
207
        return -time.timezone
208
209
    
210
def format_date(t, offset=0, timezone='original'):
1 by mbp at sourcefrog
import from baz patch-364
211
    ## TODO: Perhaps a global option to use either universal or local time?
212
    ## Or perhaps just let people set $TZ?
213
    assert isinstance(t, float)
214
    
8 by mbp at sourcefrog
store committer's timezone in revision and show
215
    if timezone == 'utc':
1 by mbp at sourcefrog
import from baz patch-364
216
        tt = time.gmtime(t)
217
        offset = 0
8 by mbp at sourcefrog
store committer's timezone in revision and show
218
    elif timezone == 'original':
23 by mbp at sourcefrog
format_date: handle revisions with no timezone offset
219
        if offset == None:
220
            offset = 0
16 by mbp at sourcefrog
fix inverted calculation for original timezone -> utc
221
        tt = time.gmtime(t + offset)
12 by mbp at sourcefrog
new --timezone option for bzr log
222
    elif timezone == 'local':
1 by mbp at sourcefrog
import from baz patch-364
223
        tt = time.localtime(t)
49 by mbp at sourcefrog
fix local-time-offset calculation
224
        offset = local_time_offset(t)
12 by mbp at sourcefrog
new --timezone option for bzr log
225
    else:
226
        bailout("unsupported timezone format %r",
227
                ['options are "utc", "original", "local"'])
8 by mbp at sourcefrog
store committer's timezone in revision and show
228
1 by mbp at sourcefrog
import from baz patch-364
229
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
8 by mbp at sourcefrog
store committer's timezone in revision and show
230
            + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
1 by mbp at sourcefrog
import from baz patch-364
231
232
233
def compact_date(when):
234
    return time.strftime('%Y%m%d%H%M%S', time.gmtime(when))
235
    
236
237
238
def filesize(f):
239
    """Return size of given open file."""
240
    return os.fstat(f.fileno())[ST_SIZE]
241
242
243
if hasattr(os, 'urandom'): # python 2.4 and later
244
    rand_bytes = os.urandom
245
else:
246
    # FIXME: No good on non-Linux
247
    _rand_file = file('/dev/urandom', 'rb')
248
    rand_bytes = _rand_file.read
249
250
251
## TODO: We could later have path objects that remember their list
252
## decomposition (might be too tricksy though.)
253
254
def splitpath(p):
255
    """Turn string into list of parts.
256
257
    >>> splitpath('a')
258
    ['a']
259
    >>> splitpath('a/b')
260
    ['a', 'b']
261
    >>> splitpath('a/./b')
262
    ['a', 'b']
263
    >>> splitpath('a/.b')
264
    ['a', '.b']
265
    >>> splitpath('a/../b')
184 by mbp at sourcefrog
pychecker fixups
266
    Traceback (most recent call last):
1 by mbp at sourcefrog
import from baz patch-364
267
    ...
268
    BzrError: ("sorry, '..' not allowed in path", [])
269
    """
270
    assert isinstance(p, types.StringTypes)
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
271
    ps = [f for f in p.split('/') if (f != '.' and f != '')]
1 by mbp at sourcefrog
import from baz patch-364
272
    for f in ps:
273
        if f == '..':
274
            bailout("sorry, %r not allowed in path" % f)
275
    return ps
276
277
def joinpath(p):
278
    assert isinstance(p, list)
279
    for f in p:
183 by mbp at sourcefrog
pychecker fixups
280
        if (f == '..') or (f == None) or (f == ''):
1 by mbp at sourcefrog
import from baz patch-364
281
            bailout("sorry, %r not allowed in path" % f)
282
    return '/'.join(p)
283
284
285
def appendpath(p1, p2):
286
    if p1 == '':
287
        return p2
288
    else:
289
        return p1 + '/' + p2
290
    
291
292
def extern_command(cmd, ignore_errors = False):
293
    mutter('external command: %s' % `cmd`)
294
    if os.system(cmd):
295
        if not ignore_errors:
296
            bailout('command failed')
297