~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Vincent Ladeuil
  • Date: 2008-01-03 08:49:38 UTC
  • mfrom: (3111.1.31 175524)
  • mto: This revision was merged to the branch mainline in revision 3158.
  • Revision ID: v.ladeuil+lp@free.fr-20080103084938-7kvurk5uvde2ui54
Fix bug #175524, http test servers are 1.1 compliant

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
from bzrlib import (
26
26
    delta,
27
27
    osutils,
 
28
    revision as _mod_revision,
 
29
    conflicts as _mod_conflicts,
28
30
    symbol_versioning,
29
31
    )
30
32
from bzrlib.decorators import needs_read_lock
103
105
 
104
106
        Each conflict is an instance of bzrlib.conflicts.Conflict.
105
107
        """
106
 
        return []
 
108
        return _mod_conflicts.ConflictList()
107
109
 
108
110
    def extras(self):
109
111
        """For trees that can have unversioned files, return all such paths."""
120
122
    
121
123
    def has_filename(self, filename):
122
124
        """True if the tree has given filename."""
123
 
        raise NotImplementedError()
 
125
        raise NotImplementedError(self.has_filename)
124
126
 
125
127
    def has_id(self, file_id):
126
 
        file_id = osutils.safe_file_id(file_id)
127
128
        return self.inventory.has_id(file_id)
128
129
 
129
130
    __contains__ = has_id
130
131
 
131
132
    def has_or_had_id(self, file_id):
132
 
        file_id = osutils.safe_file_id(file_id)
133
133
        if file_id == self.inventory.root.file_id:
134
134
            return True
135
135
        return self.inventory.has_id(file_id)
150
150
 
151
151
        :raises NoSuchId:
152
152
        """
153
 
        file_id = osutils.safe_file_id(file_id)
154
153
        return self.inventory.id2path(file_id)
155
154
 
156
155
    def is_control_filename(self, filename):
186
185
        raise NotImplementedError("Tree subclass %s must implement kind"
187
186
            % self.__class__.__name__)
188
187
 
 
188
    def path_content_summary(self, path):
 
189
        """Get a summary of the information about path.
 
190
        
 
191
        :param path: A relative path within the tree.
 
192
        :return: A tuple containing kind, size, exec, sha1-or-link.
 
193
            Kind is always present (see tree.kind()).
 
194
            size is present if kind is file, None otherwise.
 
195
            exec is None unless kind is file and the platform supports the 'x'
 
196
                bit.
 
197
            sha1-or-link is the link target if kind is symlink, or the sha1 if
 
198
                it can be obtained without reading the file.
 
199
        """
 
200
        raise NotImplementedError(self.path_content_summary)
 
201
 
189
202
    def get_reference_revision(self, file_id, path=None):
