~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Vincent Ladeuil
  • Date: 2009-06-18 19:45:24 UTC
  • mto: This revision was merged to the branch mainline in revision 4466.
  • Revision ID: v.ladeuil+lp@free.fr-20090618194524-poedor61th3op5dm
Cleanup.

* bzrlib/tests/test__known_graph.py:
(TestKnownGraph): Delete dominator tests.

* bzrlib/_known_graph_pyx.pyx: 
Cleanup all references to old version and linear dominators :-/

* bzrlib/_known_graph_py.py: 
Cleanup all references to old version and linear dominators :-/

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
# TODO: Don't allow WorkingTrees to be constructed for remote branches.
18
 
 
19
 
# FIXME: I don't know if writing out the cache from the destructor is really a
20
 
# good idea, because destructors are considered poor taste in Python, and
21
 
# it's not predictable when it will be written out.
22
 
 
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""WorkingTree object and friends.
 
18
 
 
19
A WorkingTree represents the editable working copy of a branch.
 
20
Operations which represent the WorkingTree are also done here,
 
21
such as renaming or adding files.  The WorkingTree has an inventory
 
22
which is updated by these operations.  A commit produces a
 
23
new revision based on the workingtree and its inventory.
 
24
 
 
25
At the moment every WorkingTree has its own branch.  Remote
 
26
WorkingTrees aren't supported.
 
27
 
 
28
To get a WorkingTree, call bzrdir.open_workingtree() or
 
29
WorkingTree.open(dir).
 
30
"""
 
31
 
 
32
# TODO: Give the workingtree sole responsibility for the working inventory;
 
33
# remove the variable and references to it from the branch.  This may require
 
34
# updating the commit code so as to update the inventory within the working
 
35
# copy, and making sure there's only one WorkingTree for any directory on disk.
 
36
# At the moment they may alias the inventory and have old copies of it in
 
37
# memory.  (Now done? -- mbp 20060309)
 
38
 
 
39
from cStringIO import StringIO
23
40
import os
24
 
import fnmatch
25
 
        
26
 
import bzrlib.tree
27
 
from bzrlib.osutils import appendpath, file_kind, isdir, splitpath
28
 
from bzrlib.errors import BzrCheckError
29
 
from bzrlib.trace import mutter
30
 
 
31
 
class WorkingTree(bzrlib.tree.Tree):
 
41
import sys
 
42
 
 
43
from bzrlib.lazy_import import lazy_import
 
44
lazy_import(globals(), """
 
45
from bisect import bisect_left
 
46
import collections
 
47
import errno
 
48
import itertools
 
49
import operator
 
50
import stat
 
51
from time import time
 
52
import warnings
 
53
import re
 
54
 
 
55
import bzrlib
 
56
from bzrlib import (
 
57
    branch,
 
58
    bzrdir,
 
59
    conflicts as _mod_conflicts,
 
60
    dirstate,
 
61
    errors,
 
62
    generate_ids,
 
63
    globbing,
 
64
    hashcache,
 
65
    ignores,
 
66
    merge,
 
67
    revision as _mod_revision,
 
68
    revisiontree,
 
69
    repository,
 
70
    textui,
 
71
    trace,
 
72
    transform,
 
73
    ui,
 
74
    urlutils,
 
75
    views,
 
76
    xml5,
 
77
    xml6,
 
78
    xml7,
 
79
    )
 
80
import bzrlib.branch
 
81
from bzrlib.transport import get_transport
 
82
import bzrlib.ui
 
83
from bzrlib.workingtree_4 import (
 
84
    WorkingTreeFormat4,
 
85
    WorkingTreeFormat5,
 
86
    WorkingTreeFormat6,
 
87
    )
 
88
""")
 
89
 
 
90
from bzrlib import symbol_versioning
 
91
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
92
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
 
93
from bzrlib.lockable_files import LockableFiles
 
94
from bzrlib.lockdir import LockDir
 
95
import bzrlib.mutabletree
 
96
from bzrlib.mutabletree import needs_tree_write_lock
 
97
from bzrlib import osutils
 
98
from bzrlib.osutils import (
 
99
    compact_date,
 
100
    file_kind,
 
101
    isdir,
 
102
    normpath,
 
103
    pathjoin,
 
104
    rand_chars,
 
105
    realpath,
 
106
    safe_unicode,
 
107
    splitpath,
 
108
    supports_executable,
 
109
    )
 
110
from bzrlib.filters import filtered_input_file
 
111
from bzrlib.trace import mutter, note
 
112
from bzrlib.transport.local import LocalTransport
 
113
from bzrlib.progress import DummyProgress, ProgressPhase
 
114
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
 
115
from bzrlib.rio import RioReader, rio_file, Stanza
 
116
from bzrlib.symbol_versioning import (deprecated_passed,
 
117
        deprecated_method,
 
118
        deprecated_function,
 
119
        DEPRECATED_PARAMETER,
 
120
        )
 
121
 
 
122
 
 
123
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
 
124
CONFLICT_HEADER_1 = "BZR conflict list format 1"
 
125
 
 
126
ERROR_PATH_NOT_FOUND = 3    # WindowsError errno code, equivalent to ENOENT
 
127
 
 
128
 
 
129
class TreeEntry(object):
 
130
    """An entry that implements the minimum interface used by commands.
 
131
 
 
132
    This needs further inspection, it may be better to have
 
133
    InventoryEntries without ids - though that seems wrong. For now,
 
134
    this is a parallel hierarchy to InventoryEntry, and needs to become
 
135
    one of several things: decorates to that hierarchy, children of, or
 
136
    parents of it.
 
137
    Another note is that these objects are currently only used when there is
 
138
    no InventoryEntry available - i.e. for unversioned objects.
 
139
    Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
 
140
    """
 
141
 
 
142
    def __eq__(self, other):
 
143
        # yes, this us ugly, TODO: best practice __eq__ style.
 
144
        return (isinstance(other, TreeEntry)
 
145
                and other.__class__ == self.__class__)
 
146
 
 
147
    def kind_character(self):
 
148
        return "???"
 
149
 
 
150
 
 
151
class TreeDirectory(TreeEntry):
 
152
    """See TreeEntry. This is a directory in a working tree."""
 
153
 
 
154
    def __eq__(self, other):
 
155
        return (isinstance(other, TreeDirectory)
 
156
                and other.__class__ == self.__class__)
 
157
 
 
158
    def kind_character(self):
 
159
        return "/"
 
160
 
 
161
 
 
162
class TreeFile(TreeEntry):
 
163
    """See TreeEntry. This is a regular file in a working tree."""
 
164
 
 
165
    def __eq__(self, other):
 
166
        return (isinstance(other, TreeFile)
 
167
                and other.__class__ == self.__class__)
 
168
 
 
169
    def kind_character(self):
 
170
        return ''
 
171
 
 
172
 
 
173
class TreeLink(TreeEntry):
 
174
    """See TreeEntry. This is a symlink in a working tree."""
 
175
 
 
176
    def __eq__(self, other):
 
177
        return (isinstance(other, TreeLink)
 
178
                and other.__class__ == self.__class__)
 
179
 
 
180
    def kind_character(self):
 
181
        return ''
 
182
 
 
183
 
 
184
class WorkingTree(bzrlib.mutabletree.MutableTree):
32
185
    """Working copy tree.
33
186
 
34
187
    The inventory is held in the `Branch` working-inventory, and the
37
190
    It is possible for a `WorkingTree` to have a filename which is
38
191
    not listed in the Inventory and vice versa.
39
192
    """
40
 
    def __init__(self, basedir, inv):
41
 
        from bzrlib.hashcache import HashCache
42
 
        from bzrlib.trace import note, mutter
43
 
 
44
 
        self._inventory = inv
45
 
        self.basedir = basedir
46
 
        self.path2id = inv.path2id
47
 
 
 
193
 
 
194
    # override this to set the strategy for storing views
 
195
    def _make_views(self):
 
196
        return views.DisabledViews(self)
 
197
 
 
198
    def __init__(self, basedir='.',
 
199
                 branch=DEPRECATED_PARAMETER,
 
200
                 _inventory=None,
 
201
                 _control_files=None,
 
202
                 _internal=False,
 
203
                 _format=None,
 
204
                 _bzrdir=None):
 
205
        """Construct a WorkingTree instance. This is not a public API.
 
206
 
 
207
        :param branch: A branch to override probing for the branch.
 
208
        """
 
209
        self._format = _format
 
210
        self.bzrdir = _bzrdir
 
211
        if not _internal:
 
212
            raise errors.BzrError("Please use bzrdir.open_workingtree or "
 
213
                "WorkingTree.open() to obtain a WorkingTree.")
 
214
        basedir = safe_unicode(basedir)
 
215
        mutter("opening working tree %r", basedir)
 
216
        if deprecated_passed(branch):
 
217
            self._branch = branch
 
218
        else:
 
219
            self._branch = self.bzrdir.open_branch()
 
220
        self.basedir = realpath(basedir)
 
221
        # if branch is at our basedir and is a format 6 or less
 
222
        if isinstance(self._format, WorkingTreeFormat2):
 
223
            # share control object
 
224
            self._control_files = self.branch.control_files
 
225
        else:
 
226
            # assume all other formats have their own control files.
 
227
            self._control_files = _control_files
 
228
        self._transport = self._control_files._transport
48
229
        # update the whole cache up front and write to disk if anything changed;
49
230
        # in the future we might want to do this more selectively
50
 
        hc = self._hashcache = HashCache(basedir)
 
231
        # two possible ways offer themselves : in self._unlock, write the cache
 
232
        # if needed, or, when the cache sees a change, append it to the hash
 
233
        # cache file, and have the parser take the most recent entry for a
 
234
        # given path only.
 
235
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
236
        cache_filename = wt_trans.local_abspath('stat-cache')
 
237
        self._hashcache = hashcache.HashCache(basedir, cache_filename,
 
238
            self.bzrdir._get_file_mode(),
 
239
            self._content_filter_stack_provider())
 
240
        hc = self._hashcache
51
241
        hc.read()
52
 
        hc.scan()
 
242
        # is this scan needed ? it makes things kinda slow.
 
243
        #hc.scan()
53
244
 
54
245
        if hc.needs_write:
55
246
            mutter("write hc")
56
247
            hc.write()
57
 
            
58
 
            
59
 
    def __del__(self):
60
 
        if self._hashcache.needs_write:
61
 
            self._hashcache.write()
62
 
 
63
 
 
 
248
 
 
249
        if _inventory is None:
 
250
            # This will be acquired on lock_read() or lock_write()
 
251
            self._inventory_is_modified = False
 
252
            self._inventory = None
 
253
        else:
 
254
            # the caller of __init__ has provided an inventory,
 
255
            # we assume they know what they are doing - as its only
 
256
            # the Format factory and creation methods that are
 
257
            # permitted to do this.
 
258
            self._set_inventory(_inventory, dirty=False)
 
259
        self._detect_case_handling()
 
260
        self._rules_searcher = None
 
261
        self.views = self._make_views()
 
262
 
 
263
    def _detect_case_handling(self):
 
264
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
265
        try:
 
266
            wt_trans.stat("FoRMaT")
 
267
        except errors.NoSuchFile:
 
268
            self.case_sensitive = True
 
269
        else:
 
270
            self.case_sensitive = False
 
271
 
 
272
        self._setup_directory_is_tree_reference()
 
273
 
 
274
    branch = property(
 
275
        fget=lambda self: self._branch,
 
276
        doc="""The branch this WorkingTree is connected to.
 
277
 
 
278
            This cannot be set - it is reflective of the actual disk structure
 
279
            the working tree has been constructed from.
 
280
            """)
 
281
 
 
282
    def break_lock(self):
 
283
        """Break a lock if one is present from another instance.
 
284
 
 
285
        Uses the ui factory to ask for confirmation if the lock may be from
 
286
        an active process.
 
287
 
 
288
        This will probe the repository for its lock as well.
 
289
        """
 
290
        self._control_files.break_lock()
 
291
        self.branch.break_lock()
 
292
 
 
293
    def requires_rich_root(self):
 
294
        return self._format.requires_rich_root
 
295
 
 
296
    def supports_tree_reference(self):
 
297
        return False
 
298
 
 
299
    def supports_content_filtering(self):
 
300
        return self._format.supports_content_filtering()
 
301
 
 
302
    def supports_views(self):
 
303
        return self.views.supports_views()
 
304
 
 
305
    def _set_inventory(self, inv, dirty):
 
306
        """Set the internal cached inventory.
 
307
 
 
308
        :param inv: The inventory to set.
 
309
        :param dirty: A boolean indicating whether the inventory is the same
 
310
            logical inventory as whats on disk. If True the inventory is not
 
311
            the same and should be written to disk or data will be lost, if
 
312
            False then the inventory is the same as that on disk and any
 
313
            serialisation would be unneeded overhead.
 
314
        """
 
315
        self._inventory = inv
 
316
        self._inventory_is_modified = dirty
 
317
 
 
318
    @staticmethod
 
319
    def open(path=None, _unsupported=False):
 
320
        """Open an existing working tree at path.
 
321
 
 
322
        """
 
323
        if path is None:
 
324
            path = osutils.getcwd()
 
325
        control = bzrdir.BzrDir.open(path, _unsupported)
 
326
        return control.open_workingtree(_unsupported)
 
327
 
 
328
    @staticmethod
 
329
    def open_containing(path=None):
 
330
        """Open an existing working tree which has its root about path.
 
331
 
 
332
        This probes for a working tree at path and searches upwards from there.
 
333
 
 
334
        Basically we keep looking up until we find the control directory or
 
335
        run into /.  If there isn't one, raises NotBranchError.
 
336
        TODO: give this a new exception.
 
337
        If there is one, it is returned, along with the unused portion of path.
 
338
 
 
339
        :return: The WorkingTree that contains 'path', and the rest of path
 
340
        """
 
341
        if path is None:
 
342
            path = osutils.getcwd()
 
343
        control, relpath = bzrdir.BzrDir.open_containing(path)
 
344
 
 
345
        return control.open_workingtree(), relpath
 
346
 
 
347
    @staticmethod
 
348
    def open_downlevel(path=None):
 
349
        """Open an unsupported working tree.
 
350
 
 
351
        Only intended for advanced situations like upgrading part of a bzrdir.
 
352
        """
 
353
        return WorkingTree.open(path, _unsupported=True)
 
354
 
 
355
    @staticmethod
 
356
    def find_trees(location):
 
357
        def list_current(transport):
 
358
            return [d for d in transport.list_dir('') if d != '.bzr']
 
359
        def evaluate(bzrdir):
 
360
            try:
 
361
                tree = bzrdir.open_workingtree()
 
362
            except errors.NoWorkingTree:
 
363
                return True, None
 
364
            else:
 
365
                return True, tree
 
366
        transport = get_transport(location)
 
367
        iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
 
368
                                              list_current=list_current)
 
369
        return [t for t in iterator if t is not None]
 
370
 
 
371
    # should be deprecated - this is slow and in any case treating them as a
 
372
    # container is (we now know) bad style -- mbp 20070302
 
373
    ## @deprecated_method(zero_fifteen)
64
374
    def __iter__(self):
65
375
        """Iterate through file_ids for this tree.
66
376
 
69
379
        """
70
380
        inv = self._inventory
71
381
        for path, ie in inv.iter_entries():
72
 
            if os.path.exists(self.abspath(path)):
 
382
            if osutils.lexists(self.abspath(path)):
73
383
                yield ie.file_id
74
384
 
 
385
    def all_file_ids(self):
 
386
        """See Tree.iter_all_file_ids"""
 
387
        return set(self.inventory)
75
388
 
76
389
    def __repr__(self):
77
390
        return "<%s of %s>" % (self.__class__.__name__,
78
391
                               getattr(self, 'basedir', None))
79
392
 
80
 
 
81
 
 
82
393
    def abspath(self, filename):
83
 
        return os.path.join(self.basedir, filename)
 
394
        return pathjoin(self.basedir, filename)
 
395
 
 
396
    def basis_tree(self):
 
397
        """Return RevisionTree for the current last revision.
 
398
 
 
399
        If the left most parent is a ghost then the returned tree will be an
 
400
        empty tree - one obtained by calling
 
401
        repository.revision_tree(NULL_REVISION).
 
