~bzr-pqm/bzr/bzr.dev

70 by mbp at sourcefrog
Prepare for smart recursive add.
1
# Copyright (C) 2005 Canonical Ltd
2
1 by mbp at sourcefrog
import from baz patch-364
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
18
import sys
19
import os
1371 by Martin Pool
- raise NotBranchError if format file can't be read
20
import errno
1372 by Martin Pool
- avoid converting inventories to/from StringIO
21
from warnings import warn
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
22
from cStringIO import StringIO
1372 by Martin Pool
- avoid converting inventories to/from StringIO
23
1 by mbp at sourcefrog
import from baz patch-364
24
25
import bzrlib
1399.1.1 by Robert Collins
move checks for versionability of file kinds into InventoryEntry
26
from bzrlib.inventory import InventoryEntry
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
27
import bzrlib.inventory as inventory
800 by Martin Pool
Merge John's import-speedup branch:
28
from bzrlib.trace import mutter, note
1390 by Robert Collins
pair programming worx... merge integration and weave
29
from bzrlib.osutils import (isdir, quotefn, compact_date, rand_bytes, 
30
                            rename, splitpath, sha_file, appendpath, 
31
                            file_kind)
1417.1.6 by Robert Collins
introduce transactions for grouping actions done to and with branches
32
import bzrlib.errors as errors
1192 by Martin Pool
- clean up code for retrieving stored inventories
33
from bzrlib.errors import (BzrError, InvalidRevisionNumber, InvalidRevisionId,
1299 by Martin Pool
- tidy up imports
34
                           NoSuchRevision, HistoryMissing, NotBranchError,
1391 by Robert Collins
merge from integration
35
                           DivergedBranches, LockError, UnlistableStore,
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
36
                           UnlistableBranch, NoSuchFile)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
37
from bzrlib.textui import show_status
1415 by Robert Collins
remove the ancestry weave file
38
from bzrlib.revision import Revision
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
39
from bzrlib.delta import compare_trees
40
from bzrlib.tree import EmptyTree, RevisionTree
1192 by Martin Pool
- clean up code for retrieving stored inventories
41
from bzrlib.inventory import Inventory
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
42
from bzrlib.store import copy_all
43
from bzrlib.store.compressed_text import CompressedTextStore
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
44
from bzrlib.store.text import TextStore
1393.2.3 by John Arbash Meinel
Fixing typos, updating stores, getting tests to pass.
45
from bzrlib.store.weave import WeaveStore
1417.1.6 by Robert Collins
introduce transactions for grouping actions done to and with branches
46
import bzrlib.transactions as transactions
1393.2.4 by John Arbash Meinel
All tests pass.
47
from bzrlib.transport import Transport, get_transport
1189 by Martin Pool
- BROKEN: partial support for commit into weave
48
import bzrlib.xml5
1104 by Martin Pool
- Add a simple UIFactory
49
import bzrlib.ui
50
1094 by Martin Pool
- merge aaron's merge improvements 999..1008
51
1186 by Martin Pool
- start implementing v5 format; Branch refuses to operate on old branches
52
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
53
BZR_BRANCH_FORMAT_5 = "Bazaar-NG branch, format 5\n"
1 by mbp at sourcefrog
import from baz patch-364
54
## TODO: Maybe include checks for common corruption of newlines, etc?
55
56
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
57
# TODO: Some operations like log might retrieve the same revisions
58
# repeatedly to calculate deltas.  We could perhaps have a weakref
1223 by Martin Pool
- store inventories in weave
59
# cache in memory to make this faster.  In general anything can be
60
# cached in memory between lock and unlock operations.
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
61
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
62
def find_branch(*ignored, **ignored_too):
63
    # XXX: leave this here for about one release, then remove it
64
    raise NotImplementedError('find_branch() is not supported anymore, '
65
                              'please use one of the new branch constructors')
600 by Martin Pool
- Better Branch.relpath that doesn't match on
66
def _relpath(base, path):
67
    """Return path relative to base, or raise exception.
68
69
    The path may be either an absolute path or a path relative to the
70
    current working directory.
71
72
    Lifted out of Branch.relpath for ease of testing.
73
74
    os.path.commonprefix (python2.4) has a bad bug that it works just
75
    on string prefixes, assuming that '/u' is a prefix of '/u2'.  This
76
    avoids that problem."""
77
    rp = os.path.abspath(path)
78
79
    s = []
80
    head = rp
81
    while len(head) >= len(base):
82
        if head == base:
83
            break
84
        head, tail = os.path.split(head)
85
        if tail:
86
            s.insert(0, tail)
87
    else:
88
        raise NotBranchError("path %r is not within branch %r" % (rp, base))
89
90
    return os.sep.join(s)
416 by Martin Pool
- bzr log and bzr root now accept an http URL
91
        
92
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
93
def find_branch_root(t):
94
    """Find the branch root enclosing the transport's base.
95
96
    t is a Transport object.
97
98
    It is not necessary that the base of t exists.
62 by mbp at sourcefrog
- new find_branch_root function; based on suggestion from aaron
99
100
    Basically we keep looking up until we find the control directory or
1074 by Martin Pool
- check for email address in BRANCH_ROOT/.bzr/email, so you can
101
    run into the root.  If there isn't one, raises NotBranchError.
102
    """
1185.11.9 by John Arbash Meinel
Most tests pass, some problems with unavailable socket recv
103
    orig_base = t.base
62 by mbp at sourcefrog
- new find_branch_root function; based on suggestion from aaron
104
    while True:
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
105
        if t.has(bzrlib.BZRDIR):
106
            return t
107
        new_t = t.clone('..')
108
        if new_t.base == t.base:
62 by mbp at sourcefrog
- new find_branch_root function; based on suggestion from aaron
109
            # reached the root, whatever that may be
1185.11.9 by John Arbash Meinel
Most tests pass, some problems with unavailable socket recv
110
            raise NotBranchError('%s is not in a branch' % orig_base)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
111
        t = new_t
1074 by Martin Pool
- check for email address in BRANCH_ROOT/.bzr/email, so you can
112
685 by Martin Pool
- add -r option to the branch command
113
1 by mbp at sourcefrog
import from baz patch-364
114
######################################################################
115
# branch objects
116
558 by Martin Pool
- All top-level classes inherit from object
117
class Branch(object):
1 by mbp at sourcefrog
import from baz patch-364
118
    """Branch holding a history of revisions.
119
343 by Martin Pool
doc
120
    base
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
121
        Base directory/url of the branch.
122
    """
123
    base = None
124
125
    def __init__(self, *ignored, **ignored_too):
126
        raise NotImplementedError('The Branch class is abstract')
127
128
    @staticmethod
1393.1.2 by Martin Pool
- better representation in Branch factories of opening old formats
129
    def open_downlevel(base):
130
        """Open a branch which may be of an old format.
131
        
132
        Only local branches are supported."""
1393.1.16 by Martin Pool
- fix up Branch.open_downlevel for Transport
133
        return _Branch(get_transport(base), relax_version_check=True)
1393.1.2 by Martin Pool
- better representation in Branch factories of opening old formats
134
        
135
    @staticmethod
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
136
    def open(base):
137
        """Open an existing branch, rooted at 'base' (url)"""
1393.2.4 by John Arbash Meinel
All tests pass.
138
        t = get_transport(base)
1393.1.63 by Martin Pool
- add some trace statements
139
        mutter("trying to open %r with transport %r", base, t)
1185.11.11 by John Arbash Meinel
Removing the remotebranch object.
140
        return _Branch(t)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
141
142
    @staticmethod
1185.2.8 by Lalo Martins
creating the new branch constructors
143
    def open_containing(url):
1185.1.41 by Robert Collins
massive patch from Alexander Belchenko - many PEP8 fixes, removes unused function uuid
144
        """Open an existing branch which contains url.
145
        
146
        This probes for a branch at url, and searches upwards from there.
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
147
        """
1393.2.4 by John Arbash Meinel
All tests pass.
148
        t = get_transport(url)
1185.11.9 by John Arbash Meinel
Most tests pass, some problems with unavailable socket recv
149
        t = find_branch_root(t)
1185.11.11 by John Arbash Meinel
Removing the remotebranch object.
150
        return _Branch(t)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
151
152
    @staticmethod
153
    def initialize(base):
154
        """Create a new branch, rooted at 'base' (url)"""
1393.2.4 by John Arbash Meinel
All tests pass.
155
        t = get_transport(base)
1185.11.11 by John Arbash Meinel
Removing the remotebranch object.
156
        return _Branch(t, init=True)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
157
158
    def setup_caching(self, cache_root):
159
        """Subclasses that care about caching should override this, and set
160
        up cached stores located under cache_root.
161
        """
1400.1.1 by Robert Collins
implement a basic test for the ui branch command from http servers
162
        self.cache_root = cache_root
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
163
164
1185.11.11 by John Arbash Meinel
Removing the remotebranch object.
165
class _Branch(Branch):
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
166
    """A branch stored in the actual filesystem.
167
168
    Note that it's "local" in the context of the filesystem; it doesn't
169
    really matter if it's on an nfs/smb/afs/coda/... share, as long as
170
    it's writable, and can be accessed via the normal filesystem API.
578 by Martin Pool
- start to move toward Branch.lock and unlock methods,
171
172
    _lock_mode
580 by Martin Pool
- Use explicit lock methods on a branch, rather than doing it
173
        None, or 'r' or 'w'
174
175
    _lock_count
176
        If _lock_mode is true, a positive count of the number of times the
177
        lock has been taken.
578 by Martin Pool
- start to move toward Branch.lock and unlock methods,
178
614 by Martin Pool
- unify two defintions of LockError
179
    _lock
180
        Lock object from bzrlib.lock.
1 by mbp at sourcefrog
import from baz patch-364
181
    """
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
182
    # We actually expect this class to be somewhat short-lived; part of its
