1
# Copyright (C) 2006-2010 Canonical Ltd
1
# Copyright (C) 2006, 2007, 2008 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
242
241
# incorrect. It's possible some other servers or filesystems will
243
242
# have a similar bug allowing someone to think they got the lock
244
243
# when it's already held.
246
# See <https://bugs.launchpad.net/bzr/+bug/498378> for one case.
248
# Strictly the check is unnecessary and a waste of time for most
249
# people, but probably worth trapping if something is wrong.
250
244
info = self.peek()
251
245
self._trace("after locking, info=%r", info)
253
raise LockFailed(self, "lock was renamed into place, but "
255
if info.get('nonce') != self.nonce:
246
if info['nonce'] != self.nonce:
256
247
self._trace("rename succeeded, "
257
248
"but lock is still held by someone else")
258
249
raise LockContention(self)
426
417
peek() reads the info file of the lock holder, if any.
428
return self._parse_info(self.transport.get_bytes(path))
419
return self._parse_info(self.transport.get(path))
431
422
"""Check if the lock is held by anyone.
433
If it is held, this returns the lock info structure as a dict
424
If it is held, this returns the lock info structure as a rio Stanza,
434
425
which contains some information about the current lock holder.
435
426
Otherwise returns None.
447
438
# XXX: is creating this here inefficient?
448
439
config = bzrlib.config.GlobalConfig()
441
user = config.user_email()
442
except errors.NoEmailInUsername:
450
443
user = config.username()
451
except errors.NoWhoami:
452
user = osutils.getuser_unicode()
453
444
s = rio.Stanza(hostname=get_host_name(),
454
445
pid=str(os.getpid()),
455
446
start_time=str(int(time.time())),
459
450
return s.to_string()
461
def _parse_info(self, info_bytes):
462
stanza = rio.read_stanza(osutils.split_lines(info_bytes))
464
# see bug 185013; we fairly often end up with the info file being
465
# empty after an interruption; we could log a message here but
466
# there may not be much we can say
469
return stanza.as_dict()
452
def _parse_info(self, info_file):
453
return rio.read_stanza(info_file.readlines()).as_dict()
471
455
def attempt_lock(self):
472
456
"""Take the lock; fail if it's already held.
539
523
if deadline_str is None:
540
524
deadline_str = time.strftime('%H:%M:%S',
541
525
time.localtime(deadline))
542
# As local lock urls are correct we display them.
543
# We avoid displaying remote lock urls.
544
526
lock_url = self.transport.abspath(self.path)
545
if lock_url.startswith('file://'):
546
lock_url = lock_url.split('.bzr/')[0]
549
user, hostname, pid, time_ago = formatted_info
550
msg = ('%s lock %s ' # lock_url
554
'[process #%s], ' # pid
555
'acquired %s.') # time ago
556
msg_args = [start, lock_url, user, hostname, pid, time_ago]
558
msg += ('\nWill continue to try until %s, unless '
560
msg_args.append(deadline_str)
561
msg += '\nSee "bzr help break-lock" for more.'
562
self._report_function(msg, *msg_args)
527
self._report_function('%s %s\n'
529
'%s\n' # locked ... ago
530
'Will continue to try until %s, unless '
532
'If you\'re sure that it\'s not being '
533
'modified, use bzr break-lock %s',
563
541
if (max_attempts is not None) and (attempt_count >= max_attempts):
564
542
self._trace("exceeded %d attempts")
565
543
raise LockContention(self)
567
545
self._trace("waiting %ss", poll)
570
# As timeout is always 0 for remote locks
571
# this block is applicable only for local
573
548
self._trace("timeout after waiting %ss", timeout)
574
raise LockContention('(local)', lock_url)
549
raise LockContention(self)
576
551
def leave_in_place(self):
577
552
self._locked_via_token = True
623
598
def _format_lock_info(self, info):
624
599
"""Turn the contents of peek() into something for the user"""
625
start_time = info.get('start_time')
626
if start_time is None:
627
time_ago = '(unknown)'
629
time_ago = format_delta(time.time() - int(info['start_time']))
630
user = info.get('user', '<unknown>')
631
hostname = info.get('hostname', '<unknown>')
632
pid = info.get('pid', '<unknown>')
600
lock_url = self.transport.abspath(self.path)
601
delta = time.time() - int(info['start_time'])
603
'lock %s' % (lock_url,),
604
'held by %(user)s on host %(hostname)s [process #%(pid)s]' % info,
605
'locked %s' % (format_delta(delta),),
640
608
def validate_token(self, token):