402
        """
 
403
        try:
 
404
            revision_id = self.get_parent_ids()[0]
 
405
        except IndexError:
 
406
            # no parents, return an empty revision tree.
 
407
            # in the future this should return the tree for
 
408
            # 'empty:' - the implicit root empty tree.
 
409
            return self.branch.repository.revision_tree(
 
410
                       _mod_revision.NULL_REVISION)
 
411
        try:
 
412
            return self.revision_tree(revision_id)
 
413
        except errors.NoSuchRevision:
 
414
            pass
 
415
        # No cached copy available, retrieve from the repository.
 
416
        # FIXME? RBC 20060403 should we cache the inventory locally
 
417
        # at this point ?
 
418
        try:
 
419
            return self.branch.repository.revision_tree(revision_id)
 
420
        except (errors.RevisionNotPresent, errors.NoSuchRevision):
 
421
            # the basis tree *may* be a ghost or a low level error may have
 
422
            # occurred. If the revision is present, its a problem, if its not
 
423
            # its a ghost.
 
424
            if self.branch.repository.has_revision(revision_id):
 
425
                raise
 
426
            # the basis tree is a ghost so return an empty tree.
 
427
            return self.branch.repository.revision_tree(
 
428
                       _mod_revision.NULL_REVISION)
 
429
 
 
430
    def _cleanup(self):
 
431
        self._flush_ignore_list_cache()
 
432
 
 
433
    def relpath(self, path):
 
434
        """Return the local path portion from a given path.
 
435
 
 
436
        The path may be absolute or relative. If its a relative path it is
 
437
        interpreted relative to the python current working directory.
 
438
        """
 
439
        return osutils.relpath(self.basedir, path)
84
440
 
85
441
    def has_filename(self, filename):
86
 
        return os.path.exists(self.abspath(filename))
87
 
 
88
 
    def get_file(self, file_id):
89
 
        return self.get_file_byname(self.id2path(file_id))
90
 
 
91
 
    def get_file_byname(self, filename):
92
 
        return file(self.abspath(filename), 'rb')
 
442
        return osutils.lexists(self.abspath(filename))
 
443
 
 
444
    def get_file(self, file_id, path=None, filtered=True):
 
445
        return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
 
446
 
 
447
    def get_file_with_stat(self, file_id, path=None, filtered=True,
 
448
        _fstat=os.fstat):
 
449
        """See Tree.get_file_with_stat."""
 
450
        if path is None:
 
451
            path = self.id2path(file_id)
 
452
        file_obj = self.get_file_byname(path, filtered=False)
 
453
        stat_value = _fstat(file_obj.fileno())
 
454
        if filtered and self.supports_content_filtering():
 
455
            filters = self._content_filter_stack(path)
 
456
            file_obj = filtered_input_file(file_obj, filters)
 
457
        return (file_obj, stat_value)
 
458
 
 
459
    def get_file_text(self, file_id, path=None, filtered=True):
 
460
        return self.get_file(file_id, path=path, filtered=filtered).read()
 
461
 
 
462
    def get_file_byname(self, filename, filtered=True):
 
463
        path = self.abspath(filename)
 
464
        f = file(path, 'rb')
 
465
        if filtered and self.supports_content_filtering():
 
466
            filters = self._content_filter_stack(filename)
 
467
            return filtered_input_file(f, filters)
 
468
        else:
 
469
            return f
 
470
 
 
471
    def get_file_lines(self, file_id, path=None, filtered=True):
 
472
        """See Tree.get_file_lines()"""
 
473
        file = self.get_file(file_id, path, filtered=filtered)
 
474
        try:
 
475
            return file.readlines()
 
476
        finally:
 
477
            file.close()
 
478
 
 
479
    @needs_read_lock
 
480
    def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
 
481
        """See Tree.annotate_iter
 
482
 
 
483
        This implementation will use the basis tree implementation if possible.
 
484
        Lines not in the basis are attributed to CURRENT_REVISION
 
485
 
 
486
        If there are pending merges, lines added by those merges will be
 
487
        incorrectly attributed to CURRENT_REVISION (but after committing, the
 
488
        attribution will be correct).
 
489
        """
 
490
        basis = self.basis_tree()
 
491
        basis.lock_read()
 
492
        try:
 
493
            changes = self.iter_changes(basis, True, [self.id2path(file_id)],
 
494
                require_versioned=True).next()
 
495
            changed_content, kind = changes[2], changes[6]
 
496
            if not changed_content:
 
497
                return basis.annotate_iter(file_id)
 
498
            if kind[1] is None:
 
499
                return None
 
500
            import annotate
 
501
            if kind[0] != 'file':
 
502
                old_lines = []
 
503
            else:
 
504
                old_lines = list(basis.annotate_iter(file_id))
 
505
            old = [old_lines]
 
506
            for tree in self.branch.repository.revision_trees(
 
507
                self.get_parent_ids()[1:]):
 
508
                if file_id not in tree:
 
509
                    continue
 
510
                old.append(list(tree.annotate_iter(file_id)))
 
511
            return annotate.reannotate(old, self.get_file(file_id).readlines(),
 
512
                                       default_revision)
 
513
        finally:
 
514
            basis.unlock()
 
515
 
 
516
    def _get_ancestors(self, default_revision):
 
517
        ancestors = set([default_revision])
 
518
        for parent_id in self.get_parent_ids():
 
519
            ancestors.update(self.branch.repository.get_ancestry(
 
520
                             parent_id, topo_sorted=False))
 
521
        return ancestors
 
522
 
 
523
    def get_parent_ids(self):
 
524
        """See Tree.get_parent_ids.
 
525
 
 
526
        This implementation reads the pending merges list and last_revision
 
527
        value and uses that to decide what the parents list should be.
 
528
        """
 
529
        last_rev = _mod_revision.ensure_null(self._last_revision())
 
530
        if _mod_revision.NULL_REVISION == last_rev:
 
531
            parents = []
 
532
        else:
 
533
            parents = [last_rev]
 
534
        try:
 
535
            merges_file = self._transport.get('pending-merges')
 
536
        except errors.NoSuchFile:
 
537
            pass
 
538
        else:
 
539
            for l in merges_file.readlines():
 
540
                revision_id = l.rstrip('\n')
 
541
                parents.append(revision_id)
 
542
        return parents
 
543
 
 
544
    @needs_read_lock
 
545
    def get_root_id(self):
 
546
        """Return the id of this trees root"""
 
547
        return self._inventory.root.file_id
93
548
 
94
549
    def _get_store_filename(self, file_id):
95
 
        ## XXX: badly named; this isn't in the store at all
96
 
        return self.abspath(self.id2path(file_id))
97
 
 
98
 
                
 
550
        ## XXX: badly named; this is not in the store at all
 
551
        return self.abspath(self.id2path(file_id))
 
552
 
 
553
    @needs_read_lock
 
554
    def clone(self, to_bzrdir, revision_id=None):
 
555
        """Duplicate this working tree into to_bzr, including all state.
 
556
 
 
557
        Specifically modified files are kept as modified, but
 
558
        ignored and unknown files are discarded.
 
559
 
 
560
        If you want to make a new line of development, see bzrdir.sprout()
 
561
 
 
562
        revision
 
563
            If not None, the cloned tree will have its last revision set to
 
564
            revision, and difference between the source trees last revision
 
565
            and this one merged in.
 
566
        """
 
567
        # assumes the target bzr dir format is compatible.
 
568
        result = to_bzrdir.create_workingtree()
 
569
        self.copy_content_into(result, revision_id)
 
570
        return result
 
571
 
 
572
    @needs_read_lock
 
573
    def copy_content_into(self, tree, revision_id=None):
 
574
        """Copy the current content and user files of this tree into tree."""
 
575
        tree.set_root_id(self.get_root_id())
 
576
        if revision_id is None:
 
577
            merge.transform_tree(tree, self)
 
578
        else:
 
579
            # TODO now merge from tree.last_revision to revision (to preserve
 
580
            # user local changes)
 
581
            merge.transform_tree(tree, self)
 
582
            tree.set_parent_ids([revision_id])
 
583
 
 
584
    def id2abspath(self, file_id):
 
585
        return self.abspath(self.id2path(file_id))
 
586
 
99
587
    def has_id(self, file_id):
100
588
        # files that have been deleted are excluded
101
 
        inv = self._inventory
 
589
        inv = self.inventory
102
590
        if not inv.has_id(file_id):
103
591
            return False
104
592
        path = inv.id2path(file_id)
105
 
        return os.path.exists(self.abspath(path))
 
593
        return osutils.lexists(self.abspath(path))
106
594
 
 
595
    def has_or_had_id(self, file_id):
 
596
        if file_id == self.inventory.root.file_id:
 
597
            return True
 
598
        return self.inventory.has_id(file_id)
107
599
 
108
600
    __contains__ = has_id
109
 
    
110
601
 
111
602
    def get_file_size(self, file_id):
112
 
        # is this still called?
113
 
        raise NotImplementedError()
114
 
 
115
 
 
116
 
    def get_file_sha1(self, file_id):
117
 
        path = self._inventory.id2path(file_id)
118
 
        return self._hashcache.get_sha1(path)
119
 
 
120
 
 
121
 
    def file_class(self, filename):
122
 
        if self.path2id(filename):
123
 
            return 'V'
124
 
        elif self.is_ignored(filename):
125
 
            return 'I'
126
 
        else:
127
 
            return '?'
128
 
 
129
 
 
130
 
    def list_files(self):
131
 
        """Recursively list all files as (path, class, kind, id).
 
603
        """See Tree.get_file_size"""
 
604
        try:
 
605
            return os.path.getsize(self.id2abspath(file_id))
 
606
        except OSError, e:
 
607
            if e.errno != errno.ENOENT:
 
608
                raise
 
609
            else:
 
610
                return None
 
611
 
 
612
    @needs_read_lock
 
613
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
614
        if not path:
 
615
            path = self._inventory.id2path(file_id)
 
616
        return self._hashcache.get_sha1(path, stat_value)
 
617
 
 
618
    def get_file_mtime(self, file_id, path=None):
 
619
        if not path:
 
620
            path = self.inventory.id2path(file_id)
 
621
        return os.lstat(self.abspath(path)).st_mtime
 
622
 
 
623
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
 
624
        file_id = self.path2id(path)
 
625
        return self._inventory[file_id].executable
 
626
 
 
627
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
 
628
        mode = stat_result.st_mode
 
629
        return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
 
630
 
 
631
    if not supports_executable():
 
632
        def is_executable(self, file_id, path=None):
 
633
            return self._inventory[file_id].executable
 
634
 
 
635
        _is_executable_from_path_and_stat = \
 
636
            _is_executable_from_path_and_stat_from_basis
 
637
    else:
 
638
        def is_executable(self, file_id, path=None):
 
639
            if not path:
 
640
                path = self.id2path(file_id)
 
641
            mode = os.lstat(self.abspath(path)).st_mode
 
642
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
 
643
 
 
644
        _is_executable_from_path_and_stat = \
 
645
            _is_executable_from_path_and_stat_from_stat
 
646
 
 
647
    @needs_tree_write_lock
 
648
    def _add(self, files, ids, kinds):
 
649
        """See MutableTree._add."""
 
650
        # TODO: Re-adding a file that is removed in the working copy
 
651
        # should probably put it back with the previous ID.
 
652
        # the read and write working inventory should not occur in this
 
653
        # function - they should be part of lock_write and unlock.
 
654
        inv = self.inventory
 
655
        for f, file_id, kind in zip(files, ids, kinds):
 
656
            if file_id is None:
 
657
                inv.add_path(f, kind=kind)
 
658
            else:
 
659
                inv.add_path(f, kind=kind, file_id=file_id)
 
660
            self._inventory_is_modified = True
 
661
 
 
662
    @needs_tree_write_lock
 
663
    def _gather_kinds(self, files, kinds):
 
664
        """See MutableTree._gather_kinds."""
 
665
        for pos, f in enumerate(files):
 
666
            if kinds[pos] is None:
 
667
                fullpath = normpath(self.abspath(f))
 
668
                try:
 
669
                    kinds[pos] = file_kind(fullpath)
 
670
                except OSError, e:
 
671
                    if e.errno == errno.ENOENT:
 
672
                        raise errors.NoSuchFile(fullpath)
 
673
 
 
674
    @needs_write_lock
 
675
    def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
 
676
        """Add revision_id as a parent.
 
677
 
 
678
        This is equivalent to retrieving the current list of parent ids
 
679
        and setting the list to its value plus revision_id.
 
680
 
 
681
        :param revision_id: The revision id to add to the parent list. It may
 
682
        be a ghost revision as long as its not the first parent to be added,
 
683
        or the allow_leftmost_as_ghost parameter is set True.
 
684
        :param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
 
685
        """
 
686
        parents = self.get_parent_ids() + [revision_id]
 
687
        self.set_parent_ids(parents, allow_leftmost_as_ghost=len(parents) > 1
 
688
            or allow_leftmost_as_ghost)
 
689
 
 
690
    @needs_tree_write_lock
 
691
    def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
 
692
        """Add revision_id, tree tuple as a parent.
 
693
 
 
694
        This is equivalent to retrieving the current list of parent trees
 
695
        and setting the list to its value plus parent_tuple. See also
 
696
        add_parent_tree_id - if you only have a parent id available it will be
 
697
        simpler to use that api. If you have the parent already available, using
 
698
        this api is preferred.
 
699
 
 
700
        :param parent_tuple: The (revision id, tree) to add to the parent list.
 
701
            If the revision_id is a ghost, pass None for the tree.
 
702
        :param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
 
703
        """
 
704
        parent_ids = self.get_parent_ids() + [parent_tuple[0]]
 
705
        if len(parent_ids) > 1:
 
706
            # the leftmost may have already been a ghost, preserve that if it
 
707
            # was.
 
708
            allow_leftmost_as_ghost = True
 
