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
19
import os, types, re, time, errno
20
from stat import S_ISREG, S_ISDIR, S_ISLNK, ST_MODE, ST_SIZE
19
import os, types, re, time, types
20
from stat import S_ISREG, S_ISDIR, ST_MODE, ST_SIZE
22
from errors import bailout, BzrError
23
from trace import mutter
22
from errors import bailout
26
24
def make_readonly(filename):
27
25
"""Make a filename read-only."""
86
82
"""Return a new UUID"""
88
return file('/proc/sys/kernel/random/uuid').readline().rstrip('\n')
90
return chomp(os.popen('uuidgen').readline())
84
## XXX: Could alternatively read /proc/sys/kernel/random/uuid on
85
## Linux, but we need something portable for other systems;
86
## preferably an implementation in Python.
87
bailout('uuids not allowed!')
88
return chomp(os.popen('uuidgen').readline())
91
if s and (s[-1] == '\n'):
99
## TODO: Maybe read in chunks to handle big files
95
100
if hasattr(f, 'tell'):
96
101
assert f.tell() == 0
104
104
return s.hexdigest()
115
def fingerprint_file(f):
121
return {'size': size,
122
'sha1': s.hexdigest()}
126
"""Return per-user configuration directory.
128
By default this is ~/.bzr.conf/
130
TODO: Global option --config-dir to override this.
132
return os.path.expanduser("~/.bzr.conf")
136
"""Calculate automatic user identification.
138
Returns (realname, email).
140
Only used when none is set in the environment or the id file.
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
116
"""Return email-style username.
118
Something similar to 'Martin Pool <mbp@sourcefrog.net>'
120
:todo: Check it's reasonably well-formed.
122
:todo: Allow taking it from a dotfile to help people on windows
123
who can't easily set variables.
125
:todo: Cope without pwd module, which is only on unix.
127
e = os.environ.get('BZREMAIL') or os.environ.get('EMAIL')
148
# XXX: Any good way to get real user name on win32?
152
134
uid = os.getuid()
153
135
w = pwd.getpwuid(uid)
154
gecos = w.pw_gecos.decode(bzrlib.user_encoding)
155
username = w.pw_name.decode(bzrlib.user_encoding)
156
comma = gecos.find(',')
160
realname = gecos[:comma]
136
realname, junk = w.pw_gecos.split(',', 1)
137
return '%s <%s@%s>' % (realname, w.pw_name, socket.getfqdn())
164
138
except ImportError:
166
realname = username = getpass.getuser().decode(bzrlib.user_encoding)
168
return realname, (username + '@' + socket.gethostname())
172
"""Return the full user id from a file or environment variable.
174
TODO: Allow taking this from a file in the branch directory too
175
for per-branch ids."""
176
v = os.environ.get('BZREMAIL')
178
return v.decode(bzrlib.user_encoding)
181
return (open(os.path.join(config_dir(), "email"))
183
.decode(bzrlib.user_encoding)
186
if e.errno != errno.ENOENT:
189
v = os.environ.get('EMAIL')
191
return v.decode(bzrlib.user_encoding)
197
"""Return email-style username.
199
Something similar to 'Martin Pool <mbp@sourcefrog.net>'
201
TODO: Check it's reasonably well-formed.
207
name, email = _auto_user_id()
209
return '%s <%s>' % (name, email)
214
_EMAIL_RE = re.compile(r'[\w+.-]+@[\w+.-]+')
141
import getpass, socket
142
return '<%s@%s>' % (getpass.getuser(), socket.getfqdn())
215
145
def user_email():
216
146
"""Return just the email component of a username."""
147
e = os.environ.get('BZREMAIL') or os.environ.get('EMAIL')
219
m = _EMAIL_RE.search(e)
150
m = re.search(r'[\w+.-]+@[\w+.-]+', e)
221
bailout("%r doesn't seem to contain a reasonable email address" % e)
152
bailout('%r is not a reasonable email address' % e)
222
153
return m.group(0)
224
return _auto_user_id()[1]
156
import getpass, socket
157
return '%s@%s' % (getpass.getuser(), socket.getfqdn())
228
162
def compare_files(a, b):
229
163
"""Returns true if equal in contents"""
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
247
if time.localtime(t).tm_isdst and time.daylight:
164
# TODO: don't read the whole thing in one go.
165
result = a.read() == b.read()
170
def local_time_offset():
248
172
return -time.altzone
250
174
return -time.timezone
253
177
def format_date(t, offset=0, timezone='original'):
254
178
## TODO: Perhaps a global option to use either universal or local time?
255
179
## Or perhaps just let people set $TZ?
256
182
assert isinstance(t, float)
258
184
if timezone == 'utc':
259
185
tt = time.gmtime(t)
261
187
elif timezone == 'original':
264
tt = time.gmtime(t + offset)
265
elif timezone == 'local':
188
tt = time.gmtime(t - offset)
190
assert timezone == 'local'
266
191
tt = time.localtime(t)
267
offset = local_time_offset(t)
269
bailout("unsupported timezone format %r",
270
['options are "utc", "original", "local"'])
192
offset = local_time_offset()
272
194
return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
273
195
+ ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
311
233
BzrError: ("sorry, '..' not allowed in path", [])
313
235
assert isinstance(p, types.StringTypes)
315
# split on either delimiter because people might use either on
317
ps = re.split(r'[\\/]', p)
236
ps = [f for f in p.split('/') if f != '.']
322
239
bailout("sorry, %r not allowed in path" % f)
323
elif (f == '.') or (f == ''):
330
243
assert isinstance(p, list)
332
if (f == '..') or (f == None) or (f == ''):
245
if (f == '..') or (f is None) or (f == ''):
333
246
bailout("sorry, %r not allowed in path" % f)
334
return os.path.join(*p)
337
250
def appendpath(p1, p2):
341
return os.path.join(p1, p2)
344
257
def extern_command(cmd, ignore_errors = False):