/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

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2006 Canonical Ltd
2
 
 
 
2
#
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
96
96
 
97
97
import os
98
98
import time
99
 
from warnings import warn
100
99
from StringIO import StringIO
101
100
 
102
101
import bzrlib.config
106
105
        LockBreakMismatch,
107
106
        LockBroken,
108
107
        LockContention,
109
 
        LockError,
110
108
        LockNotHeld,
111
109
        NoSuchFile,
 
110
        PathError,
112
111
        ResourceBusy,
113
112
        UnlockableTransport,
114
113
        )
 
114
from bzrlib.trace import mutter
115
115
from bzrlib.transport import Transport
116
116
from bzrlib.osutils import rand_chars
117
117
from bzrlib.rio import RioWriter, read_stanza, Stanza
121
121
# lock at the same time they should *both* get it.  But then that's unlikely
122
122
# to be a good idea.
123
123
 
124
 
# TODO: Transport could offer a simpler put() method that avoids the
125
 
# rename-into-place for cases like creating the lock template, where there is
126
 
# no chance that the file already exists.
127
 
 
128
124
# TODO: Perhaps store some kind of note like the bzr command line in the lock
129
125
# info?
130
126
 
171
167
 
172
168
    is_held = property(lambda self: self._lock_held)
173
169
 
174
 
    def create(self):
 
170
    def create(self, mode=None):
175
171
        """Create the on-disk lock.
176
172
 
177
173
        This is typically only called when the object/directory containing the 
179
175
        """
180
176
        if self.transport.is_readonly():
181
177
            raise UnlockableTransport(self.transport)
182
 
        self.transport.mkdir(self.path)
 
178
        self.transport.mkdir(self.path, mode=mode)
183
179
 
184
180
    def attempt_lock(self):
185
181
        """Take the lock; fail if it's already held.
197
193
            sio = StringIO()
198
194
            self._prepare_info(sio)
199
195
            sio.seek(0)
200
 
            self.transport.put(tmpname + self.__INFO_NAME, sio)
 
196
            # append will create a new file; we use append rather than put
 
197
            # because we don't want to write to a temporary file and rename
 
198
            # into place, because that's going to happen to the whole
 
199
            # directory
 
200
            self.transport.append(tmpname + self.__INFO_NAME, sio)
201
201
            self.transport.rename(tmpname, self._held_dir)
202
202
            self._lock_held = True
203
203
            self.confirm()
204
 
            return
205
 
        except (DirectoryNotEmpty, FileExists, ResourceBusy), e:
206
 
            pass
207
 
        # fall through to here on contention
208
 
        raise LockContention(self)
 
204
        except (PathError, DirectoryNotEmpty, FileExists, ResourceBusy), e:
 
205
            mutter("contention on %r: %s", self, e)
 
206
            raise LockContention(self)
209
207
 
210
208
    def unlock(self):
211
209
        """Release a held lock
218
216
        # rename before deleting, because we can't atomically remove the whole
219
217
        # tree
220
218
        tmpname = '%s/releasing.%s.tmp' % (self.path, rand_chars(20))
 
219
        # gotta own it to unlock
 
220
        self.confirm()
221
221
        self.transport.rename(self._held_dir, tmpname)
222
222
        self._lock_held = False
223
223
        self.transport.delete(tmpname + self.__INFO_NAME)
224
224
        self.transport.rmdir(tmpname)
225
225
 
 
226
    def break_lock(self):
 
227
        """Break a lock not held by this instance of LockDir.
 
228
 
 
229
        This is a UI centric function: it uses the bzrlib.ui.ui_factory to
 
230
        prompt for input if a lock is detected and there is any doubt about
 
231
        it possibly being still active.
 
232
        """
 
233
        self._check_not_locked()
 
234
        holder_info = self.peek()
 
235
        if holder_info is not None:
 
236
            if bzrlib.ui.ui_factory.get_boolean(
 
237
                "Break lock %s held by %s@%s [process #%s]" % (
 
238
                    self.transport,
 
239
                    holder_info["user"],
 
240
                    holder_info["hostname"],
 
241
                    holder_info["pid"])):
 
242
                self.force_break(holder_info)
 
243
        
226
244
    def force_break(self, dead_holder_info):
227
245
        """Release a lock held by another process.
228
246
 
241
259
        """
242
260
        if not isinstance(dead_holder_info, dict):
243
261
            raise ValueError("dead_holder_info: %r" % dead_holder_info)
244
 
        if self._lock_held:
245
 
            raise AssertionError("can't break own lock: %r" % self)
 
262
        self._check_not_locked()
246
263
        current_info = self.peek()
247
264
        if current_info is None:
248
265
            # must have been recently released
261
278
        self.transport.delete(broken_info_path)
262
279
        self.transport.rmdir(tmpname)
263
280
 
 
281
    def _check_not_locked(self):
 
282
        """If the lock is held by this instance, raise an error."""
 
283
        if self._lock_held:
 
284
            raise AssertionError("can't break own lock: %r" % self)
 
285
 
264
286
    def confirm(self):
265
287
        """Make sure that the lock is still held by this locker.
266
288
 
349
371
        self.attempt_lock()
350
372
 
351
373
    def lock_read(self):
352
 
        """Compatability-mode shared lock.
 
374
        """Compatibility-mode shared lock.
353
375
 
354
376
        LockDir doesn't support shared read-only locks, so this 
355
377
        just pretends that the lock is taken but really does nothing.