/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
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]
1415 by Robert Collins
remove the ancestry weave file
824
        w = self.control_weaves.get_weave('inventory')
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):
1352 by Martin Pool
- store control weaves in .bzr/, not mixed in with file weaves
829
        return self.control_weaves.get_weave('inventory')
1223 by Martin Pool
- store inventories in weave
830
1192 by Martin Pool
- clean up code for retrieving stored inventories
831
    def get_inventory(self, revision_id):
1223 by Martin Pool
- store inventories in weave
832
        """Get Inventory object by hash."""
1372 by Martin Pool
- avoid converting inventories to/from StringIO
833
        xml = self.get_inventory_xml(revision_id)
834
        return bzrlib.xml5.serializer_v5.read_inventory_from_string(xml)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
835
1192 by Martin Pool
- clean up code for retrieving stored inventories
836
    def get_inventory_xml(self, revision_id):
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
837
        """Get inventory XML as a file object."""
1192 by Martin Pool
- clean up code for retrieving stored inventories
838
        try:
839
            assert isinstance(revision_id, basestring), type(revision_id)
1223 by Martin Pool
- store inventories in weave
840
            iw = self.get_inventory_weave()
841
            return iw.get_text(iw.lookup(revision_id))
1192 by Martin Pool
- clean up code for retrieving stored inventories
842
        except IndexError:
843
            raise bzrlib.errors.HistoryMissing(self, 'inventory', revision_id)
1180 by Martin Pool
- start splitting code for xml (de)serialization away from objects
844
1192 by Martin Pool
- clean up code for retrieving stored inventories
845
    def get_inventory_sha1(self, revision_id):
672 by Martin Pool
- revision records include the hash of their inventory and
846
        """Return the sha1 hash of the inventory entry
847
        """
1223 by Martin Pool
- store inventories in weave
848
        return self.get_revision(revision_id).inventory_sha1
672 by Martin Pool
- revision records include the hash of their inventory and
849
1 by mbp at sourcefrog
import from baz patch-364
850
    def get_revision_inventory(self, revision_id):
851
        """Return inventory of a past revision."""
1372 by Martin Pool
- avoid converting inventories to/from StringIO
852
        # TODO: Unify this with get_inventory()
1218 by Martin Pool
- fix up import
853
        # 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
854
        # must be the same as its revision, so this is trivial.
1 by mbp at sourcefrog
import from baz patch-364
855
        if revision_id == None:
909 by Martin Pool
- merge John's code to give the tree root an explicit file id
856
            return Inventory(self.get_root_id())
1 by mbp at sourcefrog
import from baz patch-364
857
        else:
820 by Martin Pool
- faster Branch.get_revision_inventory now we know the ids are the same
858
            return self.get_inventory(revision_id)
1 by mbp at sourcefrog
import from baz patch-364
859
860
    def revision_history(self):
1295 by Martin Pool
- remove pointless doctest
861
        """Return sequence of revision hashes on to this branch."""
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
862
        self.lock_read()
863
        try:
864
            return [l.rstrip('\r\n') for l in
865
                    self.controlfile('revision-history', 'r').readlines()]
866
        finally:
867
            self.unlock()
1 by mbp at sourcefrog
import from baz patch-364
868
622 by Martin Pool
Updated merge patch from Aaron
869
    def common_ancestor(self, other, self_revno=None, other_revno=None):
870
        """
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
871
        >>> from bzrlib.commit import commit
622 by Martin Pool
Updated merge patch from Aaron
872
        >>> sb = ScratchBranch(files=['foo', 'foo~'])
873
        >>> sb.common_ancestor(sb) == (None, None)
874
        True
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
875
        >>> commit(sb, "Committing first revision", verbose=False)
622 by Martin Pool
Updated merge patch from Aaron
876
        >>> sb.common_ancestor(sb)[0]
877
        1
878
        >>> clone = sb.clone()
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
879
        >>> commit(sb, "Committing second revision", verbose=False)
622 by Martin Pool
Updated merge patch from Aaron
880
        >>> sb.common_ancestor(sb)[0]
881
        2
882
        >>> sb.common_ancestor(clone)[0]
883
        1
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
884
        >>> commit(clone, "Committing divergent second revision", 
622 by Martin Pool
Updated merge patch from Aaron
885
        ...               verbose=False)
886
        >>> sb.common_ancestor(clone)[0]
887
        1
888
        >>> sb.common_ancestor(clone) == clone.common_ancestor(sb)
889
        True
890
        >>> sb.common_ancestor(sb) != clone.common_ancestor(clone)
891
        True
892
        >>> clone2 = sb.clone()
893
        >>> sb.common_ancestor(clone2)[0]
894
        2
895
        >>> sb.common_ancestor(clone2, self_revno=1)[0]
896
        1
897
        >>> sb.common_ancestor(clone2, other_revno=1)[0]
898
        1
899
        """
