1
# Copyright (C) 2006-2011 Canonical Ltd
1
# Copyright (C) 2006-2010 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
347
346
This is a UI centric function: it uses the bzrlib.ui.ui_factory to
348
347
prompt for input if a lock is detected and there is any doubt about
349
348
it possibly being still active.
351
:returns: LockResult for the broken lock.
353
350
self._check_not_locked()
355
holder_info = self.peek()
356
except LockCorrupt, e:
357
# The lock info is corrupt.
358
if bzrlib.ui.ui_factory.get_boolean("Break (corrupt %r)" % (self,)):
359
self.force_break_corrupt(e.file_data)
351
holder_info = self.peek()
361
352
if holder_info is not None:
362
353
lock_info = '\n'.join(self._format_lock_info(holder_info))
363
if bzrlib.ui.ui_factory.confirm_action(
364
"Break %(lock_info)s", 'bzrlib.lockdir.break',
365
dict(lock_info=lock_info)):
366
result = self.force_break(holder_info)
367
bzrlib.ui.ui_factory.show_message(
368
"Broke lock %s" % result.lock_url)
354
if bzrlib.ui.ui_factory.get_boolean("Break %s" % lock_info):
355
self.force_break(holder_info)
370
357
def force_break(self, dead_holder_info):
371
358
"""Release a lock held by another process.
382
369
After the lock is broken it will not be held by any process.
383
370
It is possible that another process may sneak in and take the
384
371
lock before the breaking process acquires it.
386
:returns: LockResult for the broken lock.
388
373
if not isinstance(dead_holder_info, dict):
389
374
raise ValueError("dead_holder_info: %r" % dead_holder_info)
409
394
current_info.get('nonce'))
410
395
for hook in self.hooks['lock_broken']:
414
def force_break_corrupt(self, corrupt_info_lines):
415
"""Release a lock that has been corrupted.
417
This is very similar to force_break, it except it doesn't assume that
418
self.peek() can work.
420
:param corrupt_info_lines: the lines of the corrupted info file, used
421
to check that the lock hasn't changed between reading the (corrupt)
422
info file and calling force_break_corrupt.
424
# XXX: this copes with unparseable info files, but what about missing
425
# info files? Or missing lock dirs?
426
self._check_not_locked()
427
tmpname = '%s/broken.%s.tmp' % (self.path, rand_chars(20))
428
self.transport.rename(self._held_dir, tmpname)
429
# check that we actually broke the right lock, not someone else;
430
# there's a small race window between checking it and doing the
432
broken_info_path = tmpname + self.__INFO_NAME
433
broken_content = self.transport.get_bytes(broken_info_path)
434
broken_lines = osutils.split_lines(broken_content)
435
if broken_lines != corrupt_info_lines:
436
raise LockBreakMismatch(self, broken_lines, corrupt_info_lines)
437
self.transport.delete(broken_info_path)
438
self.transport.rmdir(tmpname)
439
result = lock.LockResult(self.transport.abspath(self.path))
440
for hook in self.hooks['lock_broken']:
443
398
def _check_not_locked(self):
444
399
"""If the lock is held by this instance, raise an error."""
504
459
return s.to_string()
506
461
def _parse_info(self, info_bytes):
507
lines = osutils.split_lines(info_bytes)
509
stanza = rio.read_stanza(lines)
510
except ValueError, e:
511
mutter('Corrupt lock info file: %r', lines)
512
raise LockCorrupt("could not parse lock info file: " + str(e),
462
stanza = rio.read_stanza(osutils.split_lines(info_bytes))
514
463
if stanza is None:
515
464
# see bug 185013; we fairly often end up with the info file being
516
465
# empty after an interruption; we could log a message here but
537
486
hook(hook_result)
540
def lock_url_for_display(self):
541
"""Give a nicely-printable representation of the URL of this lock."""
542
# As local lock urls are correct we display them.
543
# We avoid displaying remote lock urls.
544
lock_url = self.transport.abspath(self.path)
545
if lock_url.startswith('file://'):
546
lock_url = lock_url.split('.bzr/')[0]
551
489
def wait_lock(self, timeout=None, poll=None, max_attempts=None):
552
490
"""Wait a certain period for a lock.
602
539
if deadline_str is None:
603
540
deadline_str = time.strftime('%H:%M:%S',
604
541
time.localtime(deadline))
542
# As local lock urls are correct we display them.
543
# We avoid displaying remote lock urls.
544
lock_url = self.transport.abspath(self.path)
545
if lock_url.startswith('file://'):
546
lock_url = lock_url.split('.bzr/')[0]
605
549
user, hostname, pid, time_ago = formatted_info
606
550
msg = ('%s lock %s ' # lock_url
607
551
'held by ' # start