183
    # purpose is to try to isolate what bits of the branch logic are tied to
184
    # filesystem access, so that in a later step, we can extricate them to
185
    # a separarte ("storage") class.
578 by Martin Pool
- start to move toward Branch.lock and unlock methods,
186
    _lock_mode = None
580 by Martin Pool
- Use explicit lock methods on a branch, rather than doing it
187
    _lock_count = None
615 by Martin Pool
Major rework of locking code:
188
    _lock = None
1223 by Martin Pool
- store inventories in weave
189
    _inventory_weave = None
353 by Martin Pool
- Per-branch locks in read and write modes.
190
    
897 by Martin Pool
- merge john's revision-naming code
191
    # Map some sort of prefix into a namespace
192
    # stuff like "revno:10", "revid:", etc.
193
    # This should match a prefix with a function which accepts
194
    REVISION_NAMESPACES = {}
195
1391 by Robert Collins
merge from integration
196
    def push_stores(self, branch_to):
197
        """Copy the content of this branches store to branch_to."""
198
        if (self._branch_format != branch_to._branch_format
199
            or self._branch_format != 4):
200
            from bzrlib.fetch import greedy_fetch
1393 by Robert Collins
reenable remotebranch tests
201
            mutter("falling back to fetch logic to push between %s(%s) and %s(%s)",
202
                   self, self._branch_format, branch_to, branch_to._branch_format)
1391 by Robert Collins
merge from integration
203
            greedy_fetch(to_branch=branch_to, from_branch=self,
204
                         revision=self.last_revision())
205
            return
206
207
        store_pairs = ((self.text_store,      branch_to.text_store),
208
                       (self.inventory_store, branch_to.inventory_store),
209
                       (self.revision_store,  branch_to.revision_store))
210
        try:
211
            for from_store, to_store in store_pairs: 
212
                copy_all(from_store, to_store)
213
        except UnlistableStore:
214
            raise UnlistableBranch(from_store)
215
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
216
    def __init__(self, transport, init=False,
1293 by Martin Pool
- add Branch constructor option to relax version check
217
                 relax_version_check=False):
1 by mbp at sourcefrog
import from baz patch-364
218
        """Create new branch object at a particular location.
219
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
220
        transport -- A Transport object, defining how to access files.
221
                (If a string, transport.transport() will be used to
222
                create a Transport object)
62 by mbp at sourcefrog
- new find_branch_root function; based on suggestion from aaron
223
        
254 by Martin Pool
- Doc cleanups from Magnus Therning
224
        init -- If True, create new control files in a previously
1 by mbp at sourcefrog
import from baz patch-364
225
             unversioned directory.  If False, the branch must already
226
             be versioned.
227
1293 by Martin Pool
- add Branch constructor option to relax version check
228
        relax_version_check -- If true, the usual check for the branch
229
            version is not applied.  This is intended only for
230
            upgrade/recovery type use; it's not guaranteed that
231
            all operations will work on old format branches.
232
1 by mbp at sourcefrog
import from baz patch-364
233
        In the test suite, creation of new trees is tested using the
234
        `ScratchBranch` class.
235
        """
1393.1.15 by Martin Pool
- better assertion message
236
        assert isinstance(transport, Transport), \
237
            "%r is not a Transport" % transport
907.1.8 by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport
238
        self._transport = transport
1 by mbp at sourcefrog
import from baz patch-364
239
        if init:
240
            self._make_control()
1293 by Martin Pool
- add Branch constructor option to relax version check
241
        self._check_format(relax_version_check)
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
242
243
        def get_store(name, compressed=True):
1393.1.41 by Martin Pool
doc
244
            # FIXME: This approach of assuming stores are all entirely compressed
245
            # or entirely uncompressed is tidy, but breaks upgrade from 
246
            # some existing branches where there's a mixture; we probably 
247
            # still want the option to look for both.
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
248
            relpath = self._rel_controlfilename(name)
249
            if compressed:
250
                store = CompressedTextStore(self._transport.clone(relpath))
251
            else:
252
                store = TextStore(self._transport.clone(relpath))
1400.1.1 by Robert Collins
implement a basic test for the ui branch command from http servers
253
            #if self._transport.should_cache():
254
            #    cache_path = os.path.join(self.cache_root, name)
255
            #    os.mkdir(cache_path)
256
            #    store = bzrlib.store.CachedStore(store, cache_path)
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
257
            return store
258
        def get_weave(name):
259
            relpath = self._rel_controlfilename(name)
260
            ws = WeaveStore(self._transport.clone(relpath))
261
            if self._transport.should_cache():
262
                ws.enable_cache = True
263
            return ws
264
1296 by Martin Pool
- v4 branch should allow access to inventory and text stores
265
        if self._branch_format == 4:
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
266
            self.inventory_store = get_store('inventory-store')
267
            self.text_store = get_store('text-store')
268
            self.revision_store = get_store('revision-store')
1390 by Robert Collins
pair programming worx... merge integration and weave
269
        elif self._branch_format == 5:
1393.2.3 by John Arbash Meinel
Fixing typos, updating stores, getting tests to pass.
270
            self.control_weaves = get_weave([])
271
            self.weave_store = get_weave('weaves')
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
272
            self.revision_store = get_store('revision-store', compressed=False)
1417.1.6 by Robert Collins
introduce transactions for grouping actions done to and with branches
273
        self._transaction = None
1 by mbp at sourcefrog
import from baz patch-364
274
275
    def __str__(self):
907.1.5 by John Arbash Meinel
Some more work, including ScratchBranch changes.
276
        return '%s(%r)' % (self.__class__.__name__, self._transport.base)
1 by mbp at sourcefrog
import from baz patch-364
277
278
279
    __repr__ = __str__
280
281
578 by Martin Pool
- start to move toward Branch.lock and unlock methods,
282
    def __del__(self):
615 by Martin Pool
Major rework of locking code:
283
        if self._lock_mode or self._lock:
1390 by Robert Collins
pair programming worx... merge integration and weave
284
            # XXX: This should show something every time, and be suitable for
285
            # headless operation and embedding
578 by Martin Pool
- start to move toward Branch.lock and unlock methods,
286
            warn("branch %r was not explicitly unlocked" % self)
615 by Martin Pool
Major rework of locking code:
287
            self._lock.unlock()
578 by Martin Pool
- start to move toward Branch.lock and unlock methods,
288
907.1.23 by John Arbash Meinel
Branch objects now automatically create Cached stores if the protocol is_remote.
289
        # TODO: It might be best to do this somewhere else,
290
        # but it is nice for a Branch object to automatically
291
        # cache it's information.
292
        # Alternatively, we could have the Transport objects cache requests
293
        # See the earlier discussion about how major objects (like Branch)
294
        # should never expect their __del__ function to run.
1185.11.9 by John Arbash Meinel
Most tests pass, some problems with unavailable socket recv
295
        if hasattr(self, 'cache_root') and self.cache_root is not None:
907.1.23 by John Arbash Meinel
Branch objects now automatically create Cached stores if the protocol is_remote.
296
            try:
297
                import shutil
298
                shutil.rmtree(self.cache_root)
299
            except:
300
                pass
301
            self.cache_root = None
302
907.1.17 by John Arbash Meinel
Adding a Branch.base property, removing pull_loc()
303
    def _get_base(self):
907.1.19 by John Arbash Meinel
Updated ScratchBranch and Branch.base, All Tests PASS !!!
304
        if self._transport:
305
            return self._transport.base
306
        return None
907.1.17 by John Arbash Meinel
Adding a Branch.base property, removing pull_loc()
307
308
    base = property(_get_base)
578 by Martin Pool
- start to move toward Branch.lock and unlock methods,
309
1417.1.6 by Robert Collins
introduce transactions for grouping actions done to and with branches
310
    def _finish_transaction(self):
311
        """Exit the current transaction."""
312
        if self._transaction is None:
313
            raise errors.LockError('Branch %s is not in a transaction' %
314
                                   self)
315
        transaction = self._transaction
316
        self._transaction = None
317
        transaction.finish()
318
319
    def get_transaction(self):
320
        """Return the current active transaction.
321
322
        If no transaction is active, this returns a passthrough object
323
        for which all data is immedaitely flushed and no caching happens.
324
        """
325
        if self._transaction is None:
326
            return transactions.PassThroughTransaction()
327
        else:
328
            return self._transaction
329
330
    def _set_transaction(self, new_transaction):
331
        """Set a new active transaction."""
332
        if self._transaction is not None:
333
            raise errors.LockError('Branch %s is in a transaction already.' %
334
                                   self)
335
        self._transaction = new_transaction
610 by Martin Pool
- replace Branch.lock(mode) with separate lock_read and lock_write
336
337
    def lock_write(self):
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
338
        # TODO: Upgrade locking to support using a Transport,
339
        # and potentially a remote locking protocol
610 by Martin Pool
- replace Branch.lock(mode) with separate lock_read and lock_write
340
        if self._lock_mode:
341
            if self._lock_mode != 'w':
342
                raise LockError("can't upgrade to a write lock from %r" %
343
                                self._lock_mode)
344
            self._lock_count += 1
345
        else:
907.1.24 by John Arbash Meinel
Remote functionality work.
346
            self._lock = self._transport.lock_write(
347
                    self._rel_controlfilename('branch-lock'))
610 by Martin Pool
- replace Branch.lock(mode) with separate lock_read and lock_write
348
            self._lock_mode = 'w'
349
            self._lock_count = 1
1417.1.6 by Robert Collins
introduce transactions for grouping actions done to and with branches
350
            self._set_transaction(transactions.PassThroughTransaction())
610 by Martin Pool
- replace Branch.lock(mode) with separate lock_read and lock_write
351
352
353
    def lock_read(self):
354
        if self._lock_mode:
355
            assert self._lock_mode in ('r', 'w'), \