190
203
        raise NotImplementedError("Tree subclass %s must implement "
191
204
                                  "get_reference_revision"
208
221
    def _get_inventory(self):
209
222
        return self._inventory
210
223
    
211
 
    def get_file(self, file_id):
212
 
        """Return a file object for the file file_id in the tree."""
 
224
    def get_file(self, file_id, path=None):
 
225
        """Return a file object for the file file_id in the tree.
 
226
        
 
227
        If both file_id and path are defined, it is implementation defined as
 
228
        to which one is used.
 
229
        """
213
230
        raise NotImplementedError(self.get_file)
214
231
 
215
232
    def get_file_mtime(self, file_id, path=None):
222
239
        raise NotImplementedError(self.get_file_mtime)
223
240
 
224
241
    def get_file_by_path(self, path):
225
 
        return self.get_file(self._inventory.path2id(path))
 
242
        return self.get_file(self._inventory.path2id(path), path)
 
243
 
 
244
    def iter_files_bytes(self, desired_files):
 
245
        """Iterate through file contents.
 
246
 
 
247
        Files will not necessarily be returned in the order they occur in
 
248
        desired_files.  No specific order is guaranteed.
 
249
 
 
250
        Yields pairs of identifier, bytes_iterator.  identifier is an opaque
 
251
        value supplied by the caller as part of desired_files.  It should
 
252
        uniquely identify the file version in the caller's context.  (Examples:
 
253
        an index number or a TreeTransform trans_id.)
 
254
 
 
255
        bytes_iterator is an iterable of bytestrings for the file.  The
 
256
        kind of iterable and length of the bytestrings are unspecified, but for
 
257
        this implementation, it is a tuple containing a single bytestring with
 
258
        the complete text of the file.
 
259
 
 
260
        :param desired_files: a list of (file_id, identifier) pairs
 
261
        """
 
262
        for file_id, identifier in desired_files:
 
263
            # We wrap the string in a tuple so that we can return an iterable
 
264
            # of bytestrings.  (Technically, a bytestring is also an iterable
 
265
            # of bytestrings, but iterating through each character is not
 
266
            # performant.)
 
267
            cur_file = (self.get_file_text(file_id),)
 
268
            yield identifier, cur_file
226
269
 
227
270
    def get_symlink_target(self, file_id):
228
271
        """Get the target for a given file_id.
234
277
        """
235
278
        raise NotImplementedError(self.get_symlink_target)
236
279
 
 
280
    def get_root_id(self):
 
281
        """Return the file_id for the root of this tree."""
 
282
        raise NotImplementedError(self.get_root_id)
 
283
 
237
284
    def annotate_iter(self, file_id):
238
 
        """Return an iterator of revision_id, line tuples
 
285
        """Return an iterator of revision_id, line tuples.
239
286
 
240
287
        For working trees (and mutable trees in general), the special
241
288
        revision_id 'current:' will be used for lines that are new in this
244
291
        """
245
292
        raise NotImplementedError(self.annotate_iter)
246
293
 
 
294
    def _get_plan_merge_data(self, file_id, other, base):
 
295
        from bzrlib import merge, versionedfile
 
296
        vf = versionedfile._PlanMergeVersionedFile(file_id)
 
297
        last_revision_a = self._get_file_revision(file_id, vf, 'this:')
 
298
        last_revision_b = other._get_file_revision(file_id, vf, 'other:')
 
299
        if base is None:
 
300
            last_revision_base = None
 
301
        else:
 
302
            last_revision_base = base._get_file_revision(file_id, vf, 'base:')
 
303
        return vf, last_revision_a, last_revision_b, last_revision_base
 
304
 
 
305
    def plan_file_merge(self, file_id, other, base=None):
 
306
        """Generate a merge plan based on annotations.
 
307
 
 
308
        If the file contains uncommitted changes in this tree, they will be
 
309
        attributed to the 'current:' pseudo-revision.  If the file contains
 
310
        uncommitted changes in the other tree, they will be assigned to the
 
311
        'other:' pseudo-revision.
 
312
        """
 
313
        data = self._get_plan_merge_data(file_id, other, base)
 
314
        vf, last_revision_a, last_revision_b, last_revision_base = data
 
315
        return vf.plan_merge(last_revision_a, last_revision_b,
 
316
                             last_revision_base)
 
317
 
 
318
    def plan_file_lca_merge(self, file_id, other, base=None):
 
319
        """Generate a merge plan based lca-newness.
 
320
 
 
321
        If the file contains uncommitted changes in this tree, they will be
 
322
        attributed to the 'current:' pseudo-revision.  If the file contains
 
323
        uncommitted changes in the other tree, they will be assigned to the
 
324
        'other:' pseudo-revision.
 
325
        """
 
326
        data = self._get_plan_merge_data(file_id, other, base)
 
327
        vf, last_revision_a, last_revision_b, last_revision_base = data
 
328
        return vf.plan_lca_merge(last_revision_a, last_revision_b,
 
329
                                 last_revision_base)
 
330
 
 
331
    def _get_file_revision(self, file_id, vf, tree_revision):
 
332
        def file_revision(revision_tree):
 
333
            revision_tree.lock_read()
 
334
            try:
 
335
                return revision_tree.inventory[file_id].revision
 
336
            finally:
 
337
                revision_tree.unlock()
 
338
 
 
339
        def iter_parent_trees():
 
340
            for revision_id in self.get_parent_ids():
 
341
                try:
 
342
                    yield self.revision_tree(revision_id)
 
343
                except:
 
344
                    yield self.repository.revision_tree(revision_id)
 
345
 
 
346
        if getattr(self, '_get_weave', None) is None:
 
347
            last_revision = tree_revision
 
348
            parent_revisions = [file_revision(t) for t in iter_parent_trees()]
 
349
            vf.add_lines(last_revision, parent_revisions,
 
350
                         self.get_file(file_id).readlines())
 
351
            repo = self.branch.repository
 
352
            transaction = repo.get_transaction()
 
353
            base_vf = repo.weave_store.get_weave(file_id, transaction)
 
354
        else:
 
355
            last_revision = file_revision(self)
 
356
            base_vf = self._get_weave(file_id)
 
357
        vf.fallback_versionedfiles.append(base_vf)
 
358
        return last_revision
 
359
 
247
360
    inventory = property(_get_inventory,
248
361
                         doc="Inventory of this Tree")
249
362
 
274
387
    def paths2ids(self, paths, trees=[], require_versioned=True):
275
388
        """Return all the ids that can be reached by walking from paths.
276
389
        
277
 
        Each path is looked up in each this tree and any extras provided in
 
390
        Each path is looked up in this tree and any extras provided in
278
391
        trees, and this is repeated recursively: the children in an extra tree
279
392
        of a directory that has been renamed under a provided path in this tree
280
 
        are all returned, even if none exist until a provided path in this
 
393
        are all returned, even if none exist under a provided path in this
281
394
        tree, and vice versa.
282
395
 
283
396
        :param paths: An iterable of paths to start converting to ids from.
292
405
 
293
406
    def print_file(self, file_id):
294
407
        """Print file with id `file_id` to stdout."""
295
 
        file_id = osutils.safe_file_id(file_id)
296
408
        import sys
297
409
        sys.stdout.write(self.get_file_text(file_id))
298
410
 
356
468
           versioned_kind.
357
469
         - lstat is the stat data *if* the file was statted.
358
470
         - path_from_tree_root is the path from the root of the tree.
359
 
         - file_id is the file_id is the entry is versioned.
 
471
         - file_id is the file_id if the entry is versioned.
360
472
         - versioned_kind is the kind of the file as last recorded in the 
361
473
           versioning system. If 'unknown' the file is not versioned.
362
474
        One of 'kind' and 'versioned_kind' must not be 'unknown'.
387
499
        return False
388
500
 
389
501
    def kind(self, file_id):
390
 
        file_id = osutils.safe_file_id(file_id)
391
502
        assert self._inventory[file_id].kind == "directory"
392
503
        return "directory"
393
504
 
395
506
        return iter([])
396
507
    
397
508
    def __contains__(self, file_id):
398
 
        file_id = osutils.safe_file_id(file_id)
399
509
        return (file_id in self._inventory)
400
510
 
401
511
    def get_file_sha1(self, file_id, path=None, stat_value=None):
496
606
    :param trees: The trees to find file_ids within
497
607
    :param require_versioned: if true, all specified filenames must occur in
498
608
        at least one tree.
499
 
    :return: a set of (path, file ids) for the specified filenames
 
609
    :return: a set of file ids for the specified filenames
500
610
    """
501
611
    not_versioned = []
502
612
    interesting_ids = set()
515
625
 
516
626
 
517
627
def _find_children_across_trees(specified_ids, trees):
518
 
    """Return a set including specified ids and their children
 
628
    """Return a set including specified ids and their children.
519
629
    
520
630
    All matches in all trees will be used.
521
631
 
547
657
    Its instances have methods like 'compare' and contain references to the
548
658
    source and target trees these operations are to be carried out on.
549
659
 
550
 
    clients of bzrlib should not need to use InterTree directly, rather they
 
660
    Clients of bzrlib should not need to use InterTree directly, rather they
551
661
    should use the convenience methods on Tree such as 'Tree.compare()' which
552
662
    will pass through to InterTree as appropriate.
553
663
    """
593
703
            return result
594
704
        return delta._compare_trees(self.source, self.target, want_unchanged,
595
705
            specific_files, include_root, extra_trees=extra_trees,
 
706
            require_versioned=require_versioned,
596
707
            want_unversioned=want_unversioned)
597
708
 
598
709
    def _iter_changes(self, include_unchanged=False,
629
740
        lookup_trees = [self.source]
630
741
        if extra_trees:
631
742
             lookup_trees.extend(extra_trees)
632
 
        specific_file_ids = self.target.paths2ids(specific_files,
633
 
            lookup_trees, require_versioned=require_versioned)
 
743
        if specific_files == []:
 
744
            specific_file_ids = []
 
745
        else:
 
746
            specific_file_ids = self.target.paths2ids(specific_files,
 
747
                lookup_trees, require_versioned=require_versioned)
634
748
        if want_unversioned:
635
 
            all_unversioned = sorted([(p.split('/'), p) for p in self.target.extras()
636
 
                if not specific_files or
 
749
            all_unversioned = sorted([(p.split('/'), p) for p in
 
750
                                     self.target.extras()
 
751
                if specific_files is None or
637
752
                    osutils.is_inside_any(specific_files, p)])
638
753
            all_unversioned = deque(all_unversioned)
639
754
        else: