/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: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

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