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