709
        self.set_parent_ids(parent_ids,
 
710
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
 
711
 
 
712
    @needs_tree_write_lock
 
713
    def add_pending_merge(self, *revision_ids):
 
714
        # TODO: Perhaps should check at this point that the
 
715
        # history of the revision is actually present?
 
716
        parents = self.get_parent_ids()
 
717
        updated = False
 
718
        for rev_id in revision_ids:
 
719
            if rev_id in parents:
 
720
                continue
 
721
            parents.append(rev_id)
 
722
            updated = True
 
723
        if updated:
 
724
            self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
 
725
 
 
726
    def path_content_summary(self, path, _lstat=os.lstat,
 
727
        _mapper=osutils.file_kind_from_stat_mode):
 
728
        """See Tree.path_content_summary."""
 
729
        abspath = self.abspath(path)
 
730
        try:
 
731
            stat_result = _lstat(abspath)
 
732
        except OSError, e:
 
733
            if getattr(e, 'errno', None) == errno.ENOENT:
 
734
                # no file.
 
735
                return ('missing', None, None, None)
 
736
            # propagate other errors
 
737
            raise
 
738
        kind = _mapper(stat_result.st_mode)
 
739
        if kind == 'file':
 
740
            size = stat_result.st_size
 
741
            # try for a stat cache lookup
 
742
            executable = self._is_executable_from_path_and_stat(path, stat_result)
 
743
            return (kind, size, executable, self._sha_from_stat(
 
744
                path, stat_result))
 
745
        elif kind == 'directory':
 
746
            # perhaps it looks like a plain directory, but it's really a
 
747
            # reference.
 
748
            if self._directory_is_tree_reference(path):
 
749
                kind = 'tree-reference'
 
750
            return kind, None, None, None
 
751
        elif kind == 'symlink':
 
752
            target = osutils.readlink(abspath)
 
753
            return ('symlink', None, None, target)
 
754
        else:
 
755
            return (kind, None, None, None)
 
756
 
 
757
    def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
 
758
        """Common ghost checking functionality from set_parent_*.
 
759
 
 
760
        This checks that the left hand-parent exists if there are any
 
761
        revisions present.
 
762
        """
 
763
        if len(revision_ids) > 0:
 
764
            leftmost_id = revision_ids[0]
 
765
            if (not allow_leftmost_as_ghost and not
 
766
                self.branch.repository.has_revision(leftmost_id)):
 
767
                raise errors.GhostRevisionUnusableHere(leftmost_id)
 
768
 
 
769
    def _set_merges_from_parent_ids(self, parent_ids):
 
770
        merges = parent_ids[1:]
 
771
        self._transport.put_bytes('pending-merges', '\n'.join(merges),
 
772
            mode=self.bzrdir._get_file_mode())
 
773
 
 
774
    def _filter_parent_ids_by_ancestry(self, revision_ids):
 
775
        """Check that all merged revisions are proper 'heads'.
 
776
 
 
777
        This will always return the first revision_id, and any merged revisions
 
778
        which are
 
779
        """
 
780
        if len(revision_ids) == 0:
 
781
            return revision_ids
 
782
        graph = self.branch.repository.get_graph()
 
783
        heads = graph.heads(revision_ids)
 
784
        new_revision_ids = revision_ids[:1]
 
785
        for revision_id in revision_ids[1:]:
 
786
            if revision_id in heads and revision_id not in new_revision_ids:
 
787
                new_revision_ids.append(revision_id)
 
788
        if new_revision_ids != revision_ids:
 
789
            trace.mutter('requested to set revision_ids = %s,'
 
790
                         ' but filtered to %s', revision_ids, new_revision_ids)
 
791
        return new_revision_ids
 
792
 
 
793
    @needs_tree_write_lock
 
794
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
 
795
        """Set the parent ids to revision_ids.
 
796
 
 
797
        See also set_parent_trees. This api will try to retrieve the tree data
 
798
        for each element of revision_ids from the trees repository. If you have
 
799
        tree data already available, it is more efficient to use
 
800
        set_parent_trees rather than set_parent_ids. set_parent_ids is however
 
801
        an easier API to use.
 
802
 
 
803
        :param revision_ids: The revision_ids to set as the parent ids of this
 
804
            working tree. Any of these may be ghosts.
 
805
        """
 
806
        self._check_parents_for_ghosts(revision_ids,
 
807
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
 
808
        for revision_id in revision_ids:
 
809
            _mod_revision.check_not_reserved_id(revision_id)
 
810
 
 
811
        revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
 
812
 
 
813
        if len(revision_ids) > 0:
 
814
            self.set_last_revision(revision_ids[0])
 
815
        else:
 
816
            self.set_last_revision(_mod_revision.NULL_REVISION)
 
817
 
 
818
        self._set_merges_from_parent_ids(revision_ids)
 
819
 
 
820
    @needs_tree_write_lock
 
821
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
 
822
        """See MutableTree.set_parent_trees."""
 
823
        parent_ids = [rev for (rev, tree) in parents_list]
 
824
        for revision_id in parent_ids:
 
825
            _mod_revision.check_not_reserved_id(revision_id)
 
826
 
 
827
        self._check_parents_for_ghosts(parent_ids,
 
828
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
 
829
 
 
830
        parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
 
831
 
 
832
        if len(parent_ids) == 0:
 
833
            leftmost_parent_id = _mod_revision.NULL_REVISION
 
834
            leftmost_parent_tree = None
 
835
        else:
 
836
            leftmost_parent_id, leftmost_parent_tree = parents_list[0]
 
837
 
 
838
        if self._change_last_revision(leftmost_parent_id):
 
839
            if leftmost_parent_tree is None:
 
840
                # If we don't have a tree, fall back to reading the
 
841
                # parent tree from the repository.
 
842
                self._cache_basis_inventory(leftmost_parent_id)
 
843
            else:
 
844
                inv = leftmost_parent_tree.inventory
 
845
                xml = self._create_basis_xml_from_inventory(
 
846
                                        leftmost_parent_id, inv)
 
847
                self._write_basis_inventory(xml)
 
848
        self._set_merges_from_parent_ids(parent_ids)
 
849
 
 
850
    @needs_tree_write_lock
 
851
    def set_pending_merges(self, rev_list):
 
852
        parents = self.get_parent_ids()
 
853
        leftmost = parents[:1]
 
854
        new_parents = leftmost + rev_list
 
855
        self.set_parent_ids(new_parents)
 
856
 
 
857
    @needs_tree_write_lock
 
858
    def set_merge_modified(self, modified_hashes):
 
859
        def iter_stanzas():
 
860
            for file_id, hash in modified_hashes.iteritems():
 
861
                yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
 
862
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
 
863
 
 
864
    def _sha_from_stat(self, path, stat_result):
 
865
        """Get a sha digest from the tree's stat cache.
 
866
 
 
867
        The default implementation assumes no stat cache is present.
 
868
 
 
869
        :param path: The path.
 
870
        :param stat_result: The stat result being looked up.
 
871
        """
 
872
        return None
 
873
 
 
874
    def _put_rio(self, filename, stanzas, header):
 
875
        self._must_be_locked()
 
876
        my_file = rio_file(stanzas, header)
 
877
        self._transport.put_file(filename, my_file,
 
878
            mode=self.bzrdir._get_file_mode())
 
879
 
 
880
    @needs_write_lock # because merge pulls data into the branch.
 
881
    def merge_from_branch(self, branch, to_revision=None, from_revision=None,
 
882
        merge_type=None):
 
883
        """Merge from a branch into this working tree.
 
884
 
 
885
        :param branch: The branch to merge from.
 
886
        :param to_revision: If non-None, the merge will merge to to_revision,
 
887
            but not beyond it. to_revision does not need to be in the history
 
888
            of the branch when it is supplied. If None, to_revision defaults to
 
889
            branch.last_revision().
 
890
        """
 
891
        from bzrlib.merge import Merger, Merge3Merger
 
892
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
893
        try:
 
894
            merger = Merger(self.branch, this_tree=self, pb=pb)
 
895
            merger.pp = ProgressPhase("Merge phase", 5, pb)
 
896
            merger.pp.next_phase()
 
897
            # check that there are no
 
898
            # local alterations
 
899
            merger.check_basis(check_clean=True, require_commits=False)
 
900
            if to_revision is None:
 
901
                to_revision = _mod_revision.ensure_null(branch.last_revision())
 
902
            merger.other_rev_id = to_revision
 
903
            if _mod_revision.is_null(merger.other_rev_id):
 
904
                raise errors.NoCommits(branch)
 
905
            self.branch.fetch(branch, last_revision=merger.other_rev_id)
 
906
            merger.other_basis = merger.other_rev_id
 
907
            merger.other_tree = self.branch.repository.revision_tree(
 
908
                merger.other_rev_id)
 
909
            merger.other_branch = branch
 
910
            merger.pp.next_phase()
 
911
            if from_revision is None:
 
912
                merger.find_base()
 
913
            else:
 
914
                merger.set_base_revision(from_revision, branch)
 
915
            if merger.base_rev_id == merger.other_rev_id:
 
916
                raise errors.PointlessMerge
 
917
            merger.backup_files = False
 
918
            if merge_type is None:
 
919
                merger.merge_type = Merge3Merger
 
920
            else:
 
921
                merger.merge_type = merge_type
 
922
            merger.set_interesting_files(None)
 
923
            merger.show_base = False
 
924
            merger.reprocess = False
 
925
            conflicts = merger.do_merge()
 
926
            merger.set_pending()
 
927
        finally:
 
928
            pb.finished()
 
929
        return conflicts
 
930
 
 
931
    @needs_read_lock
 
932
    def merge_modified(self):
 
933
        """Return a dictionary of files modified by a merge.
 
934
 
 
935
        The list is initialized by WorkingTree.set_merge_modified, which is
 
936
        typically called after we make some automatic updates to the tree
 
937
        because of a merge.
 
938
 
 
939
        This returns a map of file_id->sha1, containing only files which are
 
940
        still in the working inventory and have that text hash.
 
941
        """
 
942
        try:
 
943
            hashfile = self._transport.get('merge-hashes')
 
944
        except errors.NoSuchFile:
 
945
            return {}
 
946
        try:
 
947
            merge_hashes = {}
 
948
            try:
 
949
                if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
 
950
                    raise errors.MergeModifiedFormatError()
 
951
            except StopIteration:
 
952
                raise errors.MergeModifiedFormatError()
 
953
            for s in RioReader(hashfile):
 
954
                # RioReader reads in Unicode, so convert file_ids back to utf8
 
955
                file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
 
956
                if file_id not in self.inventory:
 
957
                    continue
 
958
                text_hash = s.get("hash")
 
959
                if text_hash == self.get_file_sha1(file_id):
 
960
                    merge_hashes[file_id] = text_hash
 
961
            return merge_hashes
 
962
        finally:
 
963
            hashfile.close()
 
964
 
 
965
    @needs_write_lock
 
966
    def mkdir(self, path, file_id=None):
 
967
        """See MutableTree.mkdir()."""
 
968
        if file_id is None:
 
969
            file_id = generate_ids.gen_file_id(os.path.basename(path))
 
970
        os.mkdir(self.abspath(path))
 
971
        self.add(path, file_id, 'directory')
 
972
        return file_id
 
973
 
 
974
    def get_symlink_target(self, file_id):
 
975
        abspath = self.id2abspath(file_id)
 
976
        target = osutils.readlink(abspath)
 
977
        return target
 
978
 
 
979
    @needs_write_lock
 
980
    def subsume(self, other_tree):
 
981
        def add_children(inventory, entry):
 
982
            for child_entry in entry.children.values():
 
983
                inventory._byid[child_entry.file_id] = child_entry
 
984
                if child_entry.kind == 'directory':
 
985
                    add_children(inventory, child_entry)
 
986
        if other_tree.get_root_id() == self.get_root_id():
 
987
            raise errors.BadSubsumeSource(self, other_tree,
 
988
                                          'Trees have the same root')
 
989
        try:
 
990
            other_tree_path = self.relpath(other_tree.basedir)
 
991
        except errors.PathNotChild:
 
992
            raise errors.BadSubsumeSource(self, other_tree,
 
993
                'Tree is not contained by the other')
 
994
        new_root_parent = self.path2id(osutils.dirname(other_tree_path))
 
995
        if new_root_parent is None:
 
996
            raise errors.BadSubsumeSource(self, other_tree,
 
997
                'Parent directory is not versioned.')
 
998
        # We need to ensure that the result of a fetch will have a
 
999
        # versionedfile for the other_tree root, and only fetching into
 
1000
        # RepositoryKnit2 guarantees that.
 
1001
        if not self.branch.repository.supports_rich_root():
 
1002
            raise errors.SubsumeTargetNeedsUpgrade(other_tree)
 
1003
        other_tree.lock_tree_write()
 
1004
        try:
 
1005
            new_parents = other_tree.get_parent_ids()
 
1006
            other_root = other_tree.inventory.root
 
1007
            other_root.parent_id = new_root_parent
 
1008
            other_root.name = osutils.basename(other_tree_path)
 
1009
            self.inventory.add(other_root)
 
1010
            add_children(self.inventory, other_root)
 
1011
            self._write_inventory(self.inventory)
 
1012
            # normally we don't want to fetch whole repositories, but i think
 
1013
            # here we really do want to consolidate the whole thing.
 
1014
            for parent_id in other_tree.get_parent_ids():
 
1015
                self.branch.fetch(other_tree.branch, parent_id)
 
1016
                self.add_parent_tree_id(parent_id)
 
1017
        finally:
 
1018
            other_tree.unlock()
 
1019
        other_tree.bzrdir.retire_bzrdir()
 
1020
 
 
1021
    def _setup_directory_is_tree_reference(self):
 
1022
        if self._branch.repository._format.supports_tree_reference:
 
1023
            self._directory_is_tree_reference = \
 
1024
                self._directory_may_be_tree_reference
 
1025
        else:
 
1026
            self._directory_is_tree_reference = \
 
1027
                self._directory_is_never_tree_reference
 
1028
 
 
1029
    def _directory_is_never_tree_reference(self, relpath):
 
1030
        return False
 
1031
 
 
1032
    def _directory_may_be_tree_reference(self, relpath):
 
1033
        # as a special case, if a directory contains control files then
 
1034
        # it's a tree reference, except that the root of the tree is not
 
1035
        return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
 
1036
        # TODO: We could ask all the control formats whether they
 
1037
        # recognize this directory, but at the moment there's no cheap api
 
1038
        # to do that.  Since we probably can only nest bzr checkouts and
 
1039
        # they always use this name it's ok for now.  -- mbp 20060306
 
1040
        #
 
1041
        # FIXME: There is an unhandled case here of a subdirectory
 
1042
        # containing .bzr but not a branch; that will probably blow up
 
1043
        # when you try to commit it.  It might happen if there is a
 
1044
        # checkout in a subdirectory.  This can be avoided by not adding
 
1045
        # it.  mbp 20070306
 
1046
 
 
1047
    @needs_tree_write_lock
 
1048
    def extract(self, file_id, format=None):
 
1049
        """Extract a subtree from this tree.
 
1050
 
 
1051
        A new branch will be created, relative to the path for this tree.
 
1052
        """
 
1053
        self.flush()
 
1054
        def mkdirs(path):
 
1055
            segments = osutils.splitpath(path)
 
1056
            transport = self.branch.bzrdir.root_transport
 
1057
            for name in segments:
 
1058
                transport = transport.clone(name)
 
1059
                transport.ensure_base()
 
1060
            return transport
 
1061
 
 
1062
        sub_path = self.id2path(file_id)
 
1063
        branch_transport = mkdirs(sub_path)
 
1064
        if format is None:
 
1065
            format = self.bzrdir.cloning_metadir()
 
1066
        branch_transport.ensure_base()
 
1067
        branch_bzrdir = format.initialize_on_transport(branch_transport)
 
1068
        try:
 
1069
            repo = branch_bzrdir.find_repository()
 
1070
        except errors.NoRepositoryPresent:
 
1071
            repo = branch_bzrdir.create_repository()
 
1072
        if not repo.supports_rich_root():
 
1073
            raise errors.RootNotRich()
 
1074
        new_branch = branch_bzrdir.create_branch()
 
1075
        new_branch.pull(self.branch)
 
1076
        for parent_id in self.get_parent_ids():
 
1077
            new_branch.fetch(self.branch, parent_id)
 
1078
        tree_transport = self.bzrdir.root_transport.clone(sub_path)
 
1079
        if tree_transport.base != branch_transport.base:
 
1080
            tree_bzrdir = format.initialize_on_transport(tree_transport)
 
1081
            branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
 
1082
        else:
 
1083
            tree_bzrdir = branch_bzrdir
 
1084
        wt = tree_bzrdir.create_workingtree(NULL_REVISION)
 
1085
        wt.set_parent_ids(self.get_parent_ids())
 
1086
        my_inv = self.inventory
 
1087
        child_inv = Inventory(root_id=None)
 
1088
        new_root = my_inv[file_id]
 
1089
        my_inv.remove_recursive_id(file_id)
 
1090
        new_root.parent_id = None
 
1091
        child_inv.add(new_root)
 
1092
        self._write_inventory(my_inv)
 
1093
        wt._write_inventory(child_inv)
 
1094
        return wt
 
1095
 
 
1096
    def _serialize(self, inventory, out_file):
 
1097
        xml5.serializer_v5.write_inventory(self._inventory, out_file,
 
1098
            working=True)
 
1099
 
 
1100
    def _deserialize(selt, in_file):
 
1101
        return xml5.serializer_v5.read_inventory(in_file)
 
1102
 
 
1103
    def flush(self):
 
1104
        """Write the in memory inventory to disk."""
 
1105
        # TODO: Maybe this should only write on dirty ?
 
1106
        if self._control_files._lock_mode != 'w':
 
1107
            raise errors.NotWriteLocked(self)
 
1108
        sio = StringIO()
 
1109
        self._serialize(self._inventory, sio)
 
1110
        sio.seek(0)
 
1111
        self._transport.put_file('inventory', sio,
 
1112
            mode=self.bzrdir._get_file_mode())
 
1113
        self._inventory_is_modified = False
 
1114
 
 
1115
    def _kind(self, relpath):
 
1116
        return osutils.file_kind(self.abspath(relpath))
 
1117
 
 
1118
    def list_files(self, include_root=False, from_dir=None, recursive=True):
 
1119
        """List all files as (path, class, kind, id, entry).
132
1120
 
133
1121
        Lists, but does not descend into unversioned directories.
134
 
 
135
1122
        This does not include files that have been deleted in this
136
 
        tree.
 
1123
        tree. Skips the control directory.
137
1124
 
138
 
        Skips the control directory.
 
1125
        :param include_root: if True, do not return an entry for the root
 
1126
        :param from_dir: start from this directory or None for the root
 
1127
        :param recursive: whether to recurse into subdirectories or not
139
1128
        """
140
 
        inv = self._inventory
141
 
 
142
 
        def descend(from_dir_relpath, from_dir_id, dp):
143
 
            ls = os.listdir(dp)
144
 
            ls.sort()
145
 
            for f in ls:
 
1129
        # list_files is an iterator, so @needs_read_lock doesn't work properly
 
1130
        # with it. So callers should be careful to always read_lock the tree.
 
1131
        if not self.is_locked():
 
1132
            raise errors.ObjectNotLocked(self)
 
1133
 
 
1134
        inv = self.inventory
 
1135
        if from_dir is None and include_root is True:
 
1136
            yield ('', 'V', 'directory', inv.root.file_id, inv.root)
 
1137
        # Convert these into local objects to save lookup times
 
1138
        pathjoin = osutils.pathjoin
 
1139
        file_kind = self._kind
 
1140
 
 
1141
        # transport.base ends in a slash, we want the piece
 
1142
        # between the last two slashes
 
1143
        transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
 
1144
 
 
1145
        fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
 
1146
 
 
1147
        # directory file_id, relative path, absolute path, reverse sorted children
 
1148
        if from_dir is not None:
 
1149
            from_dir_id = inv.path2id(from_dir)
 
1150
            if from_dir_id is None:
 
1151
                # Directory not versioned
 
1152
                return
 
1153
            from_dir_abspath = pathjoin(self.basedir, from_dir)
 
1154
        else:
 
1155
            from_dir_id = inv.root.file_id
 
1156
            from_dir_abspath = self.basedir
 
1157
        children = os.listdir(from_dir_abspath)
 
1158
        children.sort()
 
1159
        # jam 20060527 The kernel sized tree seems equivalent whether we
 
1160
        # use a deque and popleft to keep them sorted, or if we use a plain
 
1161
        # list and just reverse() them.
 
1162
        children = collections.deque(children)
 
1163
        stack = [(from_dir_id, u'', from_dir_abspath, children)]
 
1164
        while stack:
 
1165
            from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
 
1166
 
 
1167
            while children:
 
1168
                f = children.popleft()
146
1169
                ## TODO: If we find a subdirectory with its own .bzr
147
1170
                ## directory, then that is a separate tree and we
148
1171
                ## should exclude it.
149
 
                if bzrlib.BZRDIR == f:
 
1172
 
 
1173
                # the bzrdir for this tree
 
1174
                if transport_base_dir == f:
150
1175
                    continue
151
1176
 
152
 
                # path within tree
153
 
                fp = appendpath(from_dir_relpath, f)
 
1177
                # we know that from_dir_relpath and from_dir_abspath never end in a slash
 
1178
                # and 'f' doesn't begin with one, we can do a string op, rather
 
1179
                # than the checks of pathjoin(), all relative paths will have an extra slash
 
1180
                # at the beginning
 
1181
                fp = from_dir_relpath + '/' + f
154
1182
 
155
1183
                # absolute path
156
 
                fap = appendpath(dp, f)
157
 
                
 
1184
                fap = from_dir_abspath + '/' + f
 
1185
 
158
1186
                f_ie = inv.get_child(from_dir_id, f)
159
1187
                if f_ie:
160
1188
                    c = 'V'
161
 
                elif self.is_ignored(fp):
 
1189
                elif self.is_ignored(fp[1:]):
162
1190
                    c = 'I'
163
1191
                else:
164
 
                    c = '?'
 
1192
                    # we may not have found this file, because of a unicode issue
 
1193
                    f_norm, can_access = osutils.normalized_filename(f)
 
1194
                    if f == f_norm or not can_access:
 
1195
                        # No change, so treat this file normally
 
1196
                        c = '?'
 
1197
                    else:
 
1198
                        # this file can be accessed by a normalized path
 
1199
                        # check again if it is versioned
 
1200
                        # these lines are repeated here for performance
 
1201
                        f = f_norm
 
1202
                        fp = from_dir_relpath + '/' + f
 
1203
                        fap = from_dir_abspath + '/' + f
 
1204
                        f_ie = inv.get_child(from_dir_id, f)
 
1205
                        if f_ie:
 
1206
                            c = 'V'
 
1207
                        elif self.is_ignored(fp[1:]):
 
1208
                            c = 'I'
 
1209
                        else:
 
1210
                            c = '?'
165
1211
 
166
1212
                fk = file_kind(fap)
167
1213
 
 
1214
                # make a last minute entry
168
1215
                if f_ie:
169
 
                    if f_ie.kind != fk:
170
 
                        raise BzrCheckError("file %r entered as kind %r id %r, "
171
 
                                            "now of kind %r"
172
 
                                            % (fap, f_ie.kind, f_ie.file_id, fk))
173
 
 
174
 
                yield fp, c, fk, (f_ie and f_ie.file_id)
 
1216
                    yield fp[1:], c, fk, f_ie.file_id, f_ie
 
1217
                else:
 
1218
                    try:
 
1219
                        yield fp[1:], c, fk, None, fk_entries[fk]()
 
1220
                    except KeyError:
 
1221
                        yield fp[1:], c, fk, None, TreeEntry()
 
1222
                    continue
175
1223
 
176
1224
                if fk != 'directory':
177
1225
                    continue
178
1226
 
179
 
                if c != 'V':
180
 
                    # don't descend unversioned directories
181
 
                    continue
182
 
                
183
 
                for ff in descend(fp, f_ie.file_id, fap):
184
 
                    yield ff
185
 
 
186
 
        for f in descend('', inv.root.file_id, self.basedir):
187
 
            yield f
188
 
            
189
 
 
190
 
 
 
1227
                # But do this child first if recursing down
 
1228
                if recursive:
 
1229
                    new_children = os.listdir(fap)
 
1230
                    new_children.sort()
 
1231
                    new_children = collections.deque(new_children)
 
1232
                    stack.append((f_ie.file_id, fp, fap, new_children))
 
1233
                    # Break out of inner loop,
 
1234
                    # so that we start outer loop with child
 
1235
                    break
 
1236
            else:
 
1237
                # if we finished all children, pop it off the stack
 
1238
                stack.pop()
 
1239
 
 
1240
    @needs_tree_write_lock
 
1241
    def move(self, from_paths, to_dir=None, after=False, **kwargs):
 
1242
        """Rename files.
 
1243
 
 
1244
        to_dir must exist in the inventory.
 
1245
 
 
1246
        If to_dir exists and is a directory, the files are moved into
 
1247
        it, keeping their old names.
 
1248
 
 
1249
        Note that to_dir is only the last component of the new name;
 
1250
        this doesn't change the directory.
 
1251
 
 
1252
        For each entry in from_paths the move mode will be determined
 
1253
        independently.
 
1254
 
 
1255
        The first mode moves the file in the filesystem and updates the
 
1256
        inventory. The second mode only updates the inventory without
 
1257
        touching the file on the filesystem. This is the new mode introduced
 
1258
        in version 0.15.
 
1259
 
 
1260
        move uses the second mode if 'after == True' and the target is not
 
1261
        versioned but present in the working tree.
 
1262
 
 
1263
        move uses the second mode if 'after == False' and the source is
 
1264
        versioned but no longer in the working tree, and the target is not
 
1265
        versioned but present in the working tree.
 
1266
 
 
1267
        move uses the first mode if 'after == False' and the source is
 
1268
        versioned and present in the working tree, and the target is not
 
1269
        versioned and not present in the working tree.
 
1270
 
 
1271
        Everything else results in an error.
 
1272
 
 
1273
        This returns a list of (from_path, to_path) pairs for each
 
1274
        entry that is moved.
 
1275
        """
 
1276
        rename_entries = []
 
1277
        rename_tuples = []
 
1278
 
 
1279
        # check for deprecated use of signature
 
1280
        if to_dir is None:
 
1281
            to_dir = kwargs.get('to_name', None)
 
1282
            if to_dir is None:
 
1283
                raise TypeError('You must supply a target directory')
 
1284
            else:
 
1285
                symbol_versioning.warn('The parameter to_name was deprecated'
 
1286
                                       ' in version 0.13. Use to_dir instead',
 
1287
                                       DeprecationWarning)
 
1288
 
 
1289
        # check destination directory
 
1290
        if isinstance(from_paths, basestring):
 
1291
            raise ValueError()
 
1292
        inv = self.inventory
 
1293
        to_abs = self.abspath(to_dir)
 
1294
        if not isdir(to_abs):
 
1295
            raise errors.BzrMoveFailedError('',to_dir,
 
1296
                errors.NotADirectory(to_abs))
 
1297
        if not self.has_filename(to_dir):
 
1298
            raise errors.BzrMoveFailedError('',to_dir,
 
1299
                errors.NotInWorkingDirectory(to_dir))
 
1300
        to_dir_id = inv.path2id(to_dir)
 
1301
        if to_dir_id is None:
 
1302
            raise errors.BzrMoveFailedError('',to_dir,
 
1303
                errors.NotVersionedError(path=str(to_dir)))
 
1304
 
 
1305
        to_dir_ie = inv[to_dir_id]
 
1306
        if to_dir_ie.kind != 'directory':
 
1307
            raise errors.BzrMoveFailedError('',to_dir,
 
1308
                errors.NotADirectory(to_abs))
 
1309
 
 
1310
        # create rename entries and tuples
 
1311
        for from_rel in from_paths:
 
1312
            from_tail = splitpath(from_rel)[-1]
 
1313
            from_id = inv.path2id(from_rel)
 
1314
            if from_id is None:
 
1315
                raise errors.BzrMoveFailedError(from_rel,to_dir,
 
1316
                    errors.NotVersionedError(path=str(from_rel)))
 
1317
 
 
1318
            from_entry = inv[from_id]
 
1319
            from_parent_id = from_entry.parent_id
 
1320
            to_rel = pathjoin(to_dir, from_tail)
 
1321
            rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
 
1322
                                         from_id=from_id,
 
1323
                                         from_tail=from_tail,
 
1324
                                         from_parent_id=from_parent_id,
 
1325
                                         to_rel=to_rel, to_tail=from_tail,
 
1326
                                         to_parent_id=to_dir_id)
 
1327
            rename_entries.append(rename_entry)
 
1328
            rename_tuples.append((from_rel, to_rel))
 
1329
 
 
1330
        # determine which move mode to use. checks also for movability
 
1331
        rename_entries = self._determine_mv_mode(rename_entries, after)
 
1332
 
 
1333
        original_modified = self._inventory_is_modified
 
1334
        try:
 
1335
            if len(from_paths):
 
1336
                self._inventory_is_modified = True
 
1337
            self._move(rename_entries)
 
1338
        except:
 
1339
            # restore the inventory on error
 
1340
            self._inventory_is_modified = original_modified
 
1341
            raise
 
1342
        self._write_inventory(inv)
 
1343
        return rename_tuples
 
1344
 
 
1345
    def _determine_mv_mode(self, rename_entries, after=False):
 
1346
        """Determines for each from-to pair if both inventory and working tree
 
1347
        or only the inventory has to be changed.
 
1348
 
 
1349
        Also does basic plausability tests.
 
1350
        """
 
1351
        inv = self.inventory
 
1352
 
 
1353
        for rename_entry in rename_entries:
 
1354
            # store to local variables for easier reference
 
1355
            from_rel = rename_entry.from_rel
 
1356
            from_id = rename_entry.from_id
 
1357
            to_rel = rename_entry.to_rel
 
1358
            to_id = inv.path2id(to_rel)
 
1359
            only_change_inv = False
 
1360
 
 
1361
            # check the inventory for source and destination
 
1362
            if from_id is None:
 
1363
                raise errors.BzrMoveFailedError(from_rel,to_rel,
 
1364
                    errors.NotVersionedError(path=str(from_rel)))
 
1365
            if to_id is not None:
 
1366
                raise errors.BzrMoveFailedError(from_rel,to_rel,
 
1367
                    errors.AlreadyVersionedError(path=str(to_rel)))
 
1368
 
 
1369
            # try to determine the mode for rename (only change inv or change
 
1370
            # inv and file system)
 
1371
            if after:
 
1372
                if not self.has_filename(to_rel):
 
1373
                    raise errors.BzrMoveFailedError(from_id,to_rel,
 
1374
                        errors.NoSuchFile(path=str(to_rel),
 
1375
                        extra="New file has not been created yet"))
 
1376
                only_change_inv = True
 
1377
            elif not self.has_filename(from_rel) and self.has_filename(to_rel):
 
1378
                only_change_inv = True
 
1379
            elif self.has_filename(from_rel) and not self.has_filename(to_rel):
 
1380
                only_change_inv = False
 
1381
            elif (not self.case_sensitive
 
1382
                  and from_rel.lower() == to_rel.lower()
 
1383
                  and self.has_filename(from_rel)):
 
1384
                only_change_inv = False
 
1385
            else:
 
1386
                # something is wrong, so lets determine what exactly
 
1387
                if not self.has_filename(from_rel) and \
 
1388
                   not self.has_filename(to_rel):
 
1389
                    raise errors.BzrRenameFailedError(from_rel,to_rel,
 
1390
                        errors.PathsDoNotExist(paths=(str(from_rel),
 
1391
                        str(to_rel))))
 
1392
                else:
 
1393
                    raise errors.RenameFailedFilesExist(from_rel, to_rel)
 
1394
            rename_entry.only_change_inv = only_change_inv
 
1395
        return rename_entries
 
1396
 
 
1397
    def _move(self, rename_entries):
 
1398
        """Moves a list of files.
 
1399
 
 
1400
        Depending on the value of the flag 'only_change_inv', the
 
1401
        file will be moved on the file system or not.
 
1402
        """
 
1403
        inv = self.inventory
 
1404
        moved = []
 
1405
 
 
1406
        for entry in rename_entries:
 
1407
            try:
 
1408
                self._move_entry(entry)
 
1409
            except:
 
1410
                self._rollback_move(moved)
 
1411
                raise
 
1412
            moved.append(entry)
 
1413
 
 
1414
    def _rollback_move(self, moved):
 
1415
        """Try to rollback a previous move in case of an filesystem error."""
 
1416
        inv = self.inventory
 
1417
        for entry in moved:
 
1418
            try:
 
1419
                self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
 
1420
                    entry.to_tail, entry.to_parent_id, entry.from_rel,
 
1421
                    entry.from_tail, entry.from_parent_id,
 
1422
                    entry.only_change_inv))
 