900
        my_history = self.revision_history()
901
        other_history = other.revision_history()
902
        if self_revno is None:
903
            self_revno = len(my_history)
904
        if other_revno is None:
905
            other_revno = len(other_history)
906
        indices = range(min((self_revno, other_revno)))
907
        indices.reverse()
908
        for r in indices:
909
            if my_history[r] == other_history[r]:
910
                return r+1, my_history[r]
911
        return None, None
912
385 by Martin Pool
- New Branch.enum_history method
913
1 by mbp at sourcefrog
import from baz patch-364
914
    def revno(self):
915
        """Return current revision number for this branch.
916
917
        That is equivalent to the number of revisions committed to
918
        this branch.
919
        """
920
        return len(self.revision_history())
921
922
1241 by Martin Pool
- rename last_patch to last_revision
923
    def last_revision(self):
1 by mbp at sourcefrog
import from baz patch-364
924
        """Return last patch hash, or None if no history.
925
        """
926
        ph = self.revision_history()
927
        if ph:
928
            return ph[-1]
184 by mbp at sourcefrog
pychecker fixups
929
        else:
930
            return None
485 by Martin Pool
- move commit code into its own module
931
932
974.1.27 by aaron.bentley at utoronto
Initial greedy fetch work
933
    def missing_revisions(self, other, stop_revision=None, diverged_ok=False):
1260 by Martin Pool
- some updates for fetch/update function
934
        """Return a list of new revisions that would perfectly fit.
935
        
628 by Martin Pool
- merge aaron's updated merge/pull code
936
        If self and other have not diverged, return a list of the revisions
937
        present in other, but missing from self.
938
939
        >>> from bzrlib.commit import commit
940
        >>> bzrlib.trace.silent = True
941
        >>> br1 = ScratchBranch()
942
        >>> br2 = ScratchBranch()
943
        >>> br1.missing_revisions(br2)
944
        []
945
        >>> commit(br2, "lala!", rev_id="REVISION-ID-1")
946
        >>> br1.missing_revisions(br2)
947
        [u'REVISION-ID-1']
948
        >>> br2.missing_revisions(br1)
949
        []
950
        >>> commit(br1, "lala!", rev_id="REVISION-ID-1")
951
        >>> br1.missing_revisions(br2)
952
        []
953
        >>> commit(br2, "lala!", rev_id="REVISION-ID-2A")
954
        >>> br1.missing_revisions(br2)
955
        [u'REVISION-ID-2A']
956
        >>> commit(br1, "lala!", rev_id="REVISION-ID-2B")
957
        >>> br1.missing_revisions(br2)
958
        Traceback (most recent call last):
959
        DivergedBranches: These branches have diverged.
960
        """
1260 by Martin Pool
- some updates for fetch/update function
961
        # FIXME: If the branches have diverged, but the latest
962
        # revision in this branch is completely merged into the other,
963
        # then we should still be able to pull.
628 by Martin Pool
- merge aaron's updated merge/pull code
964
        self_history = self.revision_history()
965
        self_len = len(self_history)
966
        other_history = other.revision_history()
967
        other_len = len(other_history)
968
        common_index = min(self_len, other_len) -1
969
        if common_index >= 0 and \
970
            self_history[common_index] != other_history[common_index]:
971
            raise DivergedBranches(self, other)
685 by Martin Pool
- add -r option to the branch command
972
973
        if stop_revision is None:
