/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 breezy/lockdir.py

  • Committer: Jelmer Vernooij
  • Date: 2020-05-06 02:13:25 UTC
  • mfrom: (7490.7.21 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200506021325-awbmmqu1zyorz7sj
Merge 3.1 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
98
98
but helps protect against colliding host names.
99
99
"""
100
100
 
101
 
from __future__ import absolute_import
102
 
 
103
101
 
104
102
# TODO: We sometimes have the problem that our attempt to rename '1234' to
105
103
# 'held' fails because the transport server moves into an existing directory,
124
122
    )
125
123
from .decorators import only_raises
126
124
from .errors import (
127
 
        DirectoryNotEmpty,
128
 
        FileExists,
129
 
        LockBreakMismatch,
130
 
        LockBroken,
131
 
        LockContention,
132
 
        LockCorrupt,
133
 
        LockFailed,
134
 
        LockNotHeld,
135
 
        NoSuchFile,
136
 
        PathError,
137
 
        ResourceBusy,
138
 
        TransportError,
139
 
        )
 
125
    DirectoryNotEmpty,
 
126
    FileExists,
 
127
    LockBreakMismatch,
 
128
    LockBroken,
 
129
    LockContention,
 
130
    LockCorrupt,
 
131
    LockFailed,
 
132
    LockNotHeld,
 
133
    NoSuchFile,
 
134
    PathError,
 
135
    ResourceBusy,
 
136
    TransportError,
 
137
    )
140
138
from .i18n import gettext
141
139
from .osutils import format_delta, rand_chars, get_host_name
142
 
from .sixish import (
143
 
    PY3,
144
 
    text_type,
145
 
    )
146
140
from .trace import mutter, note
147
141
 
148
142
 
171
165
 
172
166
    __INFO_NAME = '/info'
173
167
 
174
 
    def __init__(self, transport, path, file_modebits=0o644, dir_modebits=0o755,
175
 
        extra_holder_info=None):
 
168
    def __init__(self, transport, path, file_modebits=0o644,
 
169
                 dir_modebits=0o755, extra_holder_info=None):
176
170
        """Create a new LockDir object.
177
171
 
178
172
        The LockDir is initially unlocked - this just creates the object.
251
245
                self._trace("other holder is %r" % other_holder)
252
246
                try:
253
247
                    self._handle_lock_contention(other_holder)
254
 
                except:
 
248
                except BaseException:
255
249
                    self._remove_pending_dir(tmpname)
256
250
                    raise
257
251
            except Exception as e:
273
267
        self._trace("after locking, info=%r", info)
274
268
        if info is None:
275
269
            raise LockFailed(self, "lock was renamed into place, but "
276
 
                "now is missing!")
 
270
                             "now is missing!")
277
271
        if info.get('nonce') != self.nonce:
278
272
            self._trace("rename succeeded, "
279
 
                "but lock is still held by someone else")
 
273
                        "but lock is still held by someone else")
280
274
            raise LockContention(self)
281
275
        self._lock_held = True
282
276
        self._trace("... lock succeeded after %dms",
283
 
                (time.time() - start_time) * 1000)
 
277
                    (time.time() - start_time) * 1000)
284
278
        return self.nonce
285
279
 
286
280
    def _handle_lock_contention(self, other_holder):
302
296
                    ui.ui_factory.show_user_warning(
303
297
                        'locks_steal_dead',
304
298
                        lock_url=urlutils.join(self.transport.base, self.path),
305
 
                        other_holder_info=text_type(other_holder))
 
299
                        other_holder_info=str(other_holder))
306
300
                    self.force_break(other_holder)
307
301
                    self._trace("stole lock from dead holder")
308
302
                    return
340
334
        # We'll rename the whole directory into place to get atomic
341
335
        # properties
342
336
        self.transport.put_bytes_non_atomic(tmpname + self.__INFO_NAME,
343
 
            info.to_bytes())
 
337
                                            info.to_bytes())
344
338
        return tmpname
345
339
 
346
340
    @only_raises(LockNotHeld, LockBroken)
369
363
            self.transport.delete(tmpname + self.__INFO_NAME)
370
364
            try:
371
365
                self.transport.rmdir(tmpname)
372
 
            except DirectoryNotEmpty as e:
 
366
            except DirectoryNotEmpty:
373
367
                # There might have been junk left over by a rename that moved
374
368
                # another locker within the 'held' directory.  do a slower
375
369
                # deletion where we list the directory and remove everything
376
370
                # within it.
377
 
                #
378
 
                # Maybe this should be broader to allow for ftp servers with
379
 
                # non-specific error messages?
380
371
                self._trace("doing recursive deletion of non-empty directory "
381
 
                        "%s", tmpname)
 
372
                            "%s", tmpname)
382
373
                self.transport.delete_tree(tmpname)
383
374
            self._trace("... unlock succeeded after %dms",
384
 
                    (time.time() - start_time) * 1000)
 
375
                        (time.time() - start_time) * 1000)