356
                   "invalid lock mode %r" % self._lock_mode
357
            self._lock_count += 1
358
        else:
907.1.24 by John Arbash Meinel
Remote functionality work.
359
            self._lock = self._transport.lock_read(
360
                    self._rel_controlfilename('branch-lock'))
610 by Martin Pool
- replace Branch.lock(mode) with separate lock_read and lock_write
361
            self._lock_mode = 'r'
362
            self._lock_count = 1
1417.1.6 by Robert Collins
introduce transactions for grouping actions done to and with branches
363
            self._set_transaction(transactions.ReadOnlyTransaction())
610 by Martin Pool
- replace Branch.lock(mode) with separate lock_read and lock_write
364
                        
578 by Martin Pool
- start to move toward Branch.lock and unlock methods,
365
    def unlock(self):
366
        if not self._lock_mode:
610 by Martin Pool
- replace Branch.lock(mode) with separate lock_read and lock_write
367
            raise LockError('branch %r is not locked' % (self))
580 by Martin Pool
- Use explicit lock methods on a branch, rather than doing it
368
369
        if self._lock_count > 1:
370
            self._lock_count -= 1
371
        else:
1417.1.6 by Robert Collins
introduce transactions for grouping actions done to and with branches
372
            self._finish_transaction()
615 by Martin Pool
Major rework of locking code:
373
            self._lock.unlock()
374
            self._lock = None
580 by Martin Pool
- Use explicit lock methods on a branch, rather than doing it
375
            self._lock_mode = self._lock_count = None
353 by Martin Pool
- Per-branch locks in read and write modes.
376
67 by mbp at sourcefrog
use abspath() for the function that makes an absolute
377
    def abspath(self, name):
378
        """Return absolute filename for something in the branch"""
907.1.5 by John Arbash Meinel
Some more work, including ScratchBranch changes.
379
        return self._transport.abspath(name)
67 by mbp at sourcefrog
use abspath() for the function that makes an absolute
380
68 by mbp at sourcefrog
- new relpath command and function
381
    def relpath(self, path):
382
        """Return path relative to this branch of something inside it.
383
384
        Raises an error if path is not in this branch."""
907.1.24 by John Arbash Meinel
Remote functionality work.
385
        return self._transport.relpath(path)
68 by mbp at sourcefrog
- new relpath command and function
386
387
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
388
    def _rel_controlfilename(self, file_or_path):
389
        if isinstance(file_or_path, basestring):
390
            file_or_path = [file_or_path]
391
        return [bzrlib.BZRDIR] + file_or_path
392
1 by mbp at sourcefrog
import from baz patch-364
393
    def controlfilename(self, file_or_path):
394
        """Return location relative to branch."""
907.1.8 by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport
395
        return self._transport.abspath(self._rel_controlfilename(file_or_path))
1 by mbp at sourcefrog
import from baz patch-364
396
397
398
    def controlfile(self, file_or_path, mode='r'):
245 by mbp at sourcefrog
- control files always in utf-8-unix format
399
        """Open a control file for this branch.
400
401
        There are two classes of file in the control directory: text
402
        and binary.  binary files are untranslated byte streams.  Text
403
        control files are stored with Unix newlines and in UTF-8, even
404
        if the platform or locale defaults are different.
430 by Martin Pool
doc
405
406
        Controlfiles should almost never be opened in write mode but
407
        rather should be atomically copied and replaced using atomicfile.
245 by mbp at sourcefrog
- control files always in utf-8-unix format
408
        """
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
409
        import codecs
410
411
        relpath = self._rel_controlfilename(file_or_path)
412
        #TODO: codecs.open() buffers linewise, so it was overloaded with
413
        # a much larger buffer, do we need to do the same for getreader/getwriter?
414
        if mode == 'rb': 
907.1.8 by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport
415
            return self._transport.get(relpath)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
416
        elif mode == 'wb':
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
417
            raise BzrError("Branch.controlfile(mode='wb') is not supported, use put_controlfiles")
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
418
        elif mode == 'r':
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
419
            return codecs.getreader('utf-8')(self._transport.get(relpath), errors='replace')
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
420
        elif mode == 'w':
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
421
            raise BzrError("Branch.controlfile(mode='w') is not supported, use put_controlfiles")
245 by mbp at sourcefrog
- control files always in utf-8-unix format
422
        else:
423
            raise BzrError("invalid controlfile mode %r" % mode)
424
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
425
    def put_controlfile(self, path, f, encode=True):
907.1.20 by John Arbash Meinel
Removed Transport.open(), making get + put encode/decode to utf-8
426
        """Write an entry as a controlfile.
427
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
428
        :param path: The path to put the file, relative to the .bzr control
429
                     directory
430
        :param f: A file-like or string object whose contents should be copied.
431
        :param encode:  If true, encode the contents as utf-8
432
        """
433
        self.put_controlfiles([(path, f)], encode=encode)
434
435
    def put_controlfiles(self, files, encode=True):
436
        """Write several entries as controlfiles.
437
438
        :param files: A list of [(path, file)] pairs, where the path is the directory
439
                      underneath the bzr control directory
440
        :param encode:  If true, encode the contents as utf-8
441
        """
442
        import codecs
443
        ctrl_files = []
444
        for path, f in files:
445
            if encode:
446
                if isinstance(f, basestring):
447
                    f = f.encode('utf-8', 'replace')
448
                else:
449
                    f = codecs.getwriter('utf-8')(f, errors='replace')
450
            path = self._rel_controlfilename(path)
451
            ctrl_files.append((path, f))
452
        self._transport.put_multi(ctrl_files)
1 by mbp at sourcefrog
import from baz patch-364
453
454
    def _make_control(self):
800 by Martin Pool
Merge John's import-speedup branch:
455
        from bzrlib.inventory import Inventory
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
456
        from bzrlib.weavefile import write_weave_v5
457
        from bzrlib.weave import Weave
802 by Martin Pool
- Remove XMLMixin class in favour of simple pack_xml, unpack_xml functions
458
        
1185.11.1 by John Arbash Meinel
(broken) Transport work is merged in. Tests do not pass yet.
459
        # Create an empty inventory
907.1.47 by John Arbash Meinel
Created mkdir_multi, modified branch to use _multi forms when initializing a branch, creating a full test routine for transports
460
        sio = StringIO()
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
461
        # if we want per-tree root ids then this is the place to set
462
        # them; they're not needed for now and so ommitted for
463
        # simplicity.
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
464
        bzrlib.xml5.serializer_v5.write_inventory(Inventory(), sio)
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
465
        empty_inv = sio.getvalue()
466
        sio = StringIO()
467
        bzrlib.weavefile.write_weave_v5(Weave(), sio)
468
        empty_weave = sio.getvalue()
907.1.47 by John Arbash Meinel
Created mkdir_multi, modified branch to use _multi forms when initializing a branch, creating a full test routine for transports
469
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
470
        dirs = [[], 'revision-store', 'weaves']
907.1.47 by John Arbash Meinel
Created mkdir_multi, modified branch to use _multi forms when initializing a branch, creating a full test routine for transports
471
        files = [('README', 
1 by mbp at sourcefrog
import from baz patch-364
472
            "This is a Bazaar-NG control directory.\n"
907.1.47 by John Arbash Meinel
Created mkdir_multi, modified branch to use _multi forms when initializing a branch, creating a full test routine for transports
473
            "Do not change any files in this directory.\n"),
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
474
            ('branch-format', BZR_BRANCH_FORMAT_5),
907.1.47 by John Arbash Meinel
Created mkdir_multi, modified branch to use _multi forms when initializing a branch, creating a full test routine for transports
475
            ('revision-history', ''),
476
            ('branch-name', ''),
477
            ('branch-lock', ''),
478
            ('pending-merges', ''),
1393.2.2 by John Arbash Meinel
Updated stores to use Transport
479
            ('inventory', empty_inv),
480
            ('inventory.weave', empty_weave),
481
            ('ancestry.weave', empty_weave)
907.1.47 by John Arbash Meinel
Created mkdir_multi, modified branch to use _multi forms when initializing a branch, creating a full test routine for transports
482
        ]
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
483
        cfn = self._rel_controlfilename
484
        self._transport.mkdir_multi([cfn(d) for d in dirs])
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
485
        self.put_controlfiles(files)
907.1.5 by John Arbash Meinel
Some more work, including ScratchBranch changes.
486
        mutter('created control directory in ' + self._transport.base)
802 by Martin Pool
- Remove XMLMixin class in favour of simple pack_xml, unpack_xml functions
487
1293 by Martin Pool
- add Branch constructor option to relax version check
488
    def _check_format(self, relax_version_check):
1 by mbp at sourcefrog
import from baz patch-364
489
        """Check this branch format is supported.
490
1187 by Martin Pool
- improved check for branch version
491
        The format level is stored, as an integer, in
492
        self._branch_format for code that needs to check it later.
1 by mbp at sourcefrog
import from baz patch-364
493
494
        In the future, we might need different in-memory Branch
495
        classes to support downlevel branches.  But not yet.
163 by mbp at sourcefrog
merge win32 portability fixes
496
        """
1185.11.9 by John Arbash Meinel
Most tests pass, some problems with unavailable socket recv
497
        try:
498
            fmt = self.controlfile('branch-format', 'r').read()
499
        except NoSuchFile:
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
500
            raise NotBranchError(self.base)
1393.1.63 by Martin Pool
- add some trace statements
501
        mutter("got branch format %r", fmt)
1187 by Martin Pool
- improved check for branch version
502
        if fmt == BZR_BRANCH_FORMAT_5:
503
            self._branch_format = 5
1294 by Martin Pool
- refactor branch version detection
504
        elif fmt == BZR_BRANCH_FORMAT_4:
505
            self._branch_format = 4
506
507
        if (not relax_version_check
508
            and self._branch_format != 5):