974
            stop_revision = other_len
1273 by Martin Pool
- fix up copy_branch, etc
975
        else:
976
            assert isinstance(stop_revision, int)
977
            if stop_revision > other_len:
978
                raise bzrlib.errors.NoSuchRevision(self, stop_revision)
685 by Martin Pool
- add -r option to the branch command
979
        return other_history[self_len:stop_revision]
980
974.1.28 by aaron.bentley at utoronto
factored install_revisions out of update_revisions, updated test cases for greedy_fetch
981
    def update_revisions(self, other, stop_revision=None):
1390 by Robert Collins
pair programming worx... merge integration and weave
982
        """Pull in new perfect-fit revisions."""
974.1.33 by aaron.bentley at utoronto
Added greedy_fetch to update_revisions
983
        from bzrlib.fetch import greedy_fetch
974.1.74 by Aaron Bentley
Made pull work after remote branch has merged latest revision
984
        from bzrlib.revision import get_intervening_revisions
974.1.75 by Aaron Bentley
Sped up pull by copying locally first
985
        if stop_revision is None:
1390 by Robert Collins
pair programming worx... merge integration and weave
986
            stop_revision = other.last_revision()
1260 by Martin Pool
- some updates for fetch/update function
987
        greedy_fetch(to_branch=self, from_branch=other,
1261 by Martin Pool
- new method Branch.has_revision
988
                     revision=stop_revision)
1390 by Robert Collins
pair programming worx... merge integration and weave
989
        pullable_revs = self.missing_revisions(
990
            other, other.revision_id_to_revno(stop_revision))
1261 by Martin Pool
- new method Branch.has_revision
991
        if pullable_revs:
992
            greedy_fetch(to_branch=self,
993
                         from_branch=other,
994
                         revision=pullable_revs[-1])
995
            self.append_revision(*pullable_revs)
1390 by Robert Collins
pair programming worx... merge integration and weave
996
    
1110 by Martin Pool
- merge aaron's merge improvements:
997
485 by Martin Pool
- move commit code into its own module
998
    def commit(self, *args, **kw):
1189 by Martin Pool
- BROKEN: partial support for commit into weave
999
        from bzrlib.commit import Commit
1000
        Commit().commit(self, *args, **kw)
1390 by Robert Collins
pair programming worx... merge integration and weave
1001
    
1105 by Martin Pool
- expose 'find-merge-base' as a new expert command,
1002
    def revision_id_to_revno(self, revision_id):
1003
        """Given a revision id, return its revno"""
1390 by Robert Collins
pair programming worx... merge integration and weave
1004
        if revision_id is None:
1005
            return 0
1105 by Martin Pool
- expose 'find-merge-base' as a new expert command,
1006
        history = self.revision_history()
1007
        try:
1008
            return history.index(revision_id) + 1
1009
        except ValueError:
1010
            raise bzrlib.errors.NoSuchRevision(self, revision_id)
1011
974.2.7 by aaron.bentley at utoronto
Merged from bzr.24
1012
    def get_rev_id(self, revno, history=None):
1013
        """Find the revision id of the specified revno."""
1014
        if revno == 0:
1015
            return None
1016
        if history is None:
1017
            history = self.revision_history()
1018
        elif revno <= 0 or revno > len(history):
1019
            raise bzrlib.errors.NoSuchRevision(self, revno)
1020
        return history[revno - 1]
1021
1 by mbp at sourcefrog
import from baz patch-364
1022
    def revision_tree(self, revision_id):
1023
        """Return Tree for a revision on this branch.
1024
1025
        `revision_id` may be None for the null revision, in which case
1026
        an `EmptyTree` is returned."""
529 by Martin Pool
todo
1027
        # TODO: refactor this to use an existing revision object
1028
        # so we don't need to read it in twice.
1 by mbp at sourcefrog
import from baz patch-364
1029
        if revision_id == None:
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
1030
            return EmptyTree()
1 by mbp at sourcefrog
import from baz patch-364
1031
        else:
1032
            inv = self.get_revision_inventory(revision_id)
1196 by Martin Pool
- [WIP] retrieve historical texts from weaves
1033
            return RevisionTree(self.weave_store, inv, revision_id)
