~bzr-pqm/bzr/bzr.dev

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