/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Robert Collins
  • Date: 2007-10-15 05:23:29 UTC
  • mfrom: (2906 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2907.
  • Revision ID: robertc@robertcollins.net-20071015052329-z5458xq9q2kq72mv
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
from bzrlib.store.versioned import VersionedFileStore
47
47
from bzrlib.store.text import TextStore
48
48
from bzrlib.testament import Testament
 
49
from bzrlib.util import bencode
49
50
""")
50
51
 
51
52
from bzrlib.decorators import needs_read_lock, needs_write_lock
620
621
        self.weave_store = text_store
621
622
        # for tests
622
623
        self._reconcile_does_inventory_gc = True
 
624
        self._reconcile_fixes_text_parents = False
623
625
        # not right yet - should be more semantically clear ? 
624
626
        # 
625
627
        self.control_store = control_store
759
761
            result['size'] = t
760
762
        return result
761
763
 
 
764
    def get_data_stream(self, revision_ids):
 
765
        raise NotImplementedError(self.get_data_stream)
 
766
 
 
767
    def insert_data_stream(self, stream):
 
768
        for item_key, bytes in stream:
 
769
            if item_key[0] == 'file':
 
770
                (file_id,) = item_key[1:]
 
771
                knit = self.weave_store.get_weave_or_empty(
 
772
                    file_id, self.get_transaction())
 
773
            elif item_key == ('inventory',):
 
774
                knit = self.get_inventory_weave()
 
775
            elif item_key == ('revisions',):
 
776
                knit = self._revision_store.get_revision_file(
 
777
                    self.get_transaction())
 
778
            elif item_key == ('signatures',):
 
779
                knit = self._revision_store.get_signature_file(
 
780
                    self.get_transaction())
 
781
            else:
 
782
                raise RepositoryDataStreamError(
 
783
                    "Unrecognised data stream key '%s'" % (item_key,))
 
784
            decoded_list = bencode.bdecode(bytes)
 
785
            format = decoded_list.pop(0)
 
786
            data_list = []
 
787
            knit_bytes = ''
 
788
            for version, options, parents, some_bytes in decoded_list:
 
789
                data_list.append((version, options, len(some_bytes), parents))
 
790
                knit_bytes += some_bytes
 
791
            knit.insert_data_stream(
 
792
                (format, data_list, StringIO(knit_bytes).read))
 
793
 
762
794
    @needs_read_lock
763
795
    def missing_revision_ids(self, other, revision_id=None):
764
796
        """Return the revision ids that other has that this does not.
1134
1166
        # maybe this generator should explicitly have the contract that it
1135
1167
        # should not be iterated until the previously yielded item has been
1136
1168
        # processed?
 
1169
        self.lock_read()
1137
1170
        inv_w = self.get_inventory_weave()
1138
1171
        inv_w.enable_cache()
1139
1172
 
1164
1197
                pass
1165
1198
            else:
1166
1199
                revisions_with_signatures.add(rev_id)
 
1200
        self.unlock()
1167
1201
        yield ("signatures", None, revisions_with_signatures)
1168
1202
 
1169
1203
        # revisions
1442
1476
                [parents_provider, other_repository._make_parents_provider()])
1443
1477
        return graph.Graph(parents_provider)
1444
1478
 
 
1479
    def get_versioned_file_checker(self, revisions, revision_versions_cache):
 
1480
        return VersionedFileChecker(revisions, revision_versions_cache, self)
 
1481
 
1445
1482
    @needs_write_lock
1446
1483
    def set_make_working_trees(self, new_value):
1447
1484
        """Set the policy flag for making working trees when creating branches.
1476
1513
                                                       self.get_transaction())
1477
1514
 
1478
1515
    @needs_read_lock
1479
 
    def check(self, revision_ids):
 
1516
    def check(self, revision_ids=None):
1480
1517
        """Check consistency of all history of given revision_ids.
1481
1518
 
1482
1519
        Different repository implementations should override _check().
1484
1521
        :param revision_ids: A non-empty list of revision_ids whose ancestry
1485
1522
             will be checked.  Typically the last revision_id of a branch.
1486
1523
        """
1487
 
        if not revision_ids:
1488
 
            raise ValueError("revision_ids must be non-empty in %s.check" 
1489
 
                    % (self,))
1490
1524
        return self._check(revision_ids)
1491
1525
 
1492
1526
    def _check(self, revision_ids):
1520
1554
                    revision_id.decode('ascii')
1521
1555
                except UnicodeDecodeError:
1522
1556
                    raise errors.NonAsciiRevisionId(method, self)
1523
 
 
1524
 
 
1525
 
 
 
1557
    
 
1558
    def revision_graph_can_have_wrong_parents(self):
 
1559
        """Is it possible for this repository to have a revision graph with
 