1185.1.53 by Robert Collins
raise a specific error on unsupported branches so that they can be distinguished from generic errors
509
            raise errors.UnsupportedFormatError(
510
                           'sorry, branch format %r not supported' % fmt,
576 by Martin Pool
- raise exceptions rather than using bailout()
511
                           ['use a different bzr version',
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
512
                            'or remove the .bzr directory'
513
                            ' and "bzr init" again'])
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
514
909 by Martin Pool
- merge John's code to give the tree root an explicit file id
515
    def get_root_id(self):
516
        """Return the id of this branches root"""
517
        inv = self.read_working_inventory()
518
        return inv.root.file_id
1 by mbp at sourcefrog
import from baz patch-364
519
909 by Martin Pool
- merge John's code to give the tree root an explicit file id
520
    def set_root_id(self, file_id):
521
        inv = self.read_working_inventory()
522
        orig_root_id = inv.root.file_id
523
        del inv._byid[inv.root.file_id]
524
        inv.root.file_id = file_id
525
        inv._byid[inv.root.file_id] = inv.root
526
        for fid in inv:
527
            entry = inv[fid]
528
            if entry.parent_id in (None, orig_root_id):
529
                entry.parent_id = inv.root.file_id
530
        self._write_inventory(inv)
580 by Martin Pool
- Use explicit lock methods on a branch, rather than doing it
531
1 by mbp at sourcefrog
import from baz patch-364
532
    def read_working_inventory(self):
533
        """Read the working inventory."""
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
534
        self.lock_read()
535
        try:
802 by Martin Pool
- Remove XMLMixin class in favour of simple pack_xml, unpack_xml functions
536
            # ElementTree does its own conversion from UTF-8, so open in
537
            # binary.
1180 by Martin Pool
- start splitting code for xml (de)serialization away from objects
538
            f = self.controlfile('inventory', 'rb')
1189 by Martin Pool
- BROKEN: partial support for commit into weave
539
            return bzrlib.xml5.serializer_v5.read_inventory(f)
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
540
        finally:
541
            self.unlock()
580 by Martin Pool
- Use explicit lock methods on a branch, rather than doing it
542
            
1 by mbp at sourcefrog
import from baz patch-364
543
544
    def _write_inventory(self, inv):
545
        """Update the working inventory.
546
547
        That is to say, the inventory describing changes underway, that
548
        will be committed to the next revision.
549
        """
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
550
        from cStringIO import StringIO
770 by Martin Pool
- write new working inventory using AtomicFile
551
        self.lock_write()
552
        try:
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
553
            sio = StringIO()
1393.2.1 by John Arbash Meinel
Merged in split-storage-2 branch. Need to cleanup a little bit more still.
554
            bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
555
            sio.seek(0)
1185.11.1 by John Arbash Meinel
(broken) Transport work is merged in. Tests do not pass yet.
556
            # Transport handles atomicity
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
557
            self.put_controlfile('inventory', sio)
770 by Martin Pool
- write new working inventory using AtomicFile
558
        finally:
559
            self.unlock()
560
        
14 by mbp at sourcefrog
write inventory to temporary file and atomically replace
561
        mutter('wrote working inventory')
580 by Martin Pool
- Use explicit lock methods on a branch, rather than doing it
562
            
1 by mbp at sourcefrog
import from baz patch-364
563
    inventory = property(read_working_inventory, _write_inventory, None,
564
                         """Inventory for the working copy.""")
565
1129 by Martin Pool
- Branch.add shouldn't write to stdout either
566
    def add(self, files, ids=None):
1 by mbp at sourcefrog
import from baz patch-364
567
        """Make files versioned.
568
1129 by Martin Pool
- Branch.add shouldn't write to stdout either
569
        Note that the command line normally calls smart_add instead,
570
        which can automatically recurse.
247 by mbp at sourcefrog
doc
571
1 by mbp at sourcefrog
import from baz patch-364
572
        This puts the files in the Added state, so that they will be
573
        recorded by the next commit.
574
596 by Martin Pool
doc
575
        files
576
            List of paths to add, relative to the base of the tree.
577
578
        ids
579
            If set, use these instead of automatically generated ids.
580
            Must be the same length as the list of files, but may
581
            contain None for ids that are to be autogenerated.
582
254 by Martin Pool
- Doc cleanups from Magnus Therning
583
        TODO: Perhaps have an option to add the ids even if the files do
596 by Martin Pool
doc
584
              not (yet) exist.
1 by mbp at sourcefrog
import from baz patch-364
585
1129 by Martin Pool
- Branch.add shouldn't write to stdout either
586
        TODO: Perhaps yield the ids and paths as they're added.
1 by mbp at sourcefrog
import from baz patch-364
587
        """
588
        # TODO: Re-adding a file that is removed in the working copy
589
        # should probably put it back with the previous ID.
800 by Martin Pool
Merge John's import-speedup branch:
590
        if isinstance(files, basestring):
591
            assert(ids is None or isinstance(ids, basestring))
1 by mbp at sourcefrog
import from baz patch-364
592
            files = [files]
493 by Martin Pool
- Merge aaron's merge command
593
            if ids is not None:
594
                ids = [ids]
595
596
        if ids is None:
597
            ids = [None] * len(files)
598
        else:
599
            assert(len(ids) == len(files))
580 by Martin Pool
- Use explicit lock methods on a branch, rather than doing it
600
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
601
        self.lock_write()
602
        try:
603
            inv = self.read_working_inventory()
604
            for f,file_id in zip(files, ids):
605
                if is_control_file(f):
606
                    raise BzrError("cannot add control file %s" % quotefn(f))
607
608
                fp = splitpath(f)
609
610
                if len(fp) == 0:
611
                    raise BzrError("cannot add top-level %r" % f)
612
613
                fullpath = os.path.normpath(self.abspath(f))
614
615
                try:
616
                    kind = file_kind(fullpath)
617
                except OSError:
618
                    # maybe something better?
1092.2.6 by Robert Collins
symlink support updated to work
619
                    raise BzrError('cannot add: not a regular file, symlink or directory: %s' % quotefn(f))
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
620
1399.1.1 by Robert Collins
move checks for versionability of file kinds into InventoryEntry
621
                if not InventoryEntry.versionable_kind(kind):
622
                    raise BzrError('cannot add: not a versionable file ('
623
                                   'i.e. regular file, symlink or directory): %s' % quotefn(f))
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
624
625
                if file_id is None:
626
                    file_id = gen_file_id(f)
627
                inv.add_path(f, kind=kind, file_id=file_id)
628
629
                mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
630
631
            self._write_inventory(inv)
632
        finally:
633
            self.unlock()
70 by mbp at sourcefrog
Prepare for smart recursive add.
634
            
1 by mbp at sourcefrog
import from baz patch-364
635
176 by mbp at sourcefrog
New cat command contributed by janmar.
636
    def print_file(self, file, revno):
637
        """Print `file` to stdout."""
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
638
        self.lock_read()
639
        try:
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
640
            tree = self.revision_tree(self.get_rev_id(revno))
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
641
            # use inventory as it was in that revision
642
            file_id = tree.inventory.path2id(file)
643
            if not file_id:
897 by Martin Pool
- merge john's revision-naming code
644
                raise BzrError("%r is not present in revision %s" % (file, revno))
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
645
            tree.print_file(file_id)
646
        finally:
647
            self.unlock()
648
649
1 by mbp at sourcefrog
import from baz patch-364
650
    def remove(self, files, verbose=False):
651
        """Mark nominated files for removal from the inventory.
652
653
        This does not remove their text.  This does not run on 
654
254 by Martin Pool
- Doc cleanups from Magnus Therning
655
        TODO: Refuse to remove modified files unless --force is given?
1 by mbp at sourcefrog
import from baz patch-364
656
254 by Martin Pool
- Doc cleanups from Magnus Therning
657
        TODO: Do something useful with directories.
1 by mbp at sourcefrog
import from baz patch-364
658
254 by Martin Pool
- Doc cleanups from Magnus Therning
659
        TODO: Should this remove the text or not?  Tough call; not
1 by mbp at sourcefrog
import from baz patch-364
660
        removing may be useful and the user can just use use rm, and
661
        is the opposite of add.  Removing it is consistent with most
662
        other tools.  Maybe an option.
663
        """
664
        ## TODO: Normalize names
665
        ## TODO: Remove nested loops; better scalability
800 by Martin Pool
Merge John's import-speedup branch:
666
        if isinstance(files, basestring):
1 by mbp at sourcefrog
import from baz patch-364
667
            files = [files]
580 by Martin Pool
- Use explicit lock methods on a branch, rather than doing it
668
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
669
        self.lock_write()
670
671
        try:
672
            tree = self.working_tree()
673
            inv = tree.inventory
674
675
            # do this before any modifications
676
            for f in files:
677
                fid = inv.path2id(f)
678
                if not fid:
679
                    raise BzrError("cannot remove unversioned file %s" % quotefn(f))
680
                mutter("remove inventory entry %s {%s}" % (quotefn(f), fid))
681
                if verbose:
682
                    # having remove it, it must be either ignored or unknown
683
                    if tree.is_ignored(f):
684
                        new_status = 'I'
685
                    else:
686
                        new_status = '?'
687
                    show_status(new_status, inv[fid].kind, quotefn(f))
688
                del inv[fid]
689
690
            self._write_inventory(inv)
691
        finally:
692
            self.unlock()
693
612 by Martin Pool
doc
694
    # FIXME: this doesn't need to be a branch method
493 by Martin Pool
- Merge aaron's merge command
695
    def set_inventory(self, new_inventory_list):
800 by Martin Pool
Merge John's import-speedup branch:
696
        from bzrlib.inventory import Inventory, InventoryEntry
909 by Martin Pool
- merge John's code to give the tree root an explicit file id
697
        inv = Inventory(self.get_root_id())