1423
            except errors.BzrMoveFailedError, e:
 
1424
                raise errors.BzrMoveFailedError( '', '', "Rollback failed."
 
1425
                        " The working tree is in an inconsistent state."
 
1426
                        " Please consider doing a 'bzr revert'."
 
1427
                        " Error message is: %s" % e)
 
1428
 
 
1429
    def _move_entry(self, entry):
 
1430
        inv = self.inventory
 
1431
        from_rel_abs = self.abspath(entry.from_rel)
 
1432
        to_rel_abs = self.abspath(entry.to_rel)
 
1433
        if from_rel_abs == to_rel_abs:
 
1434
            raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
 
1435
                "Source and target are identical.")
 
1436
 
 
1437
        if not entry.only_change_inv:
 
1438
            try:
 
1439
                osutils.rename(from_rel_abs, to_rel_abs)
 
1440
            except OSError, e:
 
1441
                raise errors.BzrMoveFailedError(entry.from_rel,
 
1442
                    entry.to_rel, e[1])
 
1443
        inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
 
1444
 
 
1445
    @needs_tree_write_lock
 
1446
    def rename_one(self, from_rel, to_rel, after=False):
 
1447
        """Rename one file.
 
1448
 
 
1449
        This can change the directory or the filename or both.
 
1450
 
 
1451
        rename_one has several 'modes' to work. First, it can rename a physical
 
1452
        file and change the file_id. That is the normal mode. Second, it can
 
1453
        only change the file_id without touching any physical file. This is
 
1454
        the new mode introduced in version 0.15.
 
1455
 
 
1456
        rename_one uses the second mode if 'after == True' and 'to_rel' is not
 
1457
        versioned but present in the working tree.
 
1458
 
 
1459
        rename_one uses the second mode if 'after == False' and 'from_rel' is
 
1460
        versioned but no longer in the working tree, and 'to_rel' is not
 
1461
        versioned but present in the working tree.
 
1462
 
 
1463
        rename_one uses the first mode if 'after == False' and 'from_rel' is
 
1464
        versioned and present in the working tree, and 'to_rel' is not
 
1465
        versioned and not present in the working tree.
 
1466
 
 
1467
        Everything else results in an error.
 
1468
        """
 
1469
        inv = self.inventory
 
1470
        rename_entries = []
 
1471
 
 
1472
        # create rename entries and tuples
 
1473
        from_tail = splitpath(from_rel)[-1]
 
1474
        from_id = inv.path2id(from_rel)
 
1475
        if from_id is None:
 
1476
            raise errors.BzrRenameFailedError(from_rel,to_rel,
 
1477
                errors.NotVersionedError(path=str(from_rel)))
 
1478
        from_entry = inv[from_id]
 
1479
        from_parent_id = from_entry.parent_id
 
1480
        to_dir, to_tail = os.path.split(to_rel)
 
1481
        to_dir_id = inv.path2id(to_dir)
 
1482
        rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
 
1483
                                     from_id=from_id,
 
1484
                                     from_tail=from_tail,
 
1485
                                     from_parent_id=from_parent_id,
 
1486
                                     to_rel=to_rel, to_tail=to_tail,
 
1487
                                     to_parent_id=to_dir_id)
 
1488
        rename_entries.append(rename_entry)
 
1489
 
 
1490
        # determine which move mode to use. checks also for movability
 
1491
        rename_entries = self._determine_mv_mode(rename_entries, after)
 
1492
 
 
1493
        # check if the target changed directory and if the target directory is
 
1494
        # versioned
 
1495
        if to_dir_id is None:
 
1496
            raise errors.BzrMoveFailedError(from_rel,to_rel,
 
1497
                errors.NotVersionedError(path=str(to_dir)))
 
1498
 
 
1499
        # all checks done. now we can continue with our actual work
 
1500
        mutter('rename_one:\n'
 
1501
               '  from_id   {%s}\n'
 
1502
               '  from_rel: %r\n'
 
1503
               '  to_rel:   %r\n'
 
1504
               '  to_dir    %r\n'
 
1505
               '  to_dir_id {%s}\n',
 
1506
               from_id, from_rel, to_rel, to_dir, to_dir_id)
 
