/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/lockdir.py

  • Committer: Martin Pool
  • Date: 2010-09-15 05:10:04 UTC
  • mto: (5452.4.1 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 5476.
  • Revision ID: mbp@sourcefrog.net-20100915051004-jfncw2tw716gfudb
Go back to using assertEqualDiff when a script fails

Show diffs side-by-side

added added

removed removed

Lines of Context:
120
120
        LockBreakMismatch,
121
121
        LockBroken,
122
122
        LockContention,
 
123
        LockCorrupt,
123
124
        LockFailed,
124
125
        LockNotHeld,
125
126
        NoSuchFile,
151
152
# files/dirs created.
152
153
 
153
154
 
154
 
_DEFAULT_TIMEOUT_SECONDS = 300
 
155
_DEFAULT_TIMEOUT_SECONDS = 30
155
156
_DEFAULT_POLL_SECONDS = 1.0
156
157
 
157
158
 
243
244
        # have a similar bug allowing someone to think they got the lock
244
245
        # when it's already held.
245
246
        #
246
 
        # See <https://bugs.edge.launchpad.net/bzr/+bug/498378> for one case.
 
247
        # See <https://bugs.launchpad.net/bzr/+bug/498378> for one case.
247
248
        #
248
249
        # Strictly the check is unnecessary and a waste of time for most
249
250
        # people, but probably worth trapping if something is wrong.
348
349
        it possibly being still active.
349
350
        """
350
351
        self._check_not_locked()
351
 
        holder_info = self.peek()
 
352
        try:
 
353
            holder_info = self.peek()
 
354
        except LockCorrupt, e:
 
355
            # The lock info is corrupt.
 
356
            if bzrlib.ui.ui_factory.get_boolean("Break (corrupt %r)" % (self,)):
 
357
                self.force_break_corrupt(e.file_data)
 
358
            return
352
359
        if holder_info is not None:
353
360
            lock_info = '\n'.join(self._format_lock_info(holder_info))
354
361
            if bzrlib.ui.ui_factory.get_boolean("Break %s" % lock_info):
395
402
        for hook in self.hooks['lock_broken']:
396
403
            hook(result)
397
404
 
 
405
    def force_break_corrupt(self, corrupt_info_lines):
 
406
        """Release a lock that has been corrupted.
 
407
        
 
408
        This is very similar to force_break, it except it doesn't assume that
 
409
        self.peek() can work.
 
410
        
 
411
        :param corrupt_info_lines: the lines of the corrupted info file, used
 
412
            to check that the lock hasn't changed between reading the (corrupt)
 
413
            info file and calling force_break_corrupt.
 
414
        """
 
415
        # XXX: this copes with unparseable info files, but what about missing
 
416
        # info files?  Or missing lock dirs?
 
417
        self._check_not_locked()
 
418
        tmpname = '%s/broken.%s.tmp' % (self.path, rand_chars(20))
 
419
        self.transport.rename(self._held_dir, tmpname)
 
420
        # check that we actually broke the right lock, not someone else;
 
421
        # there's a small race window between checking it and doing the
 
422
        # rename.
 
423
        broken_info_path = tmpname + self.__INFO_NAME
 
424
        f = self.transport.get(broken_info_path)
 
425
        broken_lines = f.readlines()
 
426
        if broken_lines != corrupt_info_lines:
 
427
            raise LockBreakMismatch(self, broken_lines, corrupt_info_lines)
 
428
        self.transport.delete(broken_info_path)
 
429
        self.transport.rmdir(tmpname)
 
430
        result = lock.LockResult(self.transport.abspath(self.path))
 
431
        for hook in self.hooks['lock_broken']:
 
432
            hook(result)
 
433
 
398
434
    def _check_not_locked(self):
399
435
        """If the lock is held by this instance, raise an error."""
400
436
        if self._lock_held:
447
483
        # XXX: is creating this here inefficient?
448
484
        config = bzrlib.config.GlobalConfig()
449
485
        try:
450
 
            user = config.user_email()
451
 
        except errors.NoEmailInUsername:
452
486
            user = config.username()
 
487
        except errors.NoWhoami:
 
488
            user = osutils.getuser_unicode()
453
489
        s = rio.Stanza(hostname=get_host_name(),
454
490
                   pid=str(os.getpid()),
455
491
                   start_time=str(int(time.time())),
459
495
        return s.to_string()
460
496
 
461
497
    def _parse_info(self, info_bytes):
462
 
        stanza = rio.read_stanza(osutils.split_lines(info_bytes))
 
498
        lines = osutils.split_lines(info_bytes)
 
499
        try:
 
500
            stanza = rio.read_stanza(lines)
 
501
        except ValueError, e:
 
502
            mutter('Corrupt lock info file: %r', lines)
 
503
            raise LockCorrupt("could not parse lock info file: " + str(e),
 
504
                              lines)
463
505
        if stanza is None:
464
506
            # see bug 185013; we fairly often end up with the info file being
465
507
            # empty after an interruption; we could log a message here but
539
581
                if deadline_str is None:
540
582
                    deadline_str = time.strftime('%H:%M:%S',
541
583
                                                 time.localtime(deadline))
 
584
                # As local lock urls are correct we display them.
 
585
                # We avoid displaying remote lock urls.
542
586
                lock_url = self.transport.abspath(self.path)
543
 
                # See <https://bugs.edge.launchpad.net/bzr/+bug/250451>
544
 
                # the URL here is sometimes not one that is useful to the
545
 
                # user, perhaps being wrapped in a lp-%d or chroot decorator,
546
 
                # especially if this error is issued from the server.
547
 
                self._report_function('%s %s\n'
548
 
                    '%s\n' # held by
549
 
                    '%s\n' # locked ... ago
550
 
                    'Will continue to try until %s, unless '
551
 
                    'you press Ctrl-C.\n'
552
 
                    'See "bzr help break-lock" for more.',
553
 
                    start,
554
 
                    formatted_info[0],
555
 
                    formatted_info[1],
556
 
                    formatted_info[2],
557
 
                    deadline_str,
558
 
                    )
559
 
 
 
587
                if lock_url.startswith('file://'):
 
588
                    lock_url = lock_url.split('.bzr/')[0]
 
589
                else:
 
590
                    lock_url = ''
 
591
                user, hostname, pid, time_ago = formatted_info
 
592
                msg = ('%s lock %s '        # lock_url
 
593
                    'held by '              # start
 
594
                    '%s\n'                  # user
 
595
                    'at %s '                # hostname
 
596
                    '[process #%s], '       # pid
 
597
                    'acquired %s.')         # time ago
 
598
                msg_args = [start, lock_url, user, hostname, pid, time_ago]
 
599
                if timeout > 0:
 
600
                    msg += ('\nWill continue to try until %s, unless '
 
601
                        'you press Ctrl-C.')
 
602
                    msg_args.append(deadline_str)
 
603
                msg += '\nSee "bzr help break-lock" for more.'
 
604
                self._report_function(msg, *msg_args)
560
605
            if (max_attempts is not None) and (attempt_count >= max_attempts):
561
606
                self._trace("exceeded %d attempts")
562
607
                raise LockContention(self)
564
609
                self._trace("waiting %ss", poll)
565
610
                time.sleep(poll)
566
611
            else:
 
612
                # As timeout is always 0 for remote locks
 
613
                # this block is applicable only for local
 
614
                # lock contention
567
615
                self._trace("timeout after waiting %ss", timeout)
568
 
                raise LockContention(self)
 
616
                raise LockContention('(local)', lock_url)
569
617
 
570
618
    def leave_in_place(self):
571
619
        self._locked_via_token = True
616
664
 
617
665
    def _format_lock_info(self, info):
618
666
        """Turn the contents of peek() into something for the user"""
619
 
        lock_url = self.transport.abspath(self.path)
620
667
        start_time = info.get('start_time')
621
668
        if start_time is None:
622
669
            time_ago = '(unknown)'
623
670
        else:
624
671
            time_ago = format_delta(time.time() - int(info['start_time']))
 
672
        user = info.get('user', '<unknown>')
 
673
        hostname = info.get('hostname', '<unknown>')
 
674
        pid = info.get('pid', '<unknown>')
625
675
        return [
626
 
            'lock %s' % (lock_url,),
627
 
            'held by %s on host %s [process #%s]' %
628
 
                tuple([info.get(x, '<unknown>') for x in ['user', 'hostname', 'pid']]),
629
 
            'locked %s' % (time_ago,),
 
676
            user,
 
677
            hostname,
 
678
            pid,
 
679
            time_ago,
630
680
            ]
631
681
 
632
682
    def validate_token(self, token):