493 by Martin Pool
- Merge aaron's merge command
698
        for path, file_id, parent, kind in new_inventory_list:
699
            name = os.path.basename(path)
700
            if name == "":
701
                continue
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
702
            # fixme, there should be a factory function inv,add_?? 
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
703
            if kind == 'directory':
704
                inv.add(inventory.InventoryDirectory(file_id, name, parent))
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
705
            elif kind == 'file':
706
                inv.add(inventory.InventoryFile(file_id, name, parent))
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
707
            elif kind == 'symlink':
708
                inv.add(inventory.InventoryLink(file_id, name, parent))
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
709
            else:
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
710
                raise BzrError("unknown kind %r" % kind)
493 by Martin Pool
- Merge aaron's merge command
711
        self._write_inventory(inv)
712
1 by mbp at sourcefrog
import from baz patch-364
713
    def unknowns(self):
714
        """Return all unknown files.
715
716
        These are files in the working directory that are not versioned or
717
        control files or ignored.
718
        
719
        >>> b = ScratchBranch(files=['foo', 'foo~'])
720
        >>> list(b.unknowns())
721
        ['foo']
722
        >>> b.add('foo')
723
        >>> list(b.unknowns())
724
        []
725
        >>> b.remove('foo')
726
        >>> list(b.unknowns())
727
        ['foo']
728
        """
729
        return self.working_tree().unknowns()
730
731
905 by Martin Pool
- merge aaron's append_multiple.patch
732
    def append_revision(self, *revision_ids):
733
        for revision_id in revision_ids:
734
            mutter("add {%s} to revision-history" % revision_id)
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
735
        self.lock_write()
769 by Martin Pool
- append to branch revision history using AtomicFile
736
        try:
1393.1.22 by Martin Pool
- clean up Branch.append_revision()
737
            rev_history = self.revision_history()
738
            rev_history.extend(revision_ids)
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
739
            self.put_controlfile('revision-history', '\n'.join(rev_history))
769 by Martin Pool
- append to branch revision history using AtomicFile
740
        finally:
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
741
            self.unlock()
233 by mbp at sourcefrog
- more output from test.sh
742
1261 by Martin Pool
- new method Branch.has_revision
743
    def has_revision(self, revision_id):
744
        """True if this branch has a copy of the revision.
745
746
        This does not necessarily imply the revision is merge
747
        or on the mainline."""
1390 by Robert Collins
pair programming worx... merge integration and weave
748
        return (revision_id is None
749
                or revision_id in self.revision_store)
1261 by Martin Pool
- new method Branch.has_revision
750
1182 by Martin Pool
- more disentangling of xml storage format from objects
751
    def get_revision_xml_file(self, revision_id):
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
752
        """Return XML file object for revision object."""
753
        if not revision_id or not isinstance(revision_id, basestring):
754
            raise InvalidRevisionId(revision_id)
755
756
        self.lock_read()
757
        try:
758
            try:
759
                return self.revision_store[revision_id]
1185.1.18 by Robert Collins
Lalo Martins remotebranch patch
760
            except (IndexError, KeyError):
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
761
                raise bzrlib.errors.NoSuchRevision(self, revision_id)
762
        finally:
763
            self.unlock()
764
1182 by Martin Pool
- more disentangling of xml storage format from objects
765
    #deprecated
766
    get_revision_xml = get_revision_xml_file
767
1231 by Martin Pool
- more progress on fetch on top of weaves
768
    def get_revision_xml(self, revision_id):
769
        return self.get_revision_xml_file(revision_id).read()
770
771
1 by mbp at sourcefrog
import from baz patch-364
772
    def get_revision(self, revision_id):
773
        """Return the Revision object for a named revision"""
1182 by Martin Pool
- more disentangling of xml storage format from objects
774
        xml_file = self.get_revision_xml_file(revision_id)
1027 by Martin Pool
- better error message when failing to get revision from store
775
776
        try:
1189 by Martin Pool
- BROKEN: partial support for commit into weave
777
            r = bzrlib.xml5.serializer_v5.read_revision(xml_file)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
778
        except SyntaxError, e:
779
            raise bzrlib.errors.BzrError('failed to unpack revision_xml',
780
                                         [revision_id,
781
                                          str(e)])
802 by Martin Pool
- Remove XMLMixin class in favour of simple pack_xml, unpack_xml functions
782
            
1 by mbp at sourcefrog
import from baz patch-364
783
        assert r.revision_id == revision_id
784
        return r
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
785
786
    def get_revision_delta(self, revno):
787
        """Return the delta for one revision.
788
789
        The delta is relative to its mainline predecessor, or the
790
        empty tree for revision 1.
791
        """
792
        assert isinstance(revno, int)
793
        rh = self.revision_history()
794
        if not (1 <= revno <= len(rh)):
795
            raise InvalidRevisionNumber(revno)
796
797
        # revno is 1-based; list is 0-based
798
799
        new_tree = self.revision_tree(rh[revno-1])
800
        if revno == 1:
801
            old_tree = EmptyTree()
802
        else:
803
            old_tree = self.revision_tree(rh[revno-2])
804
805
        return compare_trees(old_tree, new_tree)
806
672 by Martin Pool
- revision records include the hash of their inventory and
807
    def get_revision_sha1(self, revision_id):
808
        """Hash the stored value of a revision, and return it."""
809
        # In the future, revision entries will be signed. At that
810
        # point, it is probably best *not* to include the signature
811
        # in the revision hash. Because that lets you re-sign
812
        # the revision, (add signatures/remove signatures) and still
813
        # have all hash pointers stay consistent.
814
        # But for now, just hash the contents.
1230 by Martin Pool
- remove Branch.get_revision_xml; use get_revision_xml_file instead
815
        return bzrlib.osutils.sha_file(self.get_revision_xml_file(revision_id))
672 by Martin Pool
- revision records include the hash of their inventory and
816
1225 by Martin Pool
- branch now tracks ancestry - all merged revisions
817
    def get_ancestry(self, revision_id):
1415 by Robert Collins
remove the ancestry weave file
818
        """Return a list of revision-ids integrated by a revision.
819
        
820
        This currently returns a list, but the ordering is not guaranteed:
821
        treat it as a set.
822
        """
1390 by Robert Collins
pair programming worx... merge integration and weave
823
        if revision_id is None:
824
            return [None]
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
825
        w = self.get_inventory_weave()
1415 by Robert Collins
remove the ancestry weave file
826
        return [None] + map(w.idx_to_name,
827
                            w.inclusions([w.lookup(revision_id)]))
1225 by Martin Pool
- branch now tracks ancestry - all merged revisions
828
1223 by Martin Pool
- store inventories in weave
829
    def get_inventory_weave(self):
1417.1.8 by Robert Collins
use transactions in the weave store interface, which enables caching for log
830
        return self.control_weaves.get_weave('inventory',
831
                                             self.get_transaction())
1223 by Martin Pool
- store inventories in weave
832
1192 by Martin Pool
- clean up code for retrieving stored inventories
833
    def get_inventory(self, revision_id):
1223 by Martin Pool
- store inventories in weave
834
        """Get Inventory object by hash."""
1372 by Martin Pool
- avoid converting inventories to/from StringIO
835
        xml = self.get_inventory_xml(revision_id)
836
        return bzrlib.xml5.serializer_v5.read_inventory_from_string(xml)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
837
1192 by Martin Pool
- clean up code for retrieving stored inventories
838
    def get_inventory_xml(self, revision_id):
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
839
        """Get inventory XML as a file object."""
1192 by Martin Pool
- clean up code for retrieving stored inventories
840
        try:
841
            assert isinstance(revision_id, basestring), type(revision_id)
1223 by Martin Pool
- store inventories in weave
842
            iw = self.get_inventory_weave()
843
            return iw.get_text(iw.lookup(revision_id))
1192 by Martin Pool
- clean up code for retrieving stored inventories
844
        except IndexError:
845
            raise bzrlib.errors.HistoryMissing(self, 'inventory', revision_id)
1180 by Martin Pool
- start splitting code for xml (de)serialization away from objects
846
1192 by Martin Pool
- clean up code for retrieving stored inventories
847
    def get_inventory_sha1(self, revision_id):
672 by Martin Pool
- revision records include the hash of their inventory and
848
        """Return the sha1 hash of the inventory entry
849
        """
1223 by Martin Pool
- store inventories in weave
850
        return self.get_revision(revision_id).inventory_sha1
672 by Martin Pool
- revision records include the hash of their inventory and
851
1 by mbp at sourcefrog
import from baz patch-364
852
    def get_revision_inventory(self, revision_id):
853
        """Return inventory of a past revision."""
1372 by Martin Pool
- avoid converting inventories to/from StringIO
854
        # TODO: Unify this with get_inventory()
1218 by Martin Pool
- fix up import
855
        # bzr 0.0.6 and later imposes the constraint that the inventory_id
820 by Martin Pool
- faster Branch.get_revision_inventory now we know the ids are the same
856
        # must be the same as its revision, so this is trivial.
1 by mbp at sourcefrog
import from baz patch-364
857
        if revision_id == None:
909 by Martin Pool
- merge John's code to give the tree root an explicit file id
858
            return Inventory(self.get_root_id())
1 by mbp at sourcefrog
import from baz patch-364
859
        else:
820 by Martin Pool
- faster Branch.get_revision_inventory now we know the ids are the same
860
            return self.get_inventory(revision_id)
1 by mbp at sourcefrog
import from baz patch-364
861
862
    def revision_history(self):
1295 by Martin Pool
- remove pointless doctest
863
        """Return sequence of revision hashes on to this branch."""
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
864
        self.lock_read()
865
        try:
866
            return [l.rstrip('\r\n') for l in
867
                    self.controlfile('revision-history', 'r').readlines()]
868
        finally:
869
            self.unlock()