1507
 
 
1508
        self._move(rename_entries)
 
1509
        self._write_inventory(inv)
 
1510
 
 
1511
    class _RenameEntry(object):
 
1512
        def __init__(self, from_rel, from_id, from_tail, from_parent_id,
 
1513
                     to_rel, to_tail, to_parent_id, only_change_inv=False):
 
1514
            self.from_rel = from_rel
 
1515
            self.from_id = from_id
 
1516
            self.from_tail = from_tail
 
1517
            self.from_parent_id = from_parent_id
 
1518
            self.to_rel = to_rel
 
1519
            self.to_tail = to_tail
 
1520
            self.to_parent_id = to_parent_id
 
1521
            self.only_change_inv = only_change_inv
 
1522
 
 
1523
    @needs_read_lock
191
1524
    def unknowns(self):
192
 
        for subp in self.extras():
193
 
            if not self.is_ignored(subp):
194
 
                yield subp
195
 
 
 
1525
        """Return all unknown files.
 
1526
 
 
1527
        These are files in the working directory that are not versioned or
 
1528
        control files or ignored.
 
1529
        """
 
1530
        # force the extras method to be fully executed before returning, to
 
1531
        # prevent race conditions with the lock
 
1532
        return iter(
 
1533
            [subp for subp in self.extras() if not self.is_ignored(subp)])
 
1534
 
 
1535
    @needs_tree_write_lock
 
1536
    def unversion(self, file_ids):
 
1537
        """Remove the file ids in file_ids from the current versioned set.
 
1538
 
 
1539
        When a file_id is unversioned, all of its children are automatically
 
1540
        unversioned.
 
1541
 
 
1542
        :param file_ids: The file ids to stop versioning.
 
1543
        :raises: NoSuchId if any fileid is not currently versioned.
 
1544
        """
 
1545
        for file_id in file_ids:
 
1546
            if file_id not in self._inventory:
 
1547
                raise errors.NoSuchId(self, file_id)
 
1548
        for file_id in file_ids:
 
1549
            if self._inventory.has_id(file_id):
 
1550
                self._inventory.remove_recursive_id(file_id)
 
1551
        if len(file_ids):
 
1552
            # in the future this should just set a dirty bit to wait for the
 
1553
            # final unlock. However, until all methods of workingtree start
 
1554
            # with the current in -memory inventory rather than triggering
 
1555
            # a read, it is more complex - we need to teach read_inventory
 
1556
            # to know when to read, and when to not read first... and possibly
 
1557
            # to save first when the in memory one may be corrupted.
 
1558
            # so for now, we just only write it if it is indeed dirty.
 
1559
            # - RBC 20060907
 
1560
            self._write_inventory(self._inventory)
 
1561
 
 
1562
    def _iter_conflicts(self):
 
1563
        conflicted = set()
 
1564
        for info in self.list_files():
 
1565
            path = info[0]
 
1566
            stem = get_conflicted_stem(path)
 
1567
            if stem is None:
 
1568
                continue
 
1569
            if stem not in conflicted:
 
1570
                conflicted.add(stem)
 
1571
                yield stem
 
1572
 
 
1573
    @needs_write_lock
 
1574
    def pull(self, source, overwrite=False, stop_revision=None,
 
1575
             change_reporter=None, possible_transports=None, local=False):
 
1576
        top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1577
        source.lock_read()
 
1578
        try:
 
1579
            pp = ProgressPhase("Pull phase", 2, top_pb)
 
1580
            pp.next_phase()
 
1581
            old_revision_info = self.branch.last_revision_info()
 
1582
            basis_tree = self.basis_tree()
 
1583
            count = self.branch.pull(source, overwrite, stop_revision,
 
1584
                                     possible_transports=possible_transports,
 
1585
                                     local=local)
 
1586
            new_revision_info = self.branch.last_revision_info()
 
1587
            if new_revision_info != old_revision_info:
 
1588
                pp.next_phase()
 
1589
                repository = self.branch.repository
 
1590
                pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1591
                basis_tree.lock_read()
 
1592
                try:
 
1593
                    new_basis_tree = self.branch.basis_tree()
 
1594
                    merge.merge_inner(
 
1595
                                self.branch,
 
1596
                                new_basis_tree,
 
1597
                                basis_tree,
 
1598
                                this_tree=self,
 
1599
                                pb=pb,
 
1600
                                change_reporter=change_reporter)
 
1601
                    if (basis_tree.inventory.root is None and
 
1602
                        new_basis_tree.inventory.root is not None):
 
1603
                        self.set_root_id(new_basis_tree.get_root_id())
 
1604
                finally:
 
1605
                    pb.finished()
 
1606
                    basis_tree.unlock()
 
1607
                # TODO - dedup parents list with things merged by pull ?
 
1608
                # reuse the revisiontree we merged against to set the new
 
1609
                # tree data.
 
1610
                parent_trees = [(self.branch.last_revision(), new_basis_tree)]
 
1611
                # we have to pull the merge trees out again, because
 
1612
                # merge_inner has set the ids. - this corner is not yet
 
1613
                # layered well enough to prevent double handling.
 
1614
                # XXX TODO: Fix the double handling: telling the tree about
 
1615
                # the already known parent data is wasteful.
 
1616
                merges = self.get_parent_ids()[1:]
 
1617
                parent_trees.extend([
 
1618
                    (parent, repository.revision_tree(parent)) for
 
1619
                     parent in merges])
 
1620
                self.set_parent_trees(parent_trees)
 
1621
            return count
 
1622
        finally:
 
1623
            source.unlock()
 
1624
            top_pb.finished()
 
1625
 
 
1626
    @needs_write_lock
 
1627
    def put_file_bytes_non_atomic(self, file_id, bytes):
 
1628
        """See MutableTree.put_file_bytes_non_atomic."""
 
1629
        stream = file(self.id2abspath(file_id), 'wb')
 
1630
        try:
 
1631
            stream.write(bytes)
 
1632
        finally:
 
1633
            stream.close()
 
1634
        # TODO: update the hashcache here ?
196
1635
 
197
1636
    def extras(self):
198
 
        """Yield all unknown files in this WorkingTree.
 
1637
        """Yield all unversioned files in this WorkingTree.
199
1638
 
200
 
        If there are any unknown directories then only the directory is
201
 
        returned, not all its children.  But if there are unknown files
 
1639
        If there are any unversioned directories then only the directory is
 
1640
        returned, not all its children.  But if there are unversioned files
202
1641
        under a versioned subdirectory, they are returned.
203
1642
 
204
1643
        Currently returned depth-first, sorted by name within directories.
 
1644
        This is the same order used by 'osutils.walkdirs'.
205
1645
        """
206
1646
        ## TODO: Work from given directory downwards
207
1647
        for path, dir_entry in self.inventory.directories():
208
 
            mutter("search for unknowns in %r" % path)
 
1648
            # mutter("search for unknowns in %r", path)
209
1649
            dirabs = self.abspath(path)
210
1650
            if not isdir(dirabs):
211
1651
                # e.g. directory deleted
213
1653
 
214
1654
            fl = []
215
1655
            for subf in os.listdir(dirabs):
216
 
                if (subf != '.bzr'
217
 
                    and (subf not in dir_entry.children)):
218
 
                    fl.append(subf)
219
 
            
 
1656
                if self.bzrdir.is_control_filename(subf):
 
1657
                    continue
 
1658
                if subf not in dir_entry.children:
 
1659
                    try:
 
1660
                        (subf_norm,
 
1661
                         can_access) = osutils.normalized_filename(subf)
 
1662
                    except UnicodeDecodeError:
 
1663
                        path_os_enc = path.encode(osutils._fs_enc)
 
1664
                        relpath = path_os_enc + '/' + subf
 
1665
                        raise errors.BadFilenameEncoding(relpath,
 
1666
                                                         osutils._fs_enc)
 
1667
                    if subf_norm != subf and can_access:
 
1668
                        if subf_norm not in dir_entry.children:
 
1669
                            fl.append(subf_norm)
 
1670
                    else:
 
1671
                        fl.append(subf)
 
1672
 
220
1673
            fl.sort()
221
1674
            for subf in fl:
222
 
                subp = appendpath(path, subf)
 
1675
                subp = pathjoin(path, subf)
223
1676
                yield subp
224
1677
 
225
 
 
226
1678
    def ignored_files(self):
227
1679
        """Yield list of PATH, IGNORE_PATTERN"""
228
1680
        for subp in self.extras():
229
1681
            pat = self.is_ignored(subp)
230
 
            if pat != None:
 
1682
            if pat is not None:
231
1683
                yield subp, pat
232
1684
 
233
 
 
234
1685
    def get_ignore_list(self):
235
1686
        """Return list of ignore patterns.
236
1687
 
237
1688
        Cached in the Tree object after the first call.
238
1689
        """
239
 
        if hasattr(self, '_ignorelist'):
240
 
            return self._ignorelist
 
1690
        ignoreset = getattr(self, '_ignoreset', None)
 
1691
        if ignoreset is not None:
 
1692
            return ignoreset
241
1693
 
242
 
        l = bzrlib.DEFAULT_IGNORE[:]
 
1694
        ignore_globs = set()
 
1695
        ignore_globs.update(ignores.get_runtime_ignores())
 
1696
        ignore_globs.update(ignores.get_user_ignores())
243
1697
        if self.has_filename(bzrlib.IGNORE_FILENAME):
244
1698
            f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
245
 
            l.extend([line.rstrip("\n\r") for line in f.readlines()])
246
 
        self._ignorelist = l
247
 
        return l
 
1699
            try:
 
1700
                ignore_globs.update(ignores.parse_ignore_file(f))
 
1701
            finally:
 
1702
                f.close()
 
1703
        self._ignoreset = ignore_globs
 
1704
        return ignore_globs
248
1705
 
 
1706
    def _flush_ignore_list_cache(self):
 
1707
        """Resets the cached ignore list to force a cache rebuild."""
 
1708
        self._ignoreset = None
 
1709
        self._ignoreglobster = None
249
1710
 
250
1711
    def is_ignored(self, filename):
251
1712
        r"""Check whether the filename matches an ignore pattern.
256
1717
        If the file is ignored, returns the pattern which caused it to
257
1718
        be ignored, otherwise None.  So this can simply be used as a
258
1719
        boolean if desired."""
259
 
 
260
 
        # TODO: Use '**' to match directories, and other extended
261
 
        # globbing stuff from cvs/rsync.
262
 
 
263
 
        # XXX: fnmatch is actually not quite what we want: it's only
264
 
        # approximately the same as real Unix fnmatch, and doesn't
265
 
        # treat dotfiles correctly and allows * to match /.
266
 
        # Eventually it should be replaced with something more
267
 
        # accurate.
268
 
        
269
 
        for pat in self.get_ignore_list():
270
 
            if '/' in pat or '\\' in pat:
271
 
                
272
 
                # as a special case, you can put ./ at the start of a
273
 
                # pattern; this is good to match in the top-level
274
 
                # only;
275
 
                
276
 
                if (pat[:2] == './') or (pat[:2] == '.\\'):
277
 
                    newpat = pat[2:]
 
1720
        if getattr(self, '_ignoreglobster', None) is None:
 
1721
            self._ignoreglobster = globbing.Globster(self.get_ignore_list())
 
1722
        return self._ignoreglobster.match(filename)
 
1723
 
 
1724
    def kind(self, file_id):
 
1725
        return file_kind(self.id2abspath(file_id))
 
1726
 
 
1727
    def stored_kind(self, file_id):
 
1728
        """See Tree.stored_kind"""
 
1729
        return self.inventory[file_id].kind
 
1730
 
 
1731
    def _comparison_data(self, entry, path):
 
1732
        abspath = self.abspath(path)
 
1733
        try:
 
1734
            stat_value = os.lstat(abspath)
 
1735
        except OSError, e:
 
1736
            if getattr(e, 'errno', None) == errno.ENOENT:
 
1737
                stat_value = None
 
1738
                kind = None
 
1739
                executable = False
 
1740
            else:
 
1741
                raise
 
1742
        else:
 
1743
            mode = stat_value.st_mode
 
1744
            kind = osutils.file_kind_from_stat_mode(mode)
 
1745
            if not supports_executable():
 
1746
                executable = entry is not None and entry.executable
 
1747
            else:
 
1748
                executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
 
1749
        return kind, executable, stat_value
 
1750
 
 
1751
    def _file_size(self, entry, stat_value):
 
1752
        return stat_value.st_size
 
1753
 
 
1754
    def last_revision(self):
 
1755
        """Return the last revision of the branch for this tree.
 
1756
 
 
1757
        This format tree does not support a separate marker for last-revision
 
1758
        compared to the branch.
 
1759
 
 
1760
        See MutableTree.last_revision
 
1761
        """
 
1762
        return self._last_revision()
 
1763
 
 
1764
    @needs_read_lock
 
1765
    def _last_revision(self):
 
1766
        """helper for get_parent_ids."""
 
1767
        return _mod_revision.ensure_null(self.branch.last_revision())
 
1768
 
 
1769
    def is_locked(self):
 
1770
        return self._control_files.is_locked()
 
1771
 
 
1772
    def _must_be_locked(self):
 
1773
        if not self.is_locked():
 
1774
            raise errors.ObjectNotLocked(self)
 
1775
 
 
1776
    def lock_read(self):
 
1777
        """See Branch.lock_read, and WorkingTree.unlock."""
 
1778
        if not self.is_locked():
 
1779
            self._reset_data()
 
1780
        self.branch.lock_read()
 
1781
        try:
 
1782
            return self._control_files.lock_read()
 
1783
        except:
 
1784
            self.branch.unlock()
 
1785
            raise
 
1786
 
 
1787
    def lock_tree_write(self):
 
1788
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
1789
        if not self.is_locked():
 
1790
            self._reset_data()
 
1791
        self.branch.lock_read()
 
1792
        try:
 
1793
            return self._control_files.lock_write()
 
1794
        except:
 
1795
            self.branch.unlock()
 
1796
            raise
 
1797
 
 
1798
    def lock_write(self):
 
1799
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
1800
        if not self.is_locked():
 
1801
            self._reset_data()
 
1802
        self.branch.lock_write()
 
1803
        try:
 
1804
            return self._control_files.lock_write()
 
1805
        except:
 
1806
            self.branch.unlock()
 
1807
            raise
 
1808
 
 
1809
    def get_physical_lock_status(self):
 
1810
        return self._control_files.get_physical_lock_status()
 
1811
 
 
1812
    def _basis_inventory_name(self):
 
1813
        return 'basis-inventory-cache'
 
1814
 
 
1815
    def _reset_data(self):
 
1816
        """Reset transient data that cannot be revalidated."""
 
1817
        self._inventory_is_modified = False
 
1818
        result = self._deserialize(self._transport.get('inventory'))
 
1819
        self._set_inventory(result, dirty=False)
 
1820
 
 
1821
    @needs_tree_write_lock
 
1822
    def set_last_revision(self, new_revision):
 
1823
        """Change the last revision in the working tree."""
 
1824
        if self._change_last_revision(new_revision):
 
1825
            self._cache_basis_inventory(new_revision)
 
1826
 
 
1827
    def _change_last_revision(self, new_revision):
 
1828
        """Template method part of set_last_revision to perform the change.
 
1829
 
 
1830
        This is used to allow WorkingTree3 instances to not affect branch
 
1831
        when their last revision is set.
 
