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