1 by mbp at sourcefrog
import from baz patch-364
870
622 by Martin Pool
Updated merge patch from Aaron
871
    def common_ancestor(self, other, self_revno=None, other_revno=None):
872
        """
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
873
        >>> from bzrlib.commit import commit
622 by Martin Pool
Updated merge patch from Aaron
874
        >>> sb = ScratchBranch(files=['foo', 'foo~'])
875
        >>> sb.common_ancestor(sb) == (None, None)
876
        True
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
877
        >>> commit(sb, "Committing first revision", verbose=False)
622 by Martin Pool
Updated merge patch from Aaron
878
        >>> sb.common_ancestor(sb)[0]
879
        1
880
        >>> clone = sb.clone()
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
881
        >>> commit(sb, "Committing second revision", verbose=False)
622 by Martin Pool
Updated merge patch from Aaron
882
        >>> sb.common_ancestor(sb)[0]
883
        2
884
        >>> sb.common_ancestor(clone)[0]
885
        1
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
886
        >>> commit(clone, "Committing divergent second revision", 
622 by Martin Pool
Updated merge patch from Aaron
887
        ...               verbose=False)
888
        >>> sb.common_ancestor(clone)[0]
889
        1
890
        >>> sb.common_ancestor(clone) == clone.common_ancestor(sb)
891
        True
892
        >>> sb.common_ancestor(sb) != clone.common_ancestor(clone)
893
        True
894
        >>> clone2 = sb.clone()
895
        >>> sb.common_ancestor(clone2)[0]
896
        2
897
        >>> sb.common_ancestor(clone2, self_revno=1)[0]
898
        1
899
        >>> sb.common_ancestor(clone2, other_revno=1)[0]
900
        1
901
        """
902
        my_history = self.revision_history()
903
        other_history = other.revision_history()
904
        if self_revno is None:
905
            self_revno = len(my_history)
906
        if other_revno is None:
907
            other_revno = len(other_history)
908
        indices = range(min((self_revno, other_revno)))
909
        indices.reverse()
910
        for r in indices:
911
            if my_history[r] == other_history[r]:
912
                return r+1, my_history[r]
913
        return None, None
914
385 by Martin Pool
- New Branch.enum_history method
915
1 by mbp at sourcefrog
import from baz patch-364
916
    def revno(self):
917
        """Return current revision number for this branch.
918
919
        That is equivalent to the number of revisions committed to
920
        this branch.
921
        """
922
        return len(self.revision_history())
923
924
1241 by Martin Pool
- rename last_patch to last_revision
925
    def last_revision(self):
1 by mbp at sourcefrog
import from baz patch-364
926
        """Return last patch hash, or None if no history.
927
        """
928
        ph = self.revision_history()
929
        if ph:
930
            return ph[-1]
184 by mbp at sourcefrog
pychecker fixups
931
        else:
932
            return None
485 by Martin Pool
- move commit code into its own module
933
934
974.1.27 by aaron.bentley at utoronto
Initial greedy fetch work
935
    def missing_revisions(self, other, stop_revision=None, diverged_ok=False):
1260 by Martin Pool
- some updates for fetch/update function
936
        """Return a list of new revisions that would perfectly fit.
937
        
628 by Martin Pool
- merge aaron's updated merge/pull code
938
        If self and other have not diverged, return a list of the revisions
939
        present in other, but missing from self.
940
941
        >>> from bzrlib.commit import commit
942
        >>> bzrlib.trace.silent = True
943
        >>> br1 = ScratchBranch()
944
        >>> br2 = ScratchBranch()
945
        >>> br1.missing_revisions(br2)
946
        []
947
        >>> commit(br2, "lala!", rev_id="REVISION-ID-1")
948
        >>> br1.missing_revisions(br2)
949
        [u'REVISION-ID-1']
950
        >>> br2.missing_revisions(br1)
951
        []
952
        >>> commit(br1, "lala!", rev_id="REVISION-ID-1")
953
        >>> br1.missing_revisions(br2)
954
        []
955
        >>> commit(br2, "lala!", rev_id="REVISION-ID-2A")
956
        >>> br1.missing_revisions(br2)
957
        [u'REVISION-ID-2A']
958
        >>> commit(br1, "lala!", rev_id="REVISION-ID-2B")
959
        >>> br1.missing_revisions(br2)
960
        Traceback (most recent call last):
961
        DivergedBranches: These branches have diverged.
962
        """
1260 by Martin Pool
- some updates for fetch/update function
963
        # FIXME: If the branches have diverged, but the latest
964
        # revision in this branch is completely merged into the other,
965
        # then we should still be able to pull.
628 by Martin Pool
- merge aaron's updated merge/pull code
966
        self_history = self.revision_history()
967
        self_len = len(self_history)
968
        other_history = other.revision_history()
969
        other_len = len(other_history)
970
        common_index = min(self_len, other_len) -1
971
        if common_index >= 0 and \
972
            self_history[common_index] != other_history[common_index]:
973
            raise DivergedBranches(self, other)
685 by Martin Pool
- add -r option to the branch command
974
975
        if stop_revision is None:
976
            stop_revision = other_len
1273 by Martin Pool
- fix up copy_branch, etc
977
        else:
978
            assert isinstance(stop_revision, int)
979
            if stop_revision > other_len:
980
                raise bzrlib.errors.NoSuchRevision(self, stop_revision)
685 by Martin Pool
- add -r option to the branch command
981
        return other_history[self_len:stop_revision]
982
974.1.28 by aaron.bentley at utoronto
factored install_revisions out of update_revisions, updated test cases for greedy_fetch
983
    def update_revisions(self, other, stop_revision=None):
1390 by Robert Collins
pair programming worx... merge integration and weave
984
        """Pull in new perfect-fit revisions."""
974.1.33 by aaron.bentley at utoronto
Added greedy_fetch to update_revisions
985
        from bzrlib.fetch import greedy_fetch
974.1.74 by Aaron Bentley
Made pull work after remote branch has merged latest revision
986
        from bzrlib.revision import get_intervening_revisions
974.1.75 by Aaron Bentley
Sped up pull by copying locally first
987
        if stop_revision is None:
1390 by Robert Collins
pair programming worx... merge integration and weave
988
            stop_revision = other.last_revision()
1260 by Martin Pool
- some updates for fetch/update function
989
        greedy_fetch(to_branch=self, from_branch=other,
1261 by Martin Pool
- new method Branch.has_revision
990
                     revision=stop_revision)
1390 by Robert Collins
pair programming worx... merge integration and weave
991
        pullable_revs = self.missing_revisions(
992
            other, other.revision_id_to_revno(stop_revision))
1261 by Martin Pool
- new method Branch.has_revision
993
        if pullable_revs:
994
            greedy_fetch(to_branch=self,
995
                         from_branch=other,
996
                         revision=pullable_revs[-1])
997
            self.append_revision(*pullable_revs)
1390 by Robert Collins
pair programming worx... merge integration and weave
998
    
1110 by Martin Pool
- merge aaron's merge improvements:
999
485 by Martin Pool
- move commit code into its own module
1000
    def commit(self, *args, **kw):
1189 by Martin Pool
- BROKEN: partial support for commit into weave
1001
        from bzrlib.commit import Commit
1002
        Commit().commit(self, *args, **kw)
1390 by Robert Collins
pair programming worx... merge integration and weave
1003
    
1105 by Martin Pool
- expose 'find-merge-base' as a new expert command,
1004
    def revision_id_to_revno(self, revision_id):
1005
        """Given a revision id, return its revno"""
1390 by Robert Collins
pair programming worx... merge integration and weave
1006
        if revision_id is None:
1007
            return 0
1105 by Martin Pool
- expose 'find-merge-base' as a new expert command,
1008
        history = self.revision_history()
1009
        try:
1010
            return history.index(revision_id) + 1
1011
        except ValueError:
1012
            raise bzrlib.errors.NoSuchRevision(self, revision_id)
1013
974.2.7 by aaron.bentley at utoronto
Merged from bzr.24
1014
    def get_rev_id(self, revno, history=None):
1015
        """Find the revision id of the specified revno."""
1016
        if revno == 0:
1017
            return None
1018
        if history is None:
1019
            history = self.revision_history()
1020
        elif revno <= 0 or revno > len(history):
1021
            raise bzrlib.errors.NoSuchRevision(self, revno)
1022
        return history[revno - 1]
1023
1 by mbp at sourcefrog
import from baz patch-364
1024
    def revision_tree(self, revision_id):
1025
        """Return Tree for a revision on this branch.
1026
1027
        `revision_id` may be None for the null revision, in which case
1028
        an `EmptyTree` is returned."""
529 by Martin Pool
todo
1029
        # TODO: refactor this to use an existing revision object
1030
        # so we don't need to read it in twice.
1 by mbp at sourcefrog
import from baz patch-364
1031
        if revision_id == None:
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
1032
            return EmptyTree()
1 by mbp at sourcefrog
import from baz patch-364
1033
        else:
1034
            inv = self.get_revision_inventory(revision_id)
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
1035
            return RevisionTree(self.weave_store, inv, revision_id)
1 by mbp at sourcefrog
import from baz patch-364
1036
1037
1038
    def working_tree(self):
1039
        """Return a `Tree` for the working copy."""
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
1040
        from bzrlib.workingtree import WorkingTree
907.1.5 by John Arbash Meinel
Some more work, including ScratchBranch changes.
1041
        # TODO: In the future, WorkingTree should utilize Transport
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
1042
        # RobertCollins 20051003 - I don't think it should - working trees are
1043
        # much more complex to keep consistent than our careful .bzr subset.
1044
        # instead, we should say that working trees are local only, and optimise
1045
        # for that.
907.1.5 by John Arbash Meinel
Some more work, including ScratchBranch changes.
1046
        return WorkingTree(self._transport.base, self.read_working_inventory())
1 by mbp at sourcefrog
import from baz patch-364
1047
1048
1049
    def basis_tree(self):
1050
        """Return `Tree` object for last revision.
1051
1052
        If there are no revisions yet, return an `EmptyTree`.
1053
        """
1241 by Martin Pool
- rename last_patch to last_revision
1054
        return self.revision_tree(self.last_revision())
1 by mbp at sourcefrog
import from baz patch-364
1055
1056
168 by mbp at sourcefrog
new "rename" command
1057
    def rename_one(self, from_rel, to_rel):
309 by Martin Pool
doc
1058
        """Rename one file.
1059
1060
        This can change the directory or the filename or both.
353 by Martin Pool
- Per-branch locks in read and write modes.
1061
        """
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1062
        self.lock_write()
171 by mbp at sourcefrog
better error message when working file rename fails
1063
        try:
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1064
            tree = self.working_tree()
1065
            inv = tree.inventory
1066
            if not tree.has_filename(from_rel):
1067
                raise BzrError("can't rename: old working file %r does not exist" % from_rel)
1068
            if tree.has_filename(to_rel):
1069
                raise BzrError("can't rename: new working file %r already exists" % to_rel)
1070
1071
            file_id = inv.path2id(from_rel)
1072
            if file_id == None:
1073
                raise BzrError("can't rename: old name %r is not versioned" % from_rel)
1074
1075
            if inv.path2id(to_rel):
1076
                raise BzrError("can't rename: new name %r is already versioned" % to_rel)
1077
1078
            to_dir, to_tail = os.path.split(to_rel)
1079
            to_dir_id = inv.path2id(to_dir)
1080
            if to_dir_id == None and to_dir != '':
1081
                raise BzrError("can't determine destination directory id for %r" % to_dir)
1082
1083
            mutter("rename_one:")
1084
            mutter("  file_id    {%s}" % file_id)
1085
            mutter("  from_rel   %r" % from_rel)
1086
            mutter("  to_rel     %r" % to_rel)
1087
            mutter("  to_dir     %r" % to_dir)
1088
            mutter("  to_dir_id  {%s}" % to_dir_id)
1089
1090
            inv.rename(file_id, to_dir_id, to_tail)
1091
1092
            from_abs = self.abspath(from_rel)
1093
            to_abs = self.abspath(to_rel)
1094
            try:
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
1095
                rename(from_abs, to_abs)
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1096
            except OSError, e:
1097
                raise BzrError("failed to rename %r to %r: %s"
1098
                        % (from_abs, to_abs, e[1]),
1099
                        ["rename rolled back"])
1100
1101
            self._write_inventory(inv)
1102
        finally:
1103
            self.unlock()
1104
1105
174 by mbp at sourcefrog
- New 'move' command; now separated out from rename
1106
    def move(self, from_paths, to_name):
160 by mbp at sourcefrog
- basic support for moving files to different directories - have not done support for renaming them yet, but should be straightforward - some tests, but many cases are not handled yet i think
1107
        """Rename files.
1108
174 by mbp at sourcefrog
- New 'move' command; now separated out from rename
1109
        to_name must exist as a versioned directory.
1110
160 by mbp at sourcefrog
- basic support for moving files to different directories - have not done support for renaming them yet, but should be straightforward - some tests, but many cases are not handled yet i think
1111
        If to_name exists and is a directory, the files are moved into
1112
        it, keeping their old names.  If it is a directory, 
1113
1114
        Note that to_name is only the last component of the new name;
1115
        this doesn't change the directory.
1131 by Martin Pool
- remove more extraneous print statements from Branch.move
1116
1117
        This returns a list of (from_path, to_path) pairs for each
1118
        entry that is moved.
160 by mbp at sourcefrog
- basic support for moving files to different directories - have not done support for renaming them yet, but should be straightforward - some tests, but many cases are not handled yet i think
1119
        """
1131 by Martin Pool
- remove more extraneous print statements from Branch.move
1120
        result = []
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1121
        self.lock_write()
1122
        try:
1123
            ## TODO: Option to move IDs only
1124
            assert not isinstance(from_paths, basestring)
1125
            tree = self.working_tree()
1126
            inv = tree.inventory
1127
            to_abs = self.abspath(to_name)
1128
            if not isdir(to_abs):
1129
                raise BzrError("destination %r is not a directory" % to_abs)
1130
            if not tree.has_filename(to_name):
1131
                raise BzrError("destination %r not in working directory" % to_abs)
1132
            to_dir_id = inv.path2id(to_name)
1133
            if to_dir_id == None and to_name != '':
1134
                raise BzrError("destination %r is not a versioned directory" % to_name)
1135
            to_dir_ie = inv[to_dir_id]
1136
            if to_dir_ie.kind not in ('directory', 'root_directory'):
1137
                raise BzrError("destination %r is not a directory" % to_abs)
1138
1139
            to_idpath = inv.get_idpath(to_dir_id)
1140
1141
            for f in from_paths:
1142
                if not tree.has_filename(f):
1143
                    raise BzrError("%r does not exist in working tree" % f)
1144
                f_id = inv.path2id(f)
1145
                if f_id == None:
1146
                    raise BzrError("%r is not versioned" % f)
1147
                name_tail = splitpath(f)[-1]
1148
                dest_path = appendpath(to_name, name_tail)
1149
                if tree.has_filename(dest_path):
1150
                    raise BzrError("destination %r already exists" % dest_path)
1151
                if f_id in to_idpath:
1152
                    raise BzrError("can't move %r to a subdirectory of itself" % f)
1153
1154
            # OK, so there's a race here, it's possible that someone will
1155
            # create a file in this interval and then the rename might be
1156
            # left half-done.  But we should have caught most problems.
1157
1158
            for f in from_paths:
1159
                name_tail = splitpath(f)[-1]
1160
                dest_path = appendpath(to_name, name_tail)
1131 by Martin Pool
- remove more extraneous print statements from Branch.move
1161
                result.append((f, dest_path))
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1162
                inv.rename(inv.path2id(f), to_dir_id, name_tail)
1163
                try:
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
1164
                    rename(self.abspath(f), self.abspath(dest_path))
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1165
                except OSError, e:
1166
                    raise BzrError("failed to rename %r to %r: %s" % (f, dest_path, e[1]),
1167
                            ["rename rolled back"])
1168
1169
            self._write_inventory(inv)
1170
        finally:
1171
            self.unlock()
160 by mbp at sourcefrog
- basic support for moving files to different directories - have not done support for renaming them yet, but should be straightforward - some tests, but many cases are not handled yet i think
1172
1131 by Martin Pool
- remove more extraneous print statements from Branch.move
1173
        return result
1174
160 by mbp at sourcefrog
- basic support for moving files to different directories - have not done support for renaming them yet, but should be straightforward - some tests, but many cases are not handled yet i think
1175
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1176
    def revert(self, filenames, old_tree=None, backups=True):
778 by Martin Pool
- simple revert of text files
1177
        """Restore selected files to the versions from a previous tree.
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1178
1179
        backups
1180
            If true (default) backups are made of files before
1181
            they're renamed.
778 by Martin Pool
- simple revert of text files
1182
        """
1183
        from bzrlib.errors import NotVersionedError, BzrError
1184
        from bzrlib.atomicfile import AtomicFile
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1185
        from bzrlib.osutils import backup_file
778 by Martin Pool
- simple revert of text files
1186
        
1187
        inv = self.read_working_inventory()
1188
        if old_tree is None:
1189
            old_tree = self.basis_tree()
1190
        old_inv = old_tree.inventory
1191
1192
        nids = []
1193
        for fn in filenames:
1194
            file_id = inv.path2id(fn)
1195
            if not file_id:
1196
                raise NotVersionedError("not a versioned file", fn)
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1197
            if not old_inv.has_id(file_id):
1198
                raise BzrError("file not present in old tree", fn, file_id)
778 by Martin Pool
- simple revert of text files
1199
            nids.append((fn, file_id))
1200
            
1201
        # TODO: Rename back if it was previously at a different location
1202
1203
        # TODO: If given a directory, restore the entire contents from
1204
        # the previous version.
1205
1206
        # TODO: Make a backup to a temporary file.
1207
1208
        # TODO: If the file previously didn't exist, delete it?
1209
        for fn, file_id in nids:
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1210
            backup_file(fn)
1211
            
778 by Martin Pool
- simple revert of text files
1212
            f = AtomicFile(fn, 'wb')
1213
            try:
1214
                f.write(old_tree.get_file(file_id).read())
1215
                f.commit()
1216
            finally:
1217
                f.close()
1218
1219
815 by Martin Pool
- track pending-merges
1220
    def pending_merges(self):
1221
        """Return a list of pending merges.
1222
1223
        These are revisions that have been merged into the working
1224
        directory but not yet committed.
1225
        """
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
1226
        cfn = self._rel_controlfilename('pending-merges')
907.1.8 by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport
1227
        if not self._transport.has(cfn):
815 by Martin Pool
- track pending-merges
1228
            return []
1229
        p = []
1230
        for l in self.controlfile('pending-merges', 'r').readlines():
1231
            p.append(l.rstrip('\n'))
1232
        return p
1233
1234
907.1.4 by John Arbash Meinel
Add pending_merge can take multiple entries.
1235
    def add_pending_merge(self, *revision_ids):
1263 by Martin Pool
- clean up imports
1236
        # TODO: Perhaps should check at this point that the
1237
        # history of the revision is actually present?
815 by Martin Pool
- track pending-merges
1238
        p = self.pending_merges()
907.1.4 by John Arbash Meinel
Add pending_merge can take multiple entries.
1239
        updated = False
1240
        for rev_id in revision_ids:
1241
            if rev_id in p:
1242
                continue
1243
            p.append(rev_id)
1244
            updated = True
1245
        if updated:
1246
            self.set_pending_merges(p)
815 by Martin Pool
- track pending-merges
1247
1248
    def set_pending_merges(self, rev_list):