1832
        """
 
1833
        if _mod_revision.is_null(new_revision):
 
1834
            self.branch.set_revision_history([])
 
1835
            return False
 
1836
        try:
 
1837
            self.branch.generate_revision_history(new_revision)
 
1838
        except errors.NoSuchRevision:
 
1839
            # not present in the repo - dont try to set it deeper than the tip
 
1840
            self.branch.set_revision_history([new_revision])
 
1841
        return True
 
1842
 
 
1843
    def _write_basis_inventory(self, xml):
 
1844
        """Write the basis inventory XML to the basis-inventory file"""
 
1845
        path = self._basis_inventory_name()
 
1846
        sio = StringIO(xml)
 
1847
        self._transport.put_file(path, sio,
 
1848
            mode=self.bzrdir._get_file_mode())
 
1849
 
 
1850
    def _create_basis_xml_from_inventory(self, revision_id, inventory):
 
1851
        """Create the text that will be saved in basis-inventory"""
 
1852
        inventory.revision_id = revision_id
 
1853
        return xml7.serializer_v7.write_inventory_to_string(inventory)
 
1854
 
 
1855
    def _cache_basis_inventory(self, new_revision):
 
1856
        """Cache new_revision as the basis inventory."""
 
1857
        # TODO: this should allow the ready-to-use inventory to be passed in,
 
1858
        # as commit already has that ready-to-use [while the format is the
 
1859
        # same, that is].
 
1860
        try:
 
1861
            # this double handles the inventory - unpack and repack -
 
1862
            # but is easier to understand. We can/should put a conditional
 
1863
            # in here based on whether the inventory is in the latest format
 
1864
            # - perhaps we should repack all inventories on a repository
 
1865
            # upgrade ?
 
1866
            # the fast path is to copy the raw xml from the repository. If the
 
1867
            # xml contains 'revision_id="', then we assume the right
 
1868
            # revision_id is set. We must check for this full string, because a
 
1869
            # root node id can legitimately look like 'revision_id' but cannot
 
1870
            # contain a '"'.
 
1871
            xml = self.branch.repository.get_inventory_xml(new_revision)
 
1872
            firstline = xml.split('\n', 1)[0]
 
1873
            if (not 'revision_id="' in firstline or
 
1874
                'format="7"' not in firstline):
 
1875
                inv = self.branch.repository.deserialise_inventory(
 
1876
                    new_revision, xml)
 
1877
                xml = self._create_basis_xml_from_inventory(new_revision, inv)
 
1878
            self._write_basis_inventory(xml)
 
1879
        except (errors.NoSuchRevision, errors.RevisionNotPresent):
 
1880
            pass
 
1881
 
 
1882
    def read_basis_inventory(self):
 
1883
        """Read the cached basis inventory."""
 
1884
        path = self._basis_inventory_name()
 
1885
        return self._transport.get_bytes(path)
 
1886
 
 
1887
    @needs_read_lock
 
1888
    def read_working_inventory(self):
 
1889
        """Read the working inventory.
 
1890
 
 
1891
        :raises errors.InventoryModified: read_working_inventory will fail
 
1892
            when the current in memory inventory has been modified.
 
1893
        """
 
1894
        # conceptually this should be an implementation detail of the tree.
 
1895
        # XXX: Deprecate this.
 
1896
        # ElementTree does its own conversion from UTF-8, so open in
 
1897
        # binary.
 
1898
        if self._inventory_is_modified:
 
1899
            raise errors.InventoryModified(self)
 
1900
        result = self._deserialize(self._transport.get('inventory'))
 
1901
        self._set_inventory(result, dirty=False)
 
1902
        return result
 
1903
 
 
1904
    @needs_tree_write_lock
 
1905
    def remove(self, files, verbose=False, to_file=None, keep_files=True,
 
1906
        force=False):
 
1907
        """Remove nominated files from the working inventory.
 
1908
 
 
1909
        :files: File paths relative to the basedir.
 
1910
        :keep_files: If true, the files will also be kept.
 
1911
        :force: Delete files and directories, even if they are changed and
 
1912
            even if the directories are not empty.
 
1913
        """
 
1914
        if isinstance(files, basestring):
 
1915
            files = [files]
 
1916
 
 
1917
        inv_delta = []
 
1918
 
 
1919
        new_files=set()
 
1920
        unknown_nested_files=set()
 
1921
 
 
1922
        def recurse_directory_to_add_files(directory):
 
1923
            # Recurse directory and add all files
 
1924
            # so we can check if they have changed.
 
1925
            for parent_info, file_infos in\
 
1926
                self.walkdirs(directory):
 
1927
                for relpath, basename, kind, lstat, fileid, kind in file_infos:
 
1928
                    # Is it versioned or ignored?
 
1929
                    if self.path2id(relpath) or self.is_ignored(relpath):
 
1930
                        # Add nested content for deletion.
 
1931
                        new_files.add(relpath)
 
1932
                    else:
 
1933
                        # Files which are not versioned and not ignored
 
1934
                        # should be treated as unknown.
 
1935
                        unknown_nested_files.add((relpath, None, kind))
 
1936
 
 
1937
        for filename in files:
 
1938
            # Get file name into canonical form.
 
1939
            abspath = self.abspath(filename)
 
1940
            filename = self.relpath(abspath)
 
1941
            if len(filename) > 0:
 
1942
                new_files.add(filename)
 
1943
                recurse_directory_to_add_files(filename)
 
1944
 
 
1945
        files = list(new_files)
 
1946
 
 
1947
        if len(files) == 0:
 
1948
            return # nothing to do
 
1949
 
 
1950
        # Sort needed to first handle directory content before the directory
 
1951
        files.sort(reverse=True)
 
1952
 
 
1953
        # Bail out if we are going to delete files we shouldn't
 
1954
        if not keep_files and not force:
 
1955
            has_changed_files = len(unknown_nested_files) > 0
 
1956
            if not has_changed_files:
 
1957
                for (file_id, path, content_change, versioned, parent_id, name,
 
1958
                     kind, executable) in self.iter_changes(self.basis_tree(),
 
1959
                         include_unchanged=True, require_versioned=False,
 
1960
                         want_unversioned=True, specific_files=files):
 
1961
                    if versioned == (False, False):
 
1962
                        # The record is unknown ...
 
1963
                        if not self.is_ignored(path[1]):
 
1964
                            # ... but not ignored
 
1965
                            has_changed_files = True
 
1966
                            break
 
1967
                    elif content_change and (kind[1] is not None):
 
1968
                        # Versioned and changed, but not deleted
 
1969
                        has_changed_files = True
 
1970
                        break
 
1971
 
 
1972
            if has_changed_files:
 
1973
                # Make delta show ALL applicable changes in error message.
 
1974
                tree_delta = self.changes_from(self.basis_tree(),
 
1975
                    require_versioned=False, want_unversioned=True,
 
1976
                    specific_files=files)
 
1977
                for unknown_file in unknown_nested_files:
 
1978
                    if unknown_file not in tree_delta.unversioned:
 
1979
                        tree_delta.unversioned.extend((unknown_file,))
 
1980
                raise errors.BzrRemoveChangedFilesError(tree_delta)
 
1981
 
 
1982
        # Build inv_delta and delete files where applicable,
 
1983
        # do this before any modifications to inventory.
 
1984
        for f in files:
 
1985
            fid = self.path2id(f)
 
1986
            message = None
 
1987
            if not fid:
 
1988
                message = "%s is not versioned." % (f,)
 
1989
            else:
 
1990
                if verbose:
 
1991
                    # having removed it, it must be either ignored or unknown
 
1992
                    if self.is_ignored(f):
 
1993
                        new_status = 'I'
 
1994
                    else:
 
1995
                        new_status = '?'
 
1996
                    textui.show_status(new_status, self.kind(fid), f,
 
1997
                                       to_file=to_file)
 
1998
                # Unversion file
 
1999
                inv_delta.append((f, None, fid, None))
 
2000
                message = "removed %s" % (f,)
 
2001
 
 
2002
            if not keep_files:
 
2003
                abs_path = self.abspath(f)
 
2004
                if osutils.lexists(abs_path):
 
2005
                    if (osutils.isdir(abs_path) and
 
2006
                        len(os.listdir(abs_path)) > 0):
 
2007
                        if force:
 
2008
                            osutils.rmtree(abs_path)
 
2009
                        else:
 
2010
                            message = "%s is not an empty directory "\
 
2011
                                "and won't be deleted." % (f,)
 
2012
                    else:
 
2013
                        osutils.delete_any(abs_path)
 
2014
                        message = "deleted %s" % (f,)
 
2015
                elif message is not None:
 
2016
                    # Only care if we haven't done anything yet.
 
2017
                    message = "%s does not exist." % (f,)
 
2018
 
 
2019
            # Print only one message (if any) per file.
 
2020
            if message is not None:
 
2021
                note(message)
 
2022
        self.apply_inventory_delta(inv_delta)
 
2023
 
 
2024
    @needs_tree_write_lock
 
2025
    def revert(self, filenames=None, old_tree=None, backups=True,
 
2026
               pb=DummyProgress(), report_changes=False):
 
2027
        from bzrlib.conflicts import resolve
 
2028
        if filenames == []:
 
2029
            filenames = None
 
2030
            symbol_versioning.warn('Using [] to revert all files is deprecated'
 
2031
                ' as of bzr 0.91.  Please use None (the default) instead.',
 
2032
                DeprecationWarning, stacklevel=2)
 
2033
        if old_tree is None:
 
2034
            basis_tree = self.basis_tree()
 
2035
            basis_tree.lock_read()
 
2036
            old_tree = basis_tree
 
2037
        else:
 
2038
            basis_tree = None
 
2039
        try:
 
2040
            conflicts = transform.revert(self, old_tree, filenames, backups, pb,
 
2041
                                         report_changes)
 
2042
            if filenames is None and len(self.get_parent_ids()) > 1:
 
2043
                parent_trees = []
 
2044
                last_revision = self.last_revision()
 
2045
                if last_revision != NULL_REVISION:
 
2046
                    if basis_tree is None:
 
2047
                        basis_tree = self.basis_tree()
 
2048
                        basis_tree.lock_read()
 
2049
                    parent_trees.append((last_revision, basis_tree))
 
2050
                self.set_parent_trees(parent_trees)
 
2051
                resolve(self)
 
2052
            else:
 
2053
                resolve(self, filenames, ignore_misses=True, recursive=True)
 
2054
        finally:
 
2055
            if basis_tree is not None:
 
2056
                basis_tree.unlock()
 
2057
        return conflicts
 
2058
 
 
2059
    def revision_tree(self, revision_id):
 
2060
        """See Tree.revision_tree.
 
2061
 
 
2062
        WorkingTree can supply revision_trees for the basis revision only
 
2063
        because there is only one cached inventory in the bzr directory.
 
2064
        """
 
2065
        if revision_id == self.last_revision():
 
2066
            try:
 
2067
                xml = self.read_basis_inventory()
 
2068
            except errors.NoSuchFile:
 
2069
                pass
 
2070
            else:
 
2071
                try:
 
2072
                    inv = xml7.serializer_v7.read_inventory_from_string(xml)
 
2073
                    # dont use the repository revision_tree api because we want
 
2074
                    # to supply the inventory.
 
2075
                    if inv.revision_id == revision_id:
 
2076
                        return revisiontree.RevisionTree(self.branch.repository,
 
2077
                            inv, revision_id)
 
2078
                except errors.BadInventoryFormat:
 
2079
                    pass
 
2080
        # raise if there was no inventory, or if we read the wrong inventory.
 
2081
        raise errors.NoSuchRevisionInTree(self, revision_id)
 
2082
 
 
2083
    # XXX: This method should be deprecated in favour of taking in a proper
 
2084
    # new Inventory object.
 
2085
    @needs_tree_write_lock
 
2086
    def set_inventory(self, new_inventory_list):
 
2087
        from bzrlib.inventory import (Inventory,
 
2088
                                      InventoryDirectory,
 
2089
                                      InventoryEntry,
 
2090
                                      InventoryFile,
 
2091
                                      InventoryLink)
 
2092
        inv = Inventory(self.get_root_id())
 
2093
        for path, file_id, parent, kind in new_inventory_list:
 
2094
            name = os.path.basename(path)
 
2095
            if name == "":
 
2096
                continue
 
2097
            # fixme, there should be a factory function inv,add_??
 
2098
            if kind == 'directory':
 
2099
                inv.add(InventoryDirectory(file_id, name, parent))
 
2100
            elif kind == 'file':
 
2101
                inv.add(InventoryFile(file_id, name, parent))
 
2102
            elif kind == 'symlink':
 
2103
                inv.add(InventoryLink(file_id, name, parent))
 
2104
            else:
 
2105
                raise errors.BzrError("unknown kind %r" % kind)
 
2106
        self._write_inventory(inv)
 
2107
 
 
2108
    @needs_tree_write_lock
 
2109
    def set_root_id(self, file_id):
 
2110
        """Set the root id for this tree."""
 
2111
        # for compatability
 
2112
        if file_id is None:
 
2113
            raise ValueError(
 
2114
                'WorkingTree.set_root_id with fileid=None')
 
2115
        file_id = osutils.safe_file_id(file_id)
 
2116
        self._set_root_id(file_id)
 
2117
 
 
2118
    def _set_root_id(self, file_id):
 
2119
        """Set the root id for this tree, in a format specific manner.
 
2120
 
 
2121
        :param file_id: The file id to assign to the root. It must not be
 
2122
            present in the current inventory or an error will occur. It must
 
2123
            not be None, but rather a valid file id.
 
2124
        """
 
2125
        inv = self._inventory
 
2126
        orig_root_id = inv.root.file_id
 
2127
        # TODO: it might be nice to exit early if there was nothing
 
2128
        # to do, saving us from trigger a sync on unlock.
 
2129
        self._inventory_is_modified = True
 
2130
        # we preserve the root inventory entry object, but
 
2131
        # unlinkit from the byid index
 
2132
        del inv._byid[inv.root.file_id]
 
2133
        inv.root.file_id = file_id
 
2134
        # and link it into the index with the new changed id.
 
2135
        inv._byid[inv.root.file_id] = inv.root
 
2136
        # and finally update all children to reference the new id.
 
2137
        # XXX: this should be safe to just look at the root.children
 
2138
        # list, not the WHOLE INVENTORY.
 
2139
        for fid in inv:
 
2140
            entry = inv[fid]
 
2141
            if entry.parent_id == orig_root_id:
 
2142
                entry.parent_id = inv.root.file_id
 
2143
 
 
2144
    def unlock(self):
 
2145
        """See Branch.unlock.
 
2146
 
 
2147
        WorkingTree locking just uses the Branch locking facilities.
 
2148
        This is current because all working trees have an embedded branch
 
2149
        within them. IF in the future, we were to make branch data shareable
 
2150
        between multiple working trees, i.e. via shared storage, then we
 
2151
        would probably want to lock both the local tree, and the branch.
 
2152
        """
 
2153
        raise NotImplementedError(self.unlock)
 
2154
 
 
2155
    def update(self, change_reporter=None, possible_transports=None):
 
2156
        """Update a working tree along its branch.
 
2157
 
 
2158
        This will update the branch if its bound too, which means we have
 
2159
        multiple trees involved:
 
2160
 
 
2161
        - The new basis tree of the master.
 
2162
        - The old basis tree of the branch.
 
2163
        - The old basis tree of the working tree.
 
2164
        - The current working tree state.
 
2165
 
 
2166
        Pathologically, all three may be different, and non-ancestors of each
 
2167
        other.  Conceptually we want to:
 
2168
 
 
2169
        - Preserve the wt.basis->wt.state changes
 
2170
        - Transform the wt.basis to the new master basis.
 
2171
        - Apply a merge of the old branch basis to get any 'local' changes from
 
2172
          it into the tree.
 
2173
        - Restore the wt.basis->wt.state changes.
 
2174
 
 
2175
        There isn't a single operation at the moment to do that, so we:
 
2176
        - Merge current state -> basis tree of the master w.r.t. the old tree
 
2177
          basis.
 
2178
        - Do a 'normal' merge of the old branch basis if it is relevant.
 
2179
        """
 
2180
        if self.branch.get_bound_location() is not None:
 
2181
            self.lock_write()
 
2182
            update_branch = True
 
2183
        else:
 
2184
            self.lock_tree_write()
 
2185
            update_branch = False
 
2186
        try:
 
2187
            if update_branch:
 
2188
                old_tip = self.branch.update(possible_transports)
 
2189
            else:
 
2190
                old_tip = None
 
2191
            return self._update_tree(old_tip, change_reporter)
 
2192
        finally:
 
2193
            self.unlock()
 
2194
 
 
2195
    @needs_tree_write_lock
 
2196
    def _update_tree(self, old_tip=None, change_reporter=None):
 
2197
        """Update a tree to the master branch.
 
2198
 
 
2199
        :param old_tip: if supplied, the previous tip revision the branch,
 
2200
            before it was changed to the master branch's tip.
 
