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