1249
        self.lock_write()
1250
        try:
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
1251
            self.put_controlfile('pending-merges', '\n'.join(rev_list))
815 by Martin Pool
- track pending-merges
1252
        finally:
1253
            self.unlock()
1254
1255
1149 by Martin Pool
- make get_parent() be a method of Branch; add simple tests for it
1256
    def get_parent(self):
1257
        """Return the parent location of the branch.
1258
1259
        This is the default location for push/pull/missing.  The usual
1260
        pattern is that the user can override it by specifying a
1261
        location.
1262
        """
1263
        import errno
1264
        _locs = ['parent', 'pull', 'x-pull']
1265
        for l in _locs:
1266
            try:
1267
                return self.controlfile(l, 'r').read().strip('\n')
1268
            except IOError, e:
1269
                if e.errno != errno.ENOENT:
1270
                    raise
1271
        return None
1272
1150 by Martin Pool
- add new Branch.set_parent and tests
1273
1274
    def set_parent(self, url):
1275
        # TODO: Maybe delete old location files?
1276
        from bzrlib.atomicfile import AtomicFile
1277
        self.lock_write()
1278
        try:
1279
            f = AtomicFile(self.controlfilename('parent'))
1280
            try:
1281
                f.write(url + '\n')
1282
                f.commit()
1283
            finally:
1284
                f.close()
1285
        finally:
1286
            self.unlock()
1287
974.1.54 by aaron.bentley at utoronto
Fixed the revno bug in log
1288
    def check_revno(self, revno):
1289
        """\
1290
        Check whether a revno corresponds to any revision.
1291
        Zero (the NULL revision) is considered valid.
1292
        """
1293
        if revno != 0:
1294
            self.check_real_revno(revno)
1295
            
1296
    def check_real_revno(self, revno):
1297
        """\
1298
        Check whether a revno corresponds to a real revision.
1299
        Zero (the NULL revision) is considered invalid
1300
        """
1301
        if revno < 1 or revno > self.revno():
1302
            raise InvalidRevisionNumber(revno)
1303
        
1149 by Martin Pool
- make get_parent() be a method of Branch; add simple tests for it
1304
        
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
1305
        
1306
1307
1185.11.11 by John Arbash Meinel
Removing the remotebranch object.
1308
class ScratchBranch(_Branch):
1 by mbp at sourcefrog
import from baz patch-364
1309
    """Special test class: a branch that cleans up after itself.
1310
1311
    >>> b = ScratchBranch()
1312
    >>> isdir(b.base)
1313
    True
1314
    >>> bd = b.base
396 by Martin Pool
- Using the destructor on a ScratchBranch is not reliable;
1315
    >>> b.destroy()
1 by mbp at sourcefrog
import from baz patch-364
1316
    >>> isdir(bd)
1317
    False
1318
    """
622 by Martin Pool
Updated merge patch from Aaron
1319
    def __init__(self, files=[], dirs=[], base=None):
1 by mbp at sourcefrog
import from baz patch-364
1320
        """Make a test branch.
1321
1322
        This creates a temporary directory and runs init-tree in it.
1323
1324
        If any files are listed, they are created in the working copy.
1325
        """
800 by Martin Pool
Merge John's import-speedup branch:
1326
        from tempfile import mkdtemp
622 by Martin Pool
Updated merge patch from Aaron
1327
        init = False
1328
        if base is None:
800 by Martin Pool
Merge John's import-speedup branch:
1329
            base = mkdtemp()
622 by Martin Pool
Updated merge patch from Aaron
1330
            init = True
1393.2.4 by John Arbash Meinel
All tests pass.
1331
        if isinstance(base, basestring):
1332
            base = get_transport(base)
1185.11.11 by John Arbash Meinel
Removing the remotebranch object.
1333
        _Branch.__init__(self, base, init=init)
100 by mbp at sourcefrog
- add test case for ignore files
1334
        for d in dirs:
907.1.8 by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport
1335
            self._transport.mkdir(d)
100 by mbp at sourcefrog
- add test case for ignore files
1336
            
1 by mbp at sourcefrog
import from baz patch-364
1337
        for f in files:
907.1.8 by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport
1338
            self._transport.put(f, 'content of %s' % f)
1 by mbp at sourcefrog
import from baz patch-364
1339
1340
622 by Martin Pool
Updated merge patch from Aaron
1341
    def clone(self):
1342
        """
1343
        >>> orig = ScratchBranch(files=["file1", "file2"])
1344
        >>> clone = orig.clone()
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
1345
        >>> if os.name != 'nt':
1346
        ...   os.path.samefile(orig.base, clone.base)
1347
        ... else:
1348
        ...   orig.base == clone.base
1349
        ...
622 by Martin Pool
Updated merge patch from Aaron
1350
        False
1351
        >>> os.path.isfile(os.path.join(clone.base, "file1"))
1352
        True
1353
        """
800 by Martin Pool
Merge John's import-speedup branch:
1354
        from shutil import copytree
1355
        from tempfile import mkdtemp
1356
        base = mkdtemp()
622 by Martin Pool
Updated merge patch from Aaron
1357
        os.rmdir(base)
800 by Martin Pool
Merge John's import-speedup branch:
1358
        copytree(self.base, base, symlinks=True)
622 by Martin Pool
Updated merge patch from Aaron
1359
        return ScratchBranch(base=base)
1149 by Martin Pool
- make get_parent() be a method of Branch; add simple tests for it
1360
1 by mbp at sourcefrog
import from baz patch-364
1361
    def __del__(self):
396 by Martin Pool
- Using the destructor on a ScratchBranch is not reliable;
1362
        self.destroy()
1363
1364
    def destroy(self):
1 by mbp at sourcefrog
import from baz patch-364
1365
        """Destroy the test branch, removing the scratch directory."""
800 by Martin Pool
Merge John's import-speedup branch:
1366
        from shutil import rmtree
163 by mbp at sourcefrog
merge win32 portability fixes
1367
        try:
610 by Martin Pool
- replace Branch.lock(mode) with separate lock_read and lock_write
1368
            if self.base:
1369
                mutter("delete ScratchBranch %s" % self.base)
800 by Martin Pool
Merge John's import-speedup branch:
1370
                rmtree(self.base)
396 by Martin Pool
- Using the destructor on a ScratchBranch is not reliable;
1371
        except OSError, e:
163 by mbp at sourcefrog
merge win32 portability fixes
1372
            # Work around for shutil.rmtree failing on Windows when
1373
            # readonly files are encountered
396 by Martin Pool
- Using the destructor on a ScratchBranch is not reliable;
1374
            mutter("hit exception in destroying ScratchBranch: %s" % e)
163 by mbp at sourcefrog
merge win32 portability fixes
1375
            for root, dirs, files in os.walk(self.base, topdown=False):
1376
                for name in files:
1377
                    os.chmod(os.path.join(root, name), 0700)
800 by Martin Pool
Merge John's import-speedup branch:
1378
            rmtree(self.base)
907.1.19 by John Arbash Meinel
Updated ScratchBranch and Branch.base, All Tests PASS !!!
1379
        self._transport = None
1 by mbp at sourcefrog
import from baz patch-364
1380
1381
    
1382
1383
######################################################################
1384
# predicates
1385
1386
1387
def is_control_file(filename):
1388
    ## FIXME: better check
1389
    filename = os.path.normpath(filename)
1390
    while filename != '':
1391
        head, tail = os.path.split(filename)
1392
        ## mutter('check %r for control file' % ((head, tail), ))
1393
        if tail == bzrlib.BZRDIR:
1394
            return True
70 by mbp at sourcefrog
Prepare for smart recursive add.
1395
        if filename == head:
1396
            break
1 by mbp at sourcefrog
import from baz patch-364
1397
        filename = head
1398
    return False
1399
1400
1401
70 by mbp at sourcefrog
Prepare for smart recursive add.
1402
def gen_file_id(name):
1 by mbp at sourcefrog
import from baz patch-364
1403
    """Return new file id.
1404
1405
    This should probably generate proper UUIDs, but for the moment we
1406
    cope with just randomness because running uuidgen every time is
1407
    slow."""
535 by Martin Pool
- try to eliminate wierd characters from file names when they're
1408
    import re
800 by Martin Pool
Merge John's import-speedup branch:
1409
    from binascii import hexlify
1410
    from time import time
535 by Martin Pool
- try to eliminate wierd characters from file names when they're
1411
1412
    # get last component
70 by mbp at sourcefrog
Prepare for smart recursive add.
1413
    idx = name.rfind('/')
1414
    if idx != -1:
1415
        name = name[idx+1 : ]
262 by Martin Pool
- gen_file_id: break the file on either / or \ when looking
1416
    idx = name.rfind('\\')
1417
    if idx != -1:
1418
        name = name[idx+1 : ]
70 by mbp at sourcefrog
Prepare for smart recursive add.
1419
535 by Martin Pool
- try to eliminate wierd characters from file names when they're
1420
    # make it not a hidden file
70 by mbp at sourcefrog
Prepare for smart recursive add.
1421
    name = name.lstrip('.')
1422
535 by Martin Pool
- try to eliminate wierd characters from file names when they're
1423
    # remove any wierd characters; we don't escape them but rather
1424
    # just pull them out
1425
    name = re.sub(r'[^\w.]', '', name)
1426
190 by mbp at sourcefrog
64 bits of randomness in file/revision ids
1427
    s = hexlify(rand_bytes(8))
800 by Martin Pool
Merge John's import-speedup branch:
1428
    return '-'.join((name, compact_date(time()), s))
909 by Martin Pool
- merge John's code to give the tree root an explicit file id
1429
1430
1431
def gen_root_id():
1432
    """Return a new tree-root file id."""
1433
    return gen_file_id('TREE_ROOT')
1434
1092.1.34 by Robert Collins
unbreak cmd_branch now that something tests the core of it..
1435