1 by mbp at sourcefrog
import from baz patch-364
1034
1035
1036
    def working_tree(self):
1037
        """Return a `Tree` for the working copy."""
1185.2.2 by Lalo Martins
cleaning up and refactoring the branch module.
1038
        from bzrlib.workingtree import WorkingTree
907.1.5 by John Arbash Meinel
Some more work, including ScratchBranch changes.
1039
        # TODO: In the future, WorkingTree should utilize Transport
1399.1.2 by Robert Collins
push kind character creation into InventoryEntry and TreeEntry
1040
        # RobertCollins 20051003 - I don't think it should - working trees are
1041
        # much more complex to keep consistent than our careful .bzr subset.
1042
        # instead, we should say that working trees are local only, and optimise
1043
        # for that.
907.1.5 by John Arbash Meinel
Some more work, including ScratchBranch changes.
1044
        return WorkingTree(self._transport.base, self.read_working_inventory())
1 by mbp at sourcefrog
import from baz patch-364
1045
1046
1047
    def basis_tree(self):
1048
        """Return `Tree` object for last revision.
1049
1050
        If there are no revisions yet, return an `EmptyTree`.
1051
        """
1241 by Martin Pool
- rename last_patch to last_revision
1052
        return self.revision_tree(self.last_revision())
1 by mbp at sourcefrog
import from baz patch-364
1053
1054
168 by mbp at sourcefrog
new "rename" command
1055
    def rename_one(self, from_rel, to_rel):
309 by Martin Pool
doc
1056
        """Rename one file.
1057
1058
        This can change the directory or the filename or both.
353 by Martin Pool
- Per-branch locks in read and write modes.
1059
        """
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1060
        self.lock_write()
171 by mbp at sourcefrog
better error message when working file rename fails
1061
        try:
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1062
            tree = self.working_tree()
1063
            inv = tree.inventory
1064
            if not tree.has_filename(from_rel):
1065
                raise BzrError("can't rename: old working file %r does not exist" % from_rel)
1066
            if tree.has_filename(to_rel):
1067
                raise BzrError("can't rename: new working file %r already exists" % to_rel)
1068
1069
            file_id = inv.path2id(from_rel)
1070
            if file_id == None:
1071
                raise BzrError("can't rename: old name %r is not versioned" % from_rel)
1072
1073
            if inv.path2id(to_rel):
1074
                raise BzrError("can't rename: new name %r is already versioned" % to_rel)
1075
1076
            to_dir, to_tail = os.path.split(to_rel)
1077
            to_dir_id = inv.path2id(to_dir)
1078
            if to_dir_id == None and to_dir != '':
1079
                raise BzrError("can't determine destination directory id for %r" % to_dir)
1080
1081
            mutter("rename_one:")
1082
            mutter("  file_id    {%s}" % file_id)
1083
            mutter("  from_rel   %r" % from_rel)
1084
            mutter("  to_rel     %r" % to_rel)
1085
            mutter("  to_dir     %r" % to_dir)
1086
            mutter("  to_dir_id  {%s}" % to_dir_id)
1087
1088
            inv.rename(file_id, to_dir_id, to_tail)
1089
1090
            from_abs = self.abspath(from_rel)
1091
            to_abs = self.abspath(to_rel)
1092
            try:
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
1093
                rename(from_abs, to_abs)
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1094
            except OSError, e:
1095
                raise BzrError("failed to rename %r to %r: %s"
1096
                        % (from_abs, to_abs, e[1]),
1097
                        ["rename rolled back"])
1098
1099
            self._write_inventory(inv)
1100
        finally:
1101
            self.unlock()
1102
1103
174 by mbp at sourcefrog
- New 'move' command; now separated out from rename
1104
    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
1105
        """Rename files.
1106
174 by mbp at sourcefrog
- New 'move' command; now separated out from rename
1107
        to_name must exist as a versioned directory.
1108
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
1109
        If to_name exists and is a directory, the files are moved into
1110
        it, keeping their old names.  If it is a directory, 
1111
1112
        Note that to_name is only the last component of the new name;
1113
        this doesn't change the directory.
1131 by Martin Pool
- remove more extraneous print statements from Branch.move
1114
1115
        This returns a list of (from_path, to_path) pairs for each
1116
        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
1117
        """