1560
        incorrect parents?
 
1561
 
 
1562
        If True, then this repository must also implement
 
1563
        _find_inconsistent_revision_parents so that check and reconcile can
 
1564
        check for inconsistencies before proceeding with other checks that may
 
1565
        depend on the revision index being consistent.
 
1566
        """
 
1567
        raise NotImplementedError(self.revision_graph_can_have_wrong_parents)
 
1568
        
1526
1569
# remove these delegates a while after bzr 0.15
1527
1570
def __make_delegated(name, from_module):
1528
1571
    def _deprecated_repository_forwarder():
2284
2327
        return f.count_copied, f.failed_revisions
2285
2328
 
2286
2329
 
2287
 
class InterRemoteRepository(InterRepository):
2288
 
    """Code for converting between RemoteRepository objects.
2289
 
 
2290
 
    This just gets an non-remote repository from the RemoteRepository, and calls
2291
 
    InterRepository.get again.
2292
 
    """
2293
 
 
2294
 
    def __init__(self, source, target):
2295
 
        if isinstance(source, remote.RemoteRepository):
2296
 
            source._ensure_real()
2297
 
            real_source = source._real_repository
2298
 
        else:
2299
 
            real_source = source
2300
 
        if isinstance(target, remote.RemoteRepository):
2301
 
            target._ensure_real()
2302
 
            real_target = target._real_repository
2303
 
        else:
2304
 
            real_target = target
2305
 
        self.real_inter = InterRepository.get(real_source, real_target)
2306
 
 
2307
 
    @staticmethod
2308
 
    def is_compatible(source, target):
2309
 
        if isinstance(source, remote.RemoteRepository):
2310
 
            return True
 
2330
class InterRemoteToOther(InterRepository):
 
2331
 
 
2332
    def __init__(self, source, target):
 
2333
        InterRepository.__init__(self, source, target)
 
2334
        self._real_inter = None
 
2335
 
 
2336
    @staticmethod
 
2337
    def is_compatible(source, target):
 
2338
        if not isinstance(source, remote.RemoteRepository):
 
2339
            return False
 
2340
        source._ensure_real()
 
2341
        real_source = source._real_repository
 
2342
        # Is source's model compatible with target's model, and are they the
 
2343
        # same format?  Currently we can only optimise fetching from an
 
2344
        # identical model & format repo.
 
2345
        assert not isinstance(real_source, remote.RemoteRepository), (
 
2346
            "We don't support remote repos backed by remote repos yet.")
 
2347
        return real_source._format == target._format
 
2348
 
 
2349
    @needs_write_lock
 
2350
    def fetch(self, revision_id=None, pb=None):
 
2351
        """See InterRepository.fetch()."""
 
2352
        from bzrlib.fetch import RemoteToOtherFetcher
 
2353
        mutter("Using fetch logic to copy between %s(remote) and %s(%s)",
 
2354
               self.source, self.target, self.target._format)
 
2355
        # TODO: jam 20070210 This should be an assert, not a translate
 
2356
        revision_id = osutils.safe_revision_id(revision_id)
 
2357
        f = RemoteToOtherFetcher(to_repository=self.target,
 
2358
                                 from_repository=self.source,
 
2359
                                 last_revision=revision_id,
 
2360
                                 pb=pb)
 
2361
        return f.count_copied, f.failed_revisions
 
2362
 
 
2363
    @classmethod
 
2364
    def _get_repo_format_to_test(self):
 
2365
        return None
 
2366
 
 
2367
 
 
2368
class InterOtherToRemote(InterRepository):
 
2369
 
 
2370
    def __init__(self, source, target):
 
2371
        InterRepository.__init__(self, source, target)
 
2372
        self._real_inter = None
 
2373
 
 
2374
    @staticmethod
 
2375
    def is_compatible(source, target):
2311
2376
        if isinstance(target, remote.RemoteRepository):
2312
2377
            return True
2313
2378
        return False
2314
2379
 
 
2380
    def _ensure_real_inter(self):
 
2381
        if self._real_inter is None:
 
2382
            self.target._ensure_real()
 
2383
            real_target = self.target._real_repository
 
2384
            self._real_inter = InterRepository.get(self.source, real_target)
 
2385
    
2315
2386
    def copy_content(self, revision_id=None):
2316
 
        self.real_inter.copy_content(revision_id=revision_id)
 
2387
        self._ensure_real_inter()
 
2388
        self._real_inter.copy_content(revision_id=revision_id)
2317
2389
 
2318
2390
    def fetch(self, revision_id=None, pb=None):
2319
 
        self.real_inter.fetch(revision_id=revision_id, pb=pb)
 
2391
        self._ensure_real_inter()
 
2392
        self._real_inter.fetch(revision_id=revision_id, pb=pb)
2320
2393
 
2321
2394
    @classmethod
2322
2395
    def _get_repo_format_to_test(self):
2328
2401
InterRepository.register_optimiser(InterKnitRepo)
2329
2402
InterRepository.register_optimiser(InterModel1and2)
2330
2403
InterRepository.register_optimiser(InterKnit1and2)
2331
 
InterRepository.register_optimiser(InterRemoteRepository)
 
2404
InterRepository.register_optimiser(InterRemoteToOther)
 
2405
InterRepository.register_optimiser(InterOtherToRemote)
2332
2406
 
2333
2407
 
2334
2408
class CopyConverter(object):
2411
2485
    if _unescape_re is None:
2412
2486
        _unescape_re = re.compile('\&([^;]*);')
2413
2487
    return _unescape_re.sub(_unescaper, data)
 
2488
 
 
2489
 
 
2490
class _RevisionTextVersionCache(object):
 
2491
    """A cache of the versionedfile versions for revision and file-id."""
 
2492
 
 
2493
    def __init__(self, repository):
 
2494
        self.repository = repository
 
2495
        self.revision_versions = {}
 
2496
 
 
2497
    def add_revision_text_versions(self, tree):
 
2498
        """Cache text version data from the supplied revision tree"""
 
2499
        inv_revisions = {}
 
2500
        for path, entry in tree.iter_entries_by_dir():
 
2501
            inv_revisions[entry.file_id] = entry.revision
 
2502
        self.revision_versions[tree.get_revision_id()] = inv_revisions
 
2503
        return inv_revisions
 
2504
 
 
2505
    def get_text_version(self, file_id, revision_id):
 
2506
        """Determine the text version for a given file-id and revision-id"""
 
2507
        try:
 
2508
            inv_revisions = self.revision_versions[revision_id]
 
2509
        except KeyError:
 
2510
            tree = self.repository.revision_tree(revision_id)
 
2511
            inv_revisions = self.add_revision_text_versions(tree)
 
2512
        return inv_revisions.get(file_id)
 
2513
 
 
2514
 
 
2515
class VersionedFileChecker(object):
 
2516
 
 
2517
    def __init__(self, planned_revisions, revision_versions, repository):
 
2518
        self.planned_revisions = planned_revisions
 
2519
        self.revision_versions = revision_versions
 
2520
        self.repository = repository
 
2521
    
 
2522
    def calculate_file_version_parents(self, revision_id, file_id):
 
2523
        text_revision = self.revision_versions.get_text_version(
 
2524
            file_id, revision_id)
 
2525
        if text_revision is None:
 
2526
            return None
 
2527
        parents_of_text_revision = self.repository.get_parents(
 
2528
            [text_revision])[0]
 
2529
        parents_from_inventories = []
 
2530
        for parent in parents_of_text_revision:
 
2531
            if parent == _mod_revision.NULL_REVISION:
 
2532
                continue
 
2533
            try:
 
2534
                inventory = self.repository.get_inventory(parent)
 
2535
            except errors.RevisionNotPresent:
 
2536
                pass
 
2537
            else:
 
2538
                try:
 
2539
                    introduced_in = inventory[file_id].revision
 
2540
                except errors.NoSuchId:
 
2541
                    pass
 
2542
                else:
 
2543
                    parents_from_inventories.append(introduced_in)
 
2544
        graph = self.repository.get_graph()
 
2545
        heads = set(graph.heads(parents_from_inventories))
 
2546
        new_parents = []
 
2547
        for parent in parents_from_inventories:
 
2548
            if parent in heads and parent not in new_parents:
 
2549
                new_parents.append(parent)
 
2550
        return new_parents
 
2551
 
 
2552
    def check_file_version_parents(self, weave, file_id):
 
2553
        result = {}
 
2554
        for num, revision_id in enumerate(self.planned_revisions):
 
2555
            correct_parents = self.calculate_file_version_parents(
 
2556
                revision_id, file_id)
 
2557
            if correct_parents is None:
 
2558
                continue
 
2559
            text_revision = self.revision_versions.get_text_version(
 
2560
                file_id, revision_id)
 
2561
            knit_parents = weave.get_parents(text_revision)
 
2562
            if correct_parents != knit_parents:
 
2563
                result[revision_id] = (knit_parents, correct_parents)
 
2564
        return result