2201
        """
 
2202
        # here if old_tip is not None, it is the old tip of the branch before
 
2203
        # it was updated from the master branch. This should become a pending
 
2204
        # merge in the working tree to preserve the user existing work.  we
 
2205
        # cant set that until we update the working trees last revision to be
 
2206
        # one from the new branch, because it will just get absorbed by the
 
2207
        # parent de-duplication logic.
 
2208
        #
 
2209
        # We MUST save it even if an error occurs, because otherwise the users
 
2210
        # local work is unreferenced and will appear to have been lost.
 
2211
        #
 
2212
        result = 0
 
2213
        try:
 
2214
            last_rev = self.get_parent_ids()[0]
 
2215
        except IndexError:
 
2216
            last_rev = _mod_revision.NULL_REVISION
 
2217
        if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
 
2218
            # merge tree state up to new branch tip.
 
2219
            basis = self.basis_tree()
 
2220
            basis.lock_read()
 
2221
            try:
 
2222
                to_tree = self.branch.basis_tree()
 
2223
                if basis.inventory.root is None:
 
2224
                    self.set_root_id(to_tree.get_root_id())
 
2225
                    self.flush()
 
2226
                result += merge.merge_inner(
 
2227
                                      self.branch,
 
2228
                                      to_tree,
 
2229
                                      basis,
 
2230
                                      this_tree=self,
 
2231
                                      change_reporter=change_reporter)
 
2232
            finally:
 
2233
                basis.unlock()
 
2234
            # TODO - dedup parents list with things merged by pull ?
 
2235
            # reuse the tree we've updated to to set the basis:
 
2236
            parent_trees = [(self.branch.last_revision(), to_tree)]
 
2237
            merges = self.get_parent_ids()[1:]
 
2238
            # Ideally we ask the tree for the trees here, that way the working
 
2239
            # tree can decide whether to give us the entire tree or give us a
 
2240
            # lazy initialised tree. dirstate for instance will have the trees
 
2241
            # in ram already, whereas a last-revision + basis-inventory tree
 
2242
            # will not, but also does not need them when setting parents.
 
2243
            for parent in merges:
 
2244
                parent_trees.append(
 
2245
                    (parent, self.branch.repository.revision_tree(parent)))
 
2246
            if (old_tip is not None and not _mod_revision.is_null(old_tip)):
 
2247
                parent_trees.append(
 
2248
                    (old_tip, self.branch.repository.revision_tree(old_tip)))
 
2249
            self.set_parent_trees(parent_trees)
 
2250
            last_rev = parent_trees[0][0]
 
2251
        else:
 
2252
            # the working tree had the same last-revision as the master
 
2253
            # branch did. We may still have pivot local work from the local
 
2254
            # branch into old_tip:
 
2255
            if (old_tip is not None and not _mod_revision.is_null(old_tip)):
 
2256
                self.add_parent_tree_id(old_tip)
 
2257
        if (old_tip is not None and not _mod_revision.is_null(old_tip)
 
2258
            and old_tip != last_rev):
 
2259
            # our last revision was not the prior branch last revision
 
2260
            # and we have converted that last revision to a pending merge.
 
2261
            # base is somewhere between the branch tip now
 
2262
            # and the now pending merge
 
2263
 
 
2264
            # Since we just modified the working tree and inventory, flush out
 
2265
            # the current state, before we modify it again.
 
2266
            # TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
 
2267
            #       requires it only because TreeTransform directly munges the
 
2268
            #       inventory and calls tree._write_inventory(). Ultimately we
 
2269
            #       should be able to remove this extra flush.
 
2270
            self.flush()
 
2271
            graph = self.branch.repository.get_graph()
 
2272
            base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
 
2273
                                                old_tip)
 
2274
            base_tree = self.branch.repository.revision_tree(base_rev_id)
 
2275
            other_tree = self.branch.repository.revision_tree(old_tip)
 
2276
            result += merge.merge_inner(
 
2277
                                  self.branch,
 
2278
                                  other_tree,
 
2279
                                  base_tree,
 
2280
                                  this_tree=self,
 
2281
                                  change_reporter=change_reporter)
 
2282
        return result
 
2283
 
 
2284
    def _write_hashcache_if_dirty(self):
 
2285
        """Write out the hashcache if it is dirty."""
 
2286
        if self._hashcache.needs_write:
 
2287
            try:
 
2288
                self._hashcache.write()
 
2289
            except OSError, e:
 
2290
                if e.errno not in (errno.EPERM, errno.EACCES):
 
2291
                    raise
 
2292
                # TODO: jam 20061219 Should this be a warning? A single line
 
2293
                #       warning might be sufficient to let the user know what
 
2294
                #       is going on.
 
2295
                mutter('Could not write hashcache for %s\nError: %s',
 
2296
                       self._hashcache.cache_file_name(), e)
 
2297
 
 
2298
    @needs_tree_write_lock
 
2299
    def _write_inventory(self, inv):
 
2300
        """Write inventory as the current inventory."""
 
2301
        self._set_inventory(inv, dirty=True)
 
2302
        self.flush()
 
2303
 
 
2304
    def set_conflicts(self, arg):
 
2305
        raise errors.UnsupportedOperation(self.set_conflicts, self)
 
2306
 
 
2307
    def add_conflicts(self, arg):
 
2308
        raise errors.UnsupportedOperation(self.add_conflicts, self)
 
2309
 
 
2310
    @needs_read_lock
 
2311
    def conflicts(self):
 
2312
        conflicts = _mod_conflicts.ConflictList()
 
2313
        for conflicted in self._iter_conflicts():
 
2314
            text = True
 
2315
            try:
 
2316
                if file_kind(self.abspath(conflicted)) != "file":
 
2317
                    text = False
 
2318
            except errors.NoSuchFile:
 
2319
                text = False
 
2320
            if text is True:
 
2321
                for suffix in ('.THIS', '.OTHER'):
 
2322
                    try:
 
2323
                        kind = file_kind(self.abspath(conflicted+suffix))
 
2324
                        if kind != "file":
 
2325
                            text = False
 
2326
                    except errors.NoSuchFile:
 
2327
                        text = False
 
2328
                    if text == False:
 
2329
                        break
 
2330
            ctype = {True: 'text conflict', False: 'contents conflict'}[text]
 
2331
            conflicts.append(_mod_conflicts.Conflict.factory(ctype,
 
2332
                             path=conflicted,
 
2333
                             file_id=self.path2id(conflicted)))
 
2334
        return conflicts
 
2335
 
 
2336
    def walkdirs(self, prefix=""):
 
2337
        """Walk the directories of this tree.
 
2338
 
 
2339
        returns a generator which yields items in the form:
 
2340
                ((curren_directory_path, fileid),
 
2341
                 [(file1_path, file1_name, file1_kind, (lstat), file1_id,
 
2342
                   file1_kind), ... ])
 
2343
 
 
2344
        This API returns a generator, which is only valid during the current
 
2345
        tree transaction - within a single lock_read or lock_write duration.
 
2346
 
 
2347
        If the tree is not locked, it may cause an error to be raised,
 
2348
        depending on the tree implementation.
 
2349
        """
 
2350
        disk_top = self.abspath(prefix)
 
2351
        if disk_top.endswith('/'):
 
2352
            disk_top = disk_top[:-1]
 
2353
        top_strip_len = len(disk_top) + 1
 
2354
        inventory_iterator = self._walkdirs(prefix)
 
2355
        disk_iterator = osutils.walkdirs(disk_top, prefix)
 
2356
        try:
 
2357
            current_disk = disk_iterator.next()
 
2358
            disk_finished = False
 
2359
        except OSError, e:
 
2360
            if not (e.errno == errno.ENOENT or
 
2361
                (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
 
2362
                raise
 
2363
            current_disk = None
 
2364
            disk_finished = True
 
2365
        try:
 
2366
            current_inv = inventory_iterator.next()
 
2367
            inv_finished = False
 
2368
        except StopIteration:
 
2369
            current_inv = None
 
2370
            inv_finished = True
 
2371
        while not inv_finished or not disk_finished:
 
2372
            if current_disk:
 
2373
                ((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
 
2374
                    cur_disk_dir_content) = current_disk
 
2375
            else:
 
2376
                ((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
 
2377
                    cur_disk_dir_content) = ((None, None), None)
 
2378
            if not disk_finished:
 
2379
                # strip out .bzr dirs
 
2380
                if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
 
2381
                    len(cur_disk_dir_content) > 0):
 
2382
                    # osutils.walkdirs can be made nicer -
 
2383
                    # yield the path-from-prefix rather than the pathjoined
 
2384
                    # value.
 
2385
                    bzrdir_loc = bisect_left(cur_disk_dir_content,
 
2386
                        ('.bzr', '.bzr'))
 
2387
                    if (bzrdir_loc < len(cur_disk_dir_content)
 
2388
                        and self.bzrdir.is_control_filename(
 
2389
                            cur_disk_dir_content[bzrdir_loc][0])):
 
2390
                        # we dont yield the contents of, or, .bzr itself.
 
2391
                        del cur_disk_dir_content[bzrdir_loc]
 
2392
            if inv_finished:
 
2393
                # everything is unknown
 
2394
                direction = 1
 
2395
            elif disk_finished:
 
2396
                # everything is missing
 
2397
                direction = -1
 
2398
            else:
 
2399
                direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
 
2400
            if direction > 0:
 
2401
                # disk is before inventory - unknown
 
2402
                dirblock = [(relpath, basename, kind, stat, None, None) for
 
2403
                    relpath, basename, kind, stat, top_path in
 
2404
                    cur_disk_dir_content]
 
2405
                yield (cur_disk_dir_relpath, None), dirblock
 
2406
                try:
 
2407
                    current_disk = disk_iterator.next()
 
2408
                except StopIteration:
 
2409
                    disk_finished = True
 
2410
            elif direction < 0:
 
2411
                # inventory is before disk - missing.
 
2412
                dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
 
2413
                    for relpath, basename, dkind, stat, fileid, kind in
 
2414
                    current_inv[1]]
 
2415
                yield (current_inv[0][0], current_inv[0][1]), dirblock
 
2416
                try:
 
2417
                    current_inv = inventory_iterator.next()
 
2418
                except StopIteration:
 
2419
                    inv_finished = True
 
2420
            else:
 
2421
                # versioned present directory
 
2422
                # merge the inventory and disk data together
 
2423
                dirblock = []
 
2424
                for relpath, subiterator in itertools.groupby(sorted(
 
2425
                    current_inv[1] + cur_disk_dir_content,
 
2426
                    key=operator.itemgetter(0)), operator.itemgetter(1)):
 
2427
                    path_elements = list(subiterator)
 
2428
                    if len(path_elements) == 2:
 
2429
                        inv_row, disk_row = path_elements
 
2430
                        # versioned, present file
 
2431
                        dirblock.append((inv_row[0],
 
2432
                            inv_row[1], disk_row[2],
 
2433
                            disk_row[3], inv_row[4],
 
2434
                            inv_row[5]))
 
2435
                    elif len(path_elements[0]) == 5:
 
2436
                        # unknown disk file
 
2437
                        dirblock.append((path_elements[0][0],
 
2438
                            path_elements[0][1], path_elements[0][2],
 
2439
                            path_elements[0][3], None, None))
 
2440
                    elif len(path_elements[0]) == 6:
 
2441
                        # versioned, absent file.
 
2442
                        dirblock.append((path_elements[0][0],
 
2443
                            path_elements[0][1], 'unknown', None,
 
2444
                            path_elements[0][4], path_elements[0][5]))
 
2445
                    else:
 
2446
                        raise NotImplementedError('unreachable code')
 
2447
                yield current_inv[0], dirblock
 
2448
                try:
 
2449
                    current_inv = inventory_iterator.next()
 
2450
                except StopIteration:
 
2451
                    inv_finished = True
 
2452
                try:
 
2453
                    current_disk = disk_iterator.next()
 
2454
                except StopIteration:
 
2455
                    disk_finished = True
 
2456
 
 
2457
    def _walkdirs(self, prefix=""):
 
2458
        """Walk the directories of this tree.
 
2459
 
 
2460
           :prefix: is used as the directrory to start with.
 
2461
           returns a generator which yields items in the form:
 
2462
                ((curren_directory_path, fileid),
 
2463
                 [(file1_path, file1_name, file1_kind, None, file1_id,
 
2464
                   file1_kind), ... ])
 
2465
        """
 
2466
        _directory = 'directory'
 
2467
        # get the root in the inventory
 
2468
        inv = self.inventory
 
2469
        top_id = inv.path2id(prefix)
 
2470
        if top_id is None:
 
2471
            pending = []
 
2472
        else:
 
2473
            pending = [(prefix, '', _directory, None, top_id, None)]
 
2474
        while pending:
 
2475
            dirblock = []
 
2476
            currentdir = pending.pop()
 
2477
            # 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
 
2478
            top_id = currentdir[4]
 
2479
            if currentdir[0]:
 
2480
                relroot = currentdir[0] + '/'
 
2481
            else:
 
2482
                relroot = ""
 
2483
            # FIXME: stash the node in pending
 
2484
            entry = inv[top_id]
 
2485
            if entry.kind == 'directory':
 
2486
                for name, child in entry.sorted_children():
 
2487
                    dirblock.append((relroot + name, name, child.kind, None,
 
2488
                        child.file_id, child.kind
 
2489
                        ))
 
2490
            yield (currentdir[0], entry.file_id), dirblock
 
2491
            # push the user specified dirs from dirblock
 
2492
            for dir in reversed(dirblock):
 
2493
                if dir[2] == _directory:
 
2494
                    pending.append(dir)
 
2495
 
 
2496
    @needs_tree_write_lock
 
2497
    def auto_resolve(self):
 
2498
        """Automatically resolve text conflicts according to contents.
 
2499
 
 
2500
        Only text conflicts are auto_resolvable. Files with no conflict markers
 
2501
        are considered 'resolved', because bzr always puts conflict markers
 
2502
        into files that have text conflicts.  The corresponding .THIS .BASE and
 
2503
        .OTHER files are deleted, as per 'resolve'.
 
2504
        :return: a tuple of ConflictLists: (un_resolved, resolved).
 
2505
        """
 
2506
        un_resolved = _mod_conflicts.ConflictList()
 
2507
        resolved = _mod_conflicts.ConflictList()
 
2508
        conflict_re = re.compile('^(<{7}|={7}|>{7})')
 
2509
        for conflict in self.conflicts():
 
2510
            if (conflict.typestring != 'text conflict' or
 
2511
                self.kind(conflict.file_id) != 'file'):
 
2512
                un_resolved.append(conflict)
 
2513
                continue
 
2514
            my_file = open(self.id2abspath(conflict.file_id), 'rb')
 
2515
            try:
 
2516
                for line in my_file:
 
2517
                    if conflict_re.search(line):
 
2518
                        un_resolved.append(conflict)
 
2519
                        break
278
2520
                else:
279
 
                    newpat = pat
280
 
                if fnmatch.fnmatchcase(filename, newpat):
281
 
                    return pat
 
2521
                    resolved.append(conflict)
 
2522
            finally:
 
2523
                my_file.close()
 
2524
        resolved.remove_files(self)
 
2525
        self.set_conflicts(un_resolved)
 
2526
        return un_resolved, resolved
 
2527
 
 
2528
    @needs_read_lock
 
2529
    def _check(self):
 
2530
        tree_basis = self.basis_tree()
 
2531
        tree_basis.lock_read()
 
2532
        try:
 
2533
            repo_basis = self.branch.repository.revision_tree(
 
2534
                self.last_revision())
 
2535
            if len(list(repo_basis.iter_changes(tree_basis))) > 0:
 
2536
                raise errors.BzrCheckError(
 
2537
                    "Mismatched basis inventory content.")
 
2538
            self._validate()
 
2539
        finally:
 
2540
            tree_basis.unlock()
 
2541
 
 
2542
    def _validate(self):
 
2543
        """Validate internal structures.
 
2544
 
 
2545
        This is meant mostly for the test suite. To give it a chance to detect
 
2546
        corruption after actions have occurred. The default implementation is a
 
2547
        just a no-op.
 
2548
 
 
2549
        :return: None. An exception should be raised if there is an error.
 
2550
        """
 
2551
        return
 
2552
 
 
2553
    @needs_read_lock
 
2554
    def _get_rules_searcher(self, default_searcher):
 
2555
        """See Tree._get_rules_searcher."""
 
2556
        if self._rules_searcher is None:
 
2557
            self._rules_searcher = super(WorkingTree,
 
2558
                self)._get_rules_searcher(default_searcher)
 
2559
        return self._rules_searcher
 
2560
 
 
2561
    def get_shelf_manager(self):
 
2562
        """Return the ShelfManager for this WorkingTree."""
 
2563
        from bzrlib.shelf import ShelfManager
 
2564
        return ShelfManager(self, self._transport)
 
2565
 
 
2566
 
 
2567
class WorkingTree2(WorkingTree):
 
2568
    """This is the Format 2 working tree.
 
2569
 
 
2570
    This was the first weave based working tree.
 
2571
     - uses os locks for locking.
 
2572
     - uses the branch last-revision.
 
2573
    """
 
2574
 
 
2575
    def __init__(self, *args, **kwargs):
 
2576
        super(WorkingTree2, self).__init__(*args, **kwargs)
 
2577
        # WorkingTree2 has more of a constraint that self._inventory must
 
2578
        # exist. Because this is an older format, we don't mind the overhead
 
2579
        # caused by the extra computation here.
 
2580
 
 
2581
        # Newer WorkingTree's should only have self._inventory set when they
 
2582
        # have a read lock.
 
2583
        if self._inventory is None:
 
2584
            self.read_working_inventory()
 
2585
 
 
2586
    def lock_tree_write(self):
 
2587
        """See WorkingTree.lock_tree_write().
 
2588
 
 
2589
        In Format2 WorkingTrees we have a single lock for the branch and tree
 
2590
        so lock_tree_write() degrades to lock_write().
 