1131 by Martin Pool
- remove more extraneous print statements from Branch.move
1118
        result = []
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1119
        self.lock_write()
1120
        try:
1121
            ## TODO: Option to move IDs only
1122
            assert not isinstance(from_paths, basestring)
1123
            tree = self.working_tree()
1124
            inv = tree.inventory
1125
            to_abs = self.abspath(to_name)
1126
            if not isdir(to_abs):
1127
                raise BzrError("destination %r is not a directory" % to_abs)
1128
            if not tree.has_filename(to_name):
1129
                raise BzrError("destination %r not in working directory" % to_abs)
1130
            to_dir_id = inv.path2id(to_name)
1131
            if to_dir_id == None and to_name != '':
1132
                raise BzrError("destination %r is not a versioned directory" % to_name)
1133
            to_dir_ie = inv[to_dir_id]
1134
            if to_dir_ie.kind not in ('directory', 'root_directory'):
1135
                raise BzrError("destination %r is not a directory" % to_abs)
1136
1137
            to_idpath = inv.get_idpath(to_dir_id)
1138
1139
            for f in from_paths:
1140
                if not tree.has_filename(f):
1141
                    raise BzrError("%r does not exist in working tree" % f)
1142
                f_id = inv.path2id(f)
1143
                if f_id == None:
1144
                    raise BzrError("%r is not versioned" % f)
1145
                name_tail = splitpath(f)[-1]
1146
                dest_path = appendpath(to_name, name_tail)
1147
                if tree.has_filename(dest_path):
1148
                    raise BzrError("destination %r already exists" % dest_path)
1149
                if f_id in to_idpath:
1150
                    raise BzrError("can't move %r to a subdirectory of itself" % f)
1151
1152
            # OK, so there's a race here, it's possible that someone will
1153
            # create a file in this interval and then the rename might be
1154
            # left half-done.  But we should have caught most problems.
1155
1156
            for f in from_paths:
1157
                name_tail = splitpath(f)[-1]
1158
                dest_path = appendpath(to_name, name_tail)
1131 by Martin Pool
- remove more extraneous print statements from Branch.move
1159
                result.append((f, dest_path))
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1160
                inv.rename(inv.path2id(f), to_dir_id, name_tail)
1161
                try:
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
1162
                    rename(self.abspath(f), self.abspath(dest_path))
611 by Martin Pool
- remove @with_writelock, @with_readlock decorators
1163
                except OSError, e:
1164
                    raise BzrError("failed to rename %r to %r: %s" % (f, dest_path, e[1]),
1165
                            ["rename rolled back"])
1166
1167
            self._write_inventory(inv)
1168
        finally:
1169
            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
1170
1131 by Martin Pool
- remove more extraneous print statements from Branch.move
1171
        return result
1172
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
1173
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1174
    def revert(self, filenames, old_tree=None, backups=True):
778 by Martin Pool
- simple revert of text files
1175
        """Restore selected files to the versions from a previous tree.
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1176
1177
        backups
1178
            If true (default) backups are made of files before
1179
            they're renamed.
778 by Martin Pool
- simple revert of text files
1180
        """
1181
        from bzrlib.errors import NotVersionedError, BzrError
1182
        from bzrlib.atomicfile import AtomicFile
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1183
        from bzrlib.osutils import backup_file
778 by Martin Pool
- simple revert of text files
1184
        
1185
        inv = self.read_working_inventory()
1186
        if old_tree is None:
1187
            old_tree = self.basis_tree()
1188
        old_inv = old_tree.inventory
1189
1190
        nids = []
1191
        for fn in filenames:
1192
            file_id = inv.path2id(fn)
1193
            if not file_id:
1194
                raise NotVersionedError("not a versioned file", fn)
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1195
            if not old_inv.has_id(file_id):
1196
                raise BzrError("file not present in old tree", fn, file_id)
778 by Martin Pool
- simple revert of text files
1197
            nids.append((fn, file_id))
1198
            
1199
        # TODO: Rename back if it was previously at a different location
1200
1201
        # TODO: If given a directory, restore the entire contents from
1202
        # the previous version.
1203
1204
        # TODO: Make a backup to a temporary file.
1205
1206
        # TODO: If the file previously didn't exist, delete it?
1207
        for fn, file_id in nids:
782 by Martin Pool
- Branch.revert copies files to backups before reverting them
1208
            backup_file(fn)
1209
            
778 by Martin Pool
- simple revert of text files
1210
            f = AtomicFile(fn, 'wb')
1211
            try:
1212
                f.write(old_tree.get_file(file_id).read())
1213
                f.commit()
1214
            finally:
1215
                f.close()
1216
1217
815 by Martin Pool
- track pending-merges
1218
    def pending_merges(self):
1219
        """Return a list of pending merges.
1220
1221
        These are revisions that have been merged into the working
1222
        directory but not yet committed.
1223
        """
907.1.2 by John Arbash Meinel
Working on making Branch() do all of it's work over a Transport.
1224
        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
1225
        if not self._transport.has(cfn):
815 by Martin Pool
- track pending-merges
1226
            return []
1227
        p = []
1228
        for l in self.controlfile('pending-merges', 'r').readlines():
1229
            p.append(l.rstrip('\n'))
1230
        return p
1231
1232
907.1.4 by John Arbash Meinel
Add pending_merge can take multiple entries.
1233
    def add_pending_merge(self, *revision_ids):
1263 by Martin Pool
- clean up imports
1234
        # TODO: Perhaps should check at this point that the
1235
        # history of the revision is actually present?
815 by Martin Pool
- track pending-merges
1236
        p = self.pending_merges()
907.1.4 by John Arbash Meinel
Add pending_merge can take multiple entries.
1237
        updated = False
1238
        for rev_id in revision_ids:
1239
            if rev_id in p:
1240
                continue
1241
            p.append(rev_id)
1242
            updated = True
1243
        if updated:
1244
            self.set_pending_merges(p)
815 by Martin Pool
- track pending-merges
1245
1246
    def set_pending_merges(self, rev_list):
1247
        self.lock_write()
1248
        try:
907.1.50 by John Arbash Meinel
Removed encode/decode from Transport.put/get, added more exceptions that can be thrown.
1249
            self.put_controlfile('pending-merges', '\n'.join(rev_list))
815 by Martin Pool
- track pending-merges
1250
        finally:
1251
            self.unlock()
1252
1253
1149 by Martin Pool
- make get_parent() be a method of Branch; add simple tests for it
1254
    def get_parent(self):
1255
        """Return the parent location of the branch.
1256
1257
        This is the default location for push/pull/missing.  The usual
1258
        pattern is that the user can override it by specifying a
1259
        location.
1260
        """
1261
        import errno
1262
        _locs = ['parent', 'pull', 'x-pull']
1263
        for l in _locs:
1264
            try:
1265
                return self.controlfile(l, 'r').read().strip('\n')
1266
            except IOError, e:
1267
                if e.errno != errno.ENOENT:
1268
                    raise
1269
        return None
1270
1150 by Martin Pool
- add new Branch.set_parent and tests
1271
1272
    def set_parent(self, url):
1273
        # TODO: Maybe delete old location files?
1274
        from bzrlib.atomicfile import AtomicFile
1275
        self.lock_write()
1276
        try:
1277
            f = AtomicFile(self.controlfilename('parent'))
1278
            try:
1279
                f.write(url + '\n')
1280
                f.commit()
1281
            finally:
1282
                f.close()
1283
        finally:
1284
            self.unlock()
1285
974.1.54 by aaron.bentley at utoronto
Fixed the revno bug in log
1286
    def check_revno(self, revno):
1287
        """\
1288
        Check whether a revno corresponds to any revision.
1289
        Zero (the NULL revision) is considered valid.
1290
        """
1291
        if revno != 0:
1292
            self.check_real_revno(revno)
1293
            
1294
    def check_real_revno(self, revno):
1295
        """\
1296
        Check whether a revno corresponds to a real revision.
1297
        Zero (the NULL revision) is considered invalid
1298
        """