385
376
            result = lock.LockResult(self.transport.abspath(self.path),
386
377
                                     old_nonce)
387
378
            for hook in self.hooks['lock_released']:
409
400
            if ui.ui_factory.confirm_action(
410
401
                u"Break %(lock_info)s",
411
402
                'breezy.lockdir.break',
412
 
                dict(lock_info=text_type(holder_info))):
 
403
                    dict(lock_info=str(holder_info))):
413
404
                result = self.force_break(holder_info)
414
405
                ui.ui_factory.show_message(
415
406
                    "Broke lock %s" % result.lock_url)
532
523
            info = self._read_info_file(self._held_info_path)
533
524
            self._trace("peek -> held")
534
525
            return info
535
 
        except NoSuchFile as e:
 
526
        except NoSuchFile:
536
527
            self._trace("peek -> not held")
537
528
 
538
529
    def _prepare_info(self):
552
543
            raise LockContention(self)
553
544
        result = self._attempt_lock()
554
545
        hook_result = lock.LockResult(self.transport.abspath(self.path),
555
 
                self.nonce)
 
546
                                      self.nonce)
556
547
        for hook in self.hooks['lock_acquired']:
557
548
            hook(hook_result)
558
549
        return result
619
610
                    start = gettext('Lock owner changed for')
620
611
                last_info = new_info
621
612
                msg = gettext('{0} lock {1} {2}.').format(start, lock_url,
622
 
                                                                    new_info)
 
613
                                                          new_info)
623
614
                if deadline_str is None:
624
615
                    deadline_str = time.strftime('%H:%M:%S',
625
 
                                                    time.localtime(deadline))
 
616
                                                 time.localtime(deadline))
626
617
                if timeout > 0:
627
618
                    msg += '\n' + gettext(
628
 
                             'Will continue to try until %s, unless '
629
 
                             'you press Ctrl-C.') % deadline_str
 
619
                        'Will continue to try until %s, unless '
 
620
                        'you press Ctrl-C.') % deadline_str
630
621
                msg += '\n' + gettext('See "brz help break-lock" for more.')
631
622
                self._report_function(msg)
632
623
            if (max_attempts is not None) and (attempt_count >= max_attempts):
684
675
        # we can't rely on that remotely.  Once this is cleaned up,
685
676
        # reenable this warning to prevent it coming back in
686
677
        # -- mbp 20060303
687
 
        ## warn("LockDir.lock_read falls back to write lock")
 
678
        # warn("LockDir.lock_read falls back to write lock")
688
679
        if self._lock_held or self._fake_read_lock:
689
680
            raise LockContention(self)
690
681
        self._fake_read_lock = True
733
724
        """Return a debugging representation of this object."""
734
725
        return "%s(%r)" % (self.__class__.__name__, self.info_dict)
735
726
 
736
 
    def __unicode__(self):
 
727
    def __str__(self):
737
728
        """Return a user-oriented description of this object."""
738
729
        d = self.to_readable_dict()
739
 
        return ( gettext(
 
730
        return (gettext(
740
731
            u'held by %(user)s on %(hostname)s (process #%(pid)s), '
741
732
            u'acquired %(time_ago)s') % d)
742
733
 
743
 
    if PY3:
744
 
        __str__ = __unicode__
745
 
 
746
734
    def to_readable_dict(self):
747
735
        """Turn the holder info into a dict of human-readable attributes.
748
736
 
778
766
        info = dict(
779
767
            hostname=get_host_name(),
780
768
            pid=str(os.getpid()),
781
 
            nonce=rand_chars(20),
 
769
            nonce=rand_chars(20).encode('ascii'),
782
770
            start_time=str(int(time.time())),
783
771
            user=get_username_for_lock_info(),
784
772
            )
799
787
        except ValueError as e:
800
788
            mutter('Corrupt lock info file: %r', lines)
801
789
            raise LockCorrupt("could not parse lock info file: " + str(e),
802
 
                lines)
 
790
                              lines)
803
791
        if stanza is None:
804
792
            # see bug 185013; we fairly often end up with the info file being
805
793
            # empty after an interruption; we could log a message here but
806
794
            # there may not be much we can say
807
795
            return cls({})
808
796
        else:
809
 
            return cls(stanza.as_dict())
 
797
            ret = stanza.as_dict()
 
798
            ret['nonce'] = ret['nonce'].encode('ascii')
 
799
            return cls(ret)
810
800
 
811
801
    def __hash__(self):
812
802
        return id(self)
856
846
            pid = int(pid_str)
857
847
        except ValueError:
858
848
            mutter("can't parse pid %r from %r"
859
 
                % (pid_str, self))
 
849
                   % (pid_str, self))
860
850
            return False
861
851
        return osutils.is_local_pid_dead(pid)
862
852
 
869
859
    """
870
860
    try:
871
861
        return config.GlobalStack().get('email')
872
 
    except config.NoWhoami:
 
862
    except errors.NoWhoami:
873
863
        return osutils.getuser_unicode()