2591
        """
 
2592
        self.branch.lock_write()
 
2593
        try:
 
2594
            return self._control_files.lock_write()
 
2595
        except:
 
2596
            self.branch.unlock()
 
2597
            raise
 
2598
 
 
2599
    def unlock(self):
 
2600
        # do non-implementation specific cleanup
 
2601
        self._cleanup()
 
2602
 
 
2603
        # we share control files:
 
2604
        if self._control_files._lock_count == 3:
 
2605
            # _inventory_is_modified is always False during a read lock.
 
2606
            if self._inventory_is_modified:
 
2607
                self.flush()
 
2608
            self._write_hashcache_if_dirty()
 
2609
 
 
2610
        # reverse order of locking.
 
2611
        try:
 
2612
            return self._control_files.unlock()
 
2613
        finally:
 
2614
            self.branch.unlock()
 
2615
 
 
2616
 
 
2617
class WorkingTree3(WorkingTree):
 
2618
    """This is the Format 3 working tree.
 
2619
 
 
2620
    This differs from the base WorkingTree by:
 
2621
     - having its own file lock
 
2622
     - having its own last-revision property.
 
2623
 
 
2624
    This is new in bzr 0.8
 
2625
    """
 
2626
 
 
2627
    @needs_read_lock
 
2628
    def _last_revision(self):
 
2629
        """See Mutable.last_revision."""
 
2630
        try:
 
2631
            return self._transport.get_bytes('last-revision')
 
2632
        except errors.NoSuchFile:
 
2633
            return _mod_revision.NULL_REVISION
 
2634
 
 
2635
    def _change_last_revision(self, revision_id):
 
2636
        """See WorkingTree._change_last_revision."""
 
2637
        if revision_id is None or revision_id == NULL_REVISION:
 
2638
            try:
 
2639
                self._transport.delete('last-revision')
 
2640
            except errors.NoSuchFile:
 
2641
                pass
 
2642
            return False
 
2643
        else:
 
2644
            self._transport.put_bytes('last-revision', revision_id,
 
2645
                mode=self.bzrdir._get_file_mode())
 
2646
            return True
 
2647
 
 
2648
    @needs_tree_write_lock
 
2649
    def set_conflicts(self, conflicts):
 
2650
        self._put_rio('conflicts', conflicts.to_stanzas(),
 
2651
                      CONFLICT_HEADER_1)
 
2652
 
 
2653
    @needs_tree_write_lock
 
2654
    def add_conflicts(self, new_conflicts):
 
2655
        conflict_set = set(self.conflicts())
 
2656
        conflict_set.update(set(list(new_conflicts)))
 
2657
        self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
 
2658
                                       key=_mod_conflicts.Conflict.sort_key)))
 
2659
 
 
2660
    @needs_read_lock
 
2661
    def conflicts(self):
 
2662
        try:
 
2663
            confile = self._transport.get('conflicts')
 
2664
        except errors.NoSuchFile:
 
2665
            return _mod_conflicts.ConflictList()
 
2666
        try:
 
2667
            try:
 
2668
                if confile.next() != CONFLICT_HEADER_1 + '\n':
 
2669
                    raise errors.ConflictFormatError()
 
2670
            except StopIteration:
 
2671
                raise errors.ConflictFormatError()
 
2672
            return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
 
2673
        finally:
 
2674
            confile.close()
 
2675
 
 
2676
    def unlock(self):
 
2677
        # do non-implementation specific cleanup
 
2678
        self._cleanup()
 
2679
        if self._control_files._lock_count == 1:
 
2680
            # _inventory_is_modified is always False during a read lock.
 
2681
            if self._inventory_is_modified:
 
2682
                self.flush()
 
2683
            self._write_hashcache_if_dirty()
 
2684
        # reverse order of locking.
 
2685
        try:
 
2686
            return self._control_files.unlock()
 
2687
        finally:
 
2688
            self.branch.unlock()
 
2689
 
 
2690
 
 
2691
def get_conflicted_stem(path):
 
2692
    for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
 
2693
        if path.endswith(suffix):
 
2694
            return path[:-len(suffix)]
 
2695
 
 
2696
 
 
2697
class WorkingTreeFormat(object):
 
2698
    """An encapsulation of the initialization and open routines for a format.
 
2699
 
 
2700
    Formats provide three things:
 
2701
     * An initialization routine,
 
2702
     * a format string,
 
2703
     * an open routine.
 
2704
 
 
2705
    Formats are placed in an dict by their format string for reference
 
2706
    during workingtree opening. Its not required that these be instances, they
 
2707
    can be classes themselves with class methods - it simply depends on
 
2708
    whether state is needed for a given format or not.
 
2709
 
 
2710
    Once a format is deprecated, just deprecate the initialize and open
 
2711
    methods on the format class. Do not deprecate the object, as the
 
2712
    object will be created every time regardless.
 
2713
    """
 
2714
 
 
2715
    _default_format = None
 
2716
    """The default format used for new trees."""
 
2717
 
 
2718
    _formats = {}
 
2719
    """The known formats."""
 
2720
 
 
2721
    requires_rich_root = False
 
2722
 
 
2723
    upgrade_recommended = False
 
2724
 
 
2725
    @classmethod
 
2726
    def find_format(klass, a_bzrdir):
 
2727
        """Return the format for the working tree object in a_bzrdir."""
 
2728
        try:
 
2729
            transport = a_bzrdir.get_workingtree_transport(None)
 
2730
            format_string = transport.get("format").read()
 
2731
            return klass._formats[format_string]
 
2732
        except errors.NoSuchFile:
 
2733
            raise errors.NoWorkingTree(base=transport.base)
 
2734
        except KeyError:
 
2735
            raise errors.UnknownFormatError(format=format_string,
 
2736
                                            kind="working tree")
 
2737
 
 
2738
    def __eq__(self, other):
 
2739
        return self.__class__ is other.__class__
 
2740
 
 
2741
    def __ne__(self, other):
 
2742
        return not (self == other)
 
2743
 
 
2744
    @classmethod
 
2745
    def get_default_format(klass):
 
2746
        """Return the current default format."""
 
2747
        return klass._default_format
 
2748
 
 
2749
    def get_format_string(self):
 
2750
        """Return the ASCII format string that identifies this format."""
 
2751
        raise NotImplementedError(self.get_format_string)
 
2752
 
 
2753
    def get_format_description(self):
 
2754
        """Return the short description for this format."""
 
2755
        raise NotImplementedError(self.get_format_description)
 
2756
 
 
2757
    def is_supported(self):
 
2758
        """Is this format supported?
 
2759
 
 
2760
        Supported formats can be initialized and opened.
 
2761
        Unsupported formats may not support initialization or committing or
 
2762
        some other features depending on the reason for not being supported.
 
2763
        """
 
2764
        return True
 
2765
 
 
2766
    def supports_content_filtering(self):
 
2767
        """True if this format supports content filtering."""
 
2768
        return False
 
2769
 
 
2770
    def supports_views(self):
 
2771
        """True if this format supports stored views."""
 
2772
        return False
 
2773
 
 
2774
    @classmethod
 
2775
    def register_format(klass, format):
 
2776
        klass._formats[format.get_format_string()] = format
 
2777
 
 
2778
    @classmethod
 
2779
    def set_default_format(klass, format):
 
2780
        klass._default_format = format
 
2781
 
 
2782
    @classmethod
 
2783
    def unregister_format(klass, format):
 
2784
        del klass._formats[format.get_format_string()]
 
2785
 
 
2786
 
 
2787
class WorkingTreeFormat2(WorkingTreeFormat):
 
2788
    """The second working tree format.
 
2789
 
 
2790
    This format modified the hash cache from the format 1 hash cache.
 
2791
    """
 
2792
 
 
2793
    upgrade_recommended = True
 
2794
 
 
2795
    def get_format_description(self):
 
2796
        """See WorkingTreeFormat.get_format_description()."""
 
2797
        return "Working tree format 2"
 
2798
 
 
2799
    def _stub_initialize_on_transport(self, transport, file_mode):
 
2800
        """Workaround: create control files for a remote working tree.
 
2801
 
 
2802
        This ensures that it can later be updated and dealt with locally,
 
2803
        since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
 
2804
        no working tree.  (See bug #43064).
 
2805
        """
 
2806
        sio = StringIO()
 
2807
        inv = Inventory()
 
2808
        xml5.serializer_v5.write_inventory(inv, sio, working=True)
 
2809
        sio.seek(0)
 
2810
        transport.put_file('inventory', sio, file_mode)
 
2811
        transport.put_bytes('pending-merges', '', file_mode)
 
2812
 
 
2813
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
2814
                   accelerator_tree=None, hardlink=False):
 
2815
        """See WorkingTreeFormat.initialize()."""
 
2816
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
2817
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
2818
        if from_branch is not None:
 
2819
            branch = from_branch
 
2820
        else:
 
2821
            branch = a_bzrdir.open_branch()
 
2822
        if revision_id is None:
 
2823
            revision_id = _mod_revision.ensure_null(branch.last_revision())
 
2824
        branch.lock_write()
 
2825
        try:
 
2826
            branch.generate_revision_history(revision_id)
 
2827
        finally:
 
2828
            branch.unlock()
 
2829
        inv = Inventory()
 
2830
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
 
2831
                         branch,
 
2832
                         inv,
 
2833
                         _internal=True,
 
2834
                         _format=self,
 
2835
                         _bzrdir=a_bzrdir)
 
2836
        basis_tree = branch.repository.revision_tree(revision_id)
 
2837
        if basis_tree.inventory.root is not None:
 
2838
            wt.set_root_id(basis_tree.get_root_id())
 
2839
        # set the parent list and cache the basis tree.
 
2840
        if _mod_revision.is_null(revision_id):
 
2841
            parent_trees = []
 
2842
        else:
 
2843
            parent_trees = [(revision_id, basis_tree)]
 
2844
        wt.set_parent_trees(parent_trees)
 
2845
        transform.build_tree(basis_tree, wt)
 
2846
        return wt
 
2847
 
 
2848
    def __init__(self):
 
2849
        super(WorkingTreeFormat2, self).__init__()
 
2850
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
 
2851
 
 
2852
    def open(self, a_bzrdir, _found=False):
 
2853
        """Return the WorkingTree object for a_bzrdir
 
2854
 
 
2855
        _found is a private parameter, do not use it. It is used to indicate
 
2856
               if format probing has already been done.
 
2857
        """
 
2858
        if not _found:
 
2859
            # we are being called directly and must probe.
 
2860
            raise NotImplementedError
 
2861
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
2862
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
2863
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
 
2864
                           _internal=True,
 
2865
                           _format=self,
 
2866
                           _bzrdir=a_bzrdir)
 
2867
        return wt
 
2868
 
 
2869
class WorkingTreeFormat3(WorkingTreeFormat):
 
2870
    """The second working tree format updated to record a format marker.
 
2871
 
 
2872
    This format:
 
2873
        - exists within a metadir controlling .bzr
 
2874
        - includes an explicit version marker for the workingtree control
 
2875
          files, separate from the BzrDir format
 
2876
        - modifies the hash cache format
 
2877
        - is new in bzr 0.8
 
2878
        - uses a LockDir to guard access for writes.
 
2879
    """
 
2880
 
 
2881
    upgrade_recommended = True
 
2882
 
 
2883
    def get_format_string(self):
 
2884
        """See WorkingTreeFormat.get_format_string()."""
 
2885
        return "Bazaar-NG Working Tree format 3"
 
2886
 
 
2887
    def get_format_description(self):
 
2888
        """See WorkingTreeFormat.get_format_description()."""
 
2889
        return "Working tree format 3"
 
2890
 
 
2891
    _lock_file_name = 'lock'
 
2892
    _lock_class = LockDir
 
2893
 
 
2894
    _tree_class = WorkingTree3
 
2895
 
 
2896
    def __get_matchingbzrdir(self):
 
2897
        return bzrdir.BzrDirMetaFormat1()
 
2898
 
 
2899
    _matchingbzrdir = property(__get_matchingbzrdir)
 
2900
 
 
2901
    def _open_control_files(self, a_bzrdir):
 
2902
        transport = a_bzrdir.get_workingtree_transport(None)
 
2903
        return LockableFiles(transport, self._lock_file_name,
 
2904
                             self._lock_class)
 
2905
 
 
2906
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
2907
                   accelerator_tree=None, hardlink=False):
 
2908
        """See WorkingTreeFormat.initialize().
 
2909
 
 
2910
        :param revision_id: if supplied, create a working tree at a different
 
2911
            revision than the branch is at.
 
2912
        :param accelerator_tree: A tree which can be used for retrieving file
 
2913
            contents more quickly than the revision tree, i.e. a workingtree.
 
2914
            The revision tree will be used for cases where accelerator_tree's
 
2915
            content is different.
 
2916
        :param hardlink: If true, hard-link files from accelerator_tree,
 
2917
            where possible.
 
2918
        """
 
2919
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
2920
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
2921
        transport = a_bzrdir.get_workingtree_transport(self)
 
2922
        control_files = self._open_control_files(a_bzrdir)
 
2923
        control_files.create_lock()
 
2924
        control_files.lock_write()
 
2925
        transport.put_bytes('format', self.get_format_string(),
 
2926
            mode=a_bzrdir._get_file_mode())
 
2927
        if from_branch is not None:
 
2928
            branch = from_branch
 
2929
        else:
 
2930
            branch = a_bzrdir.open_branch()
 
2931
        if revision_id is None:
 
2932
            revision_id = _mod_revision.ensure_null(branch.last_revision())
 
2933
        # WorkingTree3 can handle an inventory which has a unique root id.
 
2934
        # as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
 
2935
        # those trees. And because there isn't a format bump inbetween, we
 
2936
        # are maintaining compatibility with older clients.
 
2937
        # inv = Inventory(root_id=gen_root_id())
 
2938
        inv = self._initial_inventory()
 
2939
        wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
 
2940
                         branch,
 
2941
                         inv,
 
2942
                         _internal=True,
 
2943
                         _format=self,
 
2944
                         _bzrdir=a_bzrdir,
 
2945
                         _control_files=control_files)
 
2946
        wt.lock_tree_write()
 
2947
        try:
 
2948
            basis_tree = branch.repository.revision_tree(revision_id)
 
2949
            # only set an explicit root id if there is one to set.
 
2950
            if basis_tree.inventory.root is not None:
 
2951
                wt.set_root_id(basis_tree.get_root_id())
 
2952
            if revision_id == NULL_REVISION:
 
2953
                wt.set_parent_trees([])
282
2954
            else:
283
 
                if fnmatch.fnmatchcase(splitpath(filename)[-1], pat):
284
 
                    return pat
285
 
        else:
286
 
            return None
287
 
        
 
2955
                wt.set_parent_trees([(revision_id, basis_tree)])
 
2956
            transform.build_tree(basis_tree, wt)
 
2957
        finally:
 
2958
            # Unlock in this order so that the unlock-triggers-flush in
 
2959
            # WorkingTree is given a chance to fire.
 
2960
            control_files.unlock()
 
2961
            wt.unlock()
 
2962
        return wt
 
2963
 
 
2964
    def _initial_inventory(self):
 
2965
        return Inventory()
 
2966
 
 
2967
    def __init__(self):
 
2968
        super(WorkingTreeFormat3, self).__init__()
 
2969
 
 
2970
    def open(self, a_bzrdir, _found=False):
 
2971
        """Return the WorkingTree object for a_bzrdir
 
2972
 
 
2973
        _found is a private parameter, do not use it. It is used to indicate
 
2974
               if format probing has already been done.
 
2975
        """
 
2976
        if not _found:
 
2977
            # we are being called directly and must probe.
 
2978
            raise NotImplementedError
 
2979
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
2980
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
2981
        wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
 
2982
        return wt
 
2983
 
 
2984
    def _open(self, a_bzrdir, control_files):
 
2985
        """Open the tree itself.
 
2986
 
 
2987
        :param a_bzrdir: the dir for the tree.
 
2988
        :param control_files: the control files for the tree.
 
2989
        """
 
2990
        return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
 
2991
                                _internal=True,
 
2992
                                _format=self,
 
2993
                                _bzrdir=a_bzrdir,
 
2994
                                _control_files=control_files)
 
2995
 
 
2996
    def __str__(self):
 
2997
        return self.get_format_string()
 
2998
 
 
2999
 
 
3000
__default_format = WorkingTreeFormat4()
 
3001
WorkingTreeFormat.register_format(__default_format)
 
3002
WorkingTreeFormat.register_format(WorkingTreeFormat6())
 
3003
WorkingTreeFormat.register_format(WorkingTreeFormat5())
 
3004
WorkingTreeFormat.register_format(WorkingTreeFormat3())
 
3005
WorkingTreeFormat.set_default_format(__default_format)
 
3006
# formats which have no format string are not discoverable
 
3007
# and not independently creatable, so are not registered.
 
3008
_legacy_formats = [WorkingTreeFormat2(),
 
3009
                   ]