1299
        if revno < 1 or revno > self.revno():
1300
            raise InvalidRevisionNumber(revno)
1301
        
1149 by Martin Pool
- make get_parent() be a method of Branch; add simple tests for it
1302
        
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
1303
        
1304
1305
1185.11.11 by John Arbash Meinel
Removing the remotebranch object.
1306
class ScratchBranch(_Branch):
1 by mbp at sourcefrog
import from baz patch-364
1307
    """Special test class: a branch that cleans up after itself.
1308
1309
    >>> b = ScratchBranch()
1310
    >>> isdir(b.base)
1311
    True
1312
    >>> bd = b.base
396 by Martin Pool
- Using the destructor on a ScratchBranch is not reliable;
1313
    >>> b.destroy()
1 by mbp at sourcefrog
import from baz patch-364
1314
    >>> isdir(bd)
1315
    False
1316
    """
622 by Martin Pool
Updated merge patch from Aaron
1317
    def __init__(self, files=[], dirs=[], base=None):
1 by mbp at sourcefrog
import from baz patch-364
1318
        """Make a test branch.
1319
1320
        This creates a temporary directory and runs init-tree in it.
1321
1322
        If any files are listed, they are created in the working copy.
1323
        """
800 by Martin Pool
Merge John's import-speedup branch:
1324
        from tempfile import mkdtemp
622 by Martin Pool
Updated merge patch from Aaron
1325
        init = False
1326
        if base is None:
800 by Martin Pool
Merge John's import-speedup branch:
1327
            base = mkdtemp()
622 by Martin Pool
Updated merge patch from Aaron
1328
            init = True
1393.2.4 by John Arbash Meinel
All tests pass.
1329
        if isinstance(base, basestring):
1330
            base = get_transport(base)
1185.11.11 by John Arbash Meinel
Removing the remotebranch object.
1331
        _Branch.__init__(self, base, init=init)
100 by mbp at sourcefrog
- add test case for ignore files
1332
        for d in dirs:
907.1.8 by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport
1333
            self._transport.mkdir(d)
100 by mbp at sourcefrog
- add test case for ignore files
1334
            
1 by mbp at sourcefrog
import from baz patch-364
1335
        for f in files:
907.1.8 by John Arbash Meinel
Changed the format for abspath. Updated branch to use a hidden _transport
1336
            self._transport.put(f, 'content of %s' % f)
1 by mbp at sourcefrog
import from baz patch-364
1337
1338
622 by Martin Pool
Updated merge patch from Aaron
1339
    def clone(self):
1340
        """
1341
        >>> orig = ScratchBranch(files=["file1", "file2"])
1342
        >>> clone = orig.clone()
1185.1.40 by Robert Collins
Merge what applied of Alexander Belchenko's win32 patch.
1343
        >>> if os.name != 'nt':
1344
        ...   os.path.samefile(orig.base, clone.base)
1345
        ... else:
1346
        ...   orig.base == clone.base
1347
        ...
622 by Martin Pool
Updated merge patch from Aaron
1348
        False
1349
        >>> os.path.isfile(os.path.join(clone.base, "file1"))
1350
        True
1351
        """
800 by Martin Pool
Merge John's import-speedup branch:
1352
        from shutil import copytree
1353
        from tempfile import mkdtemp
1354
        base = mkdtemp()
622 by Martin Pool
Updated merge patch from Aaron
1355
        os.rmdir(base)
800 by Martin Pool
Merge John's import-speedup branch:
1356
        copytree(self.base, base, symlinks=True)
622 by Martin Pool
Updated merge patch from Aaron
1357
        return ScratchBranch(base=base)
1149 by Martin Pool
- make get_parent() be a method of Branch; add simple tests for it
1358
1 by mbp at sourcefrog
import from baz patch-364
1359
    def __del__(self):
396 by Martin Pool
- Using the destructor on a ScratchBranch is not reliable;
1360
        self.destroy()
1361
1362
    def destroy(self):
1 by mbp at sourcefrog
import from baz patch-364
1363
        """Destroy the test branch, removing the scratch directory."""
800 by Martin Pool
Merge John's import-speedup branch:
1364
        from shutil import rmtree
163 by mbp at sourcefrog
merge win32 portability fixes
1365
        try:
610 by Martin Pool
- replace Branch.lock(mode) with separate lock_read and lock_write
1366
            if self.base:
1367
                mutter("delete ScratchBranch %s" % self.base)
800 by Martin Pool
Merge John's import-speedup branch:
1368
                rmtree(self.base)
396 by Martin Pool
- Using the destructor on a ScratchBranch is not reliable;
1369
        except OSError, e:
163 by mbp at sourcefrog
merge win32 portability fixes
1370
            # Work around for shutil.rmtree failing on Windows when
1371
            # readonly files are encountered
396 by Martin Pool
- Using the destructor on a ScratchBranch is not reliable;
1372
            mutter("hit exception in destroying ScratchBranch: %s" % e)
163 by mbp at sourcefrog
merge win32 portability fixes
1373
            for root, dirs, files in os.walk(self.base, topdown=False):
1374
                for name in files:
1375
                    os.chmod(os.path.join(root, name), 0700)
800 by Martin Pool
Merge John's import-speedup branch:
1376
            rmtree(self.base)
907.1.19 by John Arbash Meinel
Updated ScratchBranch and Branch.base, All Tests PASS !!!
1377
        self._transport = None
1 by mbp at sourcefrog
import from baz patch-364
1378
1379
    
1380
1381
######################################################################
1382
# predicates
1383
1384
1385
def is_control_file(filename):
1386
    ## FIXME: better check
1387
    filename = os.path.normpath(filename)
1388
    while filename != '':
1389
        head, tail = os.path.split(filename)
1390
        ## mutter('check %r for control file' % ((head, tail), ))
1391
        if tail == bzrlib.BZRDIR:
1392
            return True
70 by mbp at sourcefrog
Prepare for smart recursive add.
1393
        if filename == head:
1394
            break
1 by mbp at sourcefrog
import from baz patch-364
1395
        filename = head
1396
    return False
1397
1398
1399
70 by mbp at sourcefrog
Prepare for smart recursive add.
1400
def gen_file_id(name):
1 by mbp at sourcefrog
import from baz patch-364
1401
    """Return new file id.
1402
1403
    This should probably generate proper UUIDs, but for the moment we
1404
    cope with just randomness because running uuidgen every time is
1405
    slow."""
535 by Martin Pool
- try to eliminate wierd characters from file names when they're
1406
    import re
800 by Martin Pool
Merge John's import-speedup branch:
1407
    from binascii import hexlify
1408
    from time import time
535 by Martin Pool
- try to eliminate wierd characters from file names when they're
1409
1410
    # get last component
70 by mbp at sourcefrog
Prepare for smart recursive add.
1411
    idx = name.rfind('/')
1412
    if idx != -1:
1413
        name = name[idx+1 : ]
262 by Martin Pool
- gen_file_id: break the file on either / or \ when looking
1414
    idx = name.rfind('\\')
1415
    if idx != -1:
1416
        name = name[idx+1 : ]
70 by mbp at sourcefrog
Prepare for smart recursive add.
1417
535 by Martin Pool
- try to eliminate wierd characters from file names when they're
1418
    # make it not a hidden file
70 by mbp at sourcefrog
Prepare for smart recursive add.
1419
    name = name.lstrip('.')
1420
535 by Martin Pool
- try to eliminate wierd characters from file names when they're
1421
    # remove any wierd characters; we don't escape them but rather
1422
    # just pull them out
1423
    name = re.sub(r'[^\w.]', '', name)
1424
190 by mbp at sourcefrog
64 bits of randomness in file/revision ids
1425
    s = hexlify(rand_bytes(8))
800 by Martin Pool
Merge John's import-speedup branch:
1426
    return '-'.join((name, compact_date(time()), s))
909 by Martin Pool
- merge John's code to give the tree root an explicit file id
1427
1428
1429
def gen_root_id():
1430
    """Return a new tree-root file id."""
1431
    return gen_file_id('TREE_ROOT')
1432
1092.1.34 by Robert Collins
unbreak cmd_branch now that something tests the core of it..
1433