/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: Aaron Bentley
  • Date: 2006-11-17 04:06:03 UTC
  • mfrom: (2139 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2162.
  • Revision ID: aaron.bentley@utoronto.ca-20061117040603-pgebxndswvwk26tt
Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
 
17
from cStringIO import StringIO
 
18
 
 
19
from bzrlib.lazy_import import lazy_import
 
20
lazy_import(globals(), """
17
21
from binascii import hexlify
18
22
from copy import deepcopy
19
 
from cStringIO import StringIO
20
23
import re
21
24
import time
22
 
from unittest import TestSuite
 
25
import unittest
23
26
 
24
27
from bzrlib import (
25
 
    bzrdir, 
26
 
    check, 
27
 
    delta, 
28
 
    gpg, 
29
 
    errors, 
 
28
    bzrdir,
 
29
    check,
 
30
    delta,
 
31
    errors,
 
32
    generate_ids,
 
33
    gpg,
 
34
    graph,
 
35
    knit,
 
36
    lockable_files,
 
37
    lockdir,
30
38
    osutils,
 
39
    revision as _mod_revision,
 
40
    symbol_versioning,
31
41
    transactions,
32
 
    ui, 
33
 
    xml5, 
 
42
    ui,
 
43
    weave,
 
44
    weavefile,
 
45
    xml5,
34
46
    xml6,
35
47
    )
 
48
from bzrlib.osutils import (
 
49
    rand_bytes,
 
50
    compact_date, 
 
51
    local_time_offset,
 
52
    )
 
53
from bzrlib.revisiontree import RevisionTree
 
54
from bzrlib.store.versioned import VersionedFileStore
 
55
from bzrlib.store.text import TextStore
 
56
from bzrlib.testament import Testament
 
57
""")
 
58
 
36
59
from bzrlib.decorators import needs_read_lock, needs_write_lock
37
 
from bzrlib.errors import InvalidRevisionId
38
 
from bzrlib.graph import Graph
39
60
from bzrlib.inter import InterObject
40
61
from bzrlib.inventory import Inventory, InventoryDirectory, ROOT_ID
41
 
from bzrlib.knit import KnitVersionedFile, KnitPlainFactory
42
 
from bzrlib.lockable_files import LockableFiles, TransportLock
43
 
from bzrlib.lockdir import LockDir
44
 
from bzrlib.osutils import (safe_unicode, rand_bytes, compact_date, 
45
 
                            local_time_offset)
46
 
from bzrlib.revision import NULL_REVISION, Revision
47
 
from bzrlib.revisiontree import RevisionTree
48
 
from bzrlib.store.versioned import VersionedFileStore, WeaveStore
49
 
from bzrlib.store.text import TextStore
50
 
from bzrlib import symbol_versioning
51
 
from bzrlib.symbol_versioning import (deprecated_method,
52
 
        zero_nine, 
 
62
from bzrlib.symbol_versioning import (
 
63
        deprecated_method,
 
64
        zero_nine,
53
65
        )
54
 
from bzrlib.testament import Testament
55
66
from bzrlib.trace import mutter, note, warning
56
 
from bzrlib.tsort import topo_sort
57
 
from bzrlib.weave import WeaveFile
58
67
 
59
68
 
60
69
# Old formats display a warning, but only once
317
326
        or testing the revision graph.
318
327
        """
319
328
        if not revision_id or not isinstance(revision_id, basestring):
320
 
            raise InvalidRevisionId(revision_id=revision_id, branch=self)
 
329
            raise errors.InvalidRevisionId(revision_id=revision_id,
 
330
                                           branch=self)
321
331
        return self._revision_store.get_revisions([revision_id],
322
332
                                                  self.get_transaction())[0]
323
333
    @needs_read_lock
426
436
        # revisions. We don't need to see all lines in the inventory because
427
437
        # only those added in an inventory in rev X can contain a revision=X
428
438
        # line.
429
 
        for line in w.iter_lines_added_or_present_in_versions(selected_revision_ids):
430
 
            start = line.find('file_id="')+9
431
 
            if start < 9: continue
432
 
            end = line.find('"', start)
433
 
            assert end>= 0
434
 
            file_id = _unescape_xml(line[start:end])
 
439
        pb = ui.ui_factory.nested_progress_bar()
 
440
        try:
 
441
            for line in w.iter_lines_added_or_present_in_versions(
 
442
                selected_revision_ids, pb=pb):
 
443
                start = line.find('file_id="')+9
 
444
                if start < 9: continue
 
445
                end = line.find('"', start)
 
446
                assert end>= 0
 
447
                file_id = _unescape_xml(line[start:end])
435
448
 
436
 
            start = line.find('revision="')+10
437
 
            if start < 10: continue
438
 
            end = line.find('"', start)
439
 
            assert end>= 0
440
 
            revision_id = _unescape_xml(line[start:end])
441
 
            if revision_id in selected_revision_ids:
442
 
                result.setdefault(file_id, set()).add(revision_id)
 
449
                start = line.find('revision="')+10
 
450
                if start < 10: continue
 
451
                end = line.find('"', start)
 
452
                assert end>= 0
 
453
                revision_id = _unescape_xml(line[start:end])
 
454
                if revision_id in selected_revision_ids:
 
455
                    result.setdefault(file_id, set()).add(revision_id)
 
456
        finally:
 
457
            pb.finished()
443
458
        return result
444
459
 
445
460
    @needs_read_lock
492
507
        :return: a dictionary of revision_id->revision_parents_list.
493
508
        """
494
509
        # special case NULL_REVISION
495
 
        if revision_id == NULL_REVISION:
 
510
        if revision_id == _mod_revision.NULL_REVISION:
496
511
            return {}
497
 
        weave = self.get_inventory_weave()
498
 
        all_revisions = self._eliminate_revisions_not_present(weave.versions())
499
 
        entire_graph = dict([(node, weave.get_parents(node)) for 
 
512
        a_weave = self.get_inventory_weave()
 
513
        all_revisions = self._eliminate_revisions_not_present(
 
514
                                a_weave.versions())
 
515
        entire_graph = dict([(node, a_weave.get_parents(node)) for 
500
516
                             node in all_revisions])
501
517
        if revision_id is None:
502
518
            return entire_graph
521
537
        :param revision_ids: an iterable of revisions to graph or None for all.
522
538
        :return: a Graph object with the graph reachable from revision_ids.
523
539
        """
524
 
        result = Graph()
 
540
        result = graph.Graph()
525
541
        if not revision_ids:
526
542
            pending = set(self.all_revision_ids())
527
543
            required = set([])
528
544
        else:
529
545
            pending = set(revision_ids)
530
546
            # special case NULL_REVISION
531
 
            if NULL_REVISION in pending:
532
 
                pending.remove(NULL_REVISION)
 
547
            if _mod_revision.NULL_REVISION in pending:
 
548
                pending.remove(_mod_revision.NULL_REVISION)
533
549
            required = set(pending)
534
550
        done = set([])
535
551
        while len(pending):
589
605
        """
590
606
        # TODO: refactor this to use an existing revision object
591
607
        # so we don't need to read it in twice.
592
 
        if revision_id is None or revision_id == NULL_REVISION:
593
 
            return RevisionTree(self, Inventory(), NULL_REVISION)
 
608
        if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
 
609
            return RevisionTree(self, Inventory(root_id=None), 
 
610
                                _mod_revision.NULL_REVISION)
594
611
        else:
595
612
            inv = self.get_revision_inventory(revision_id)
596
613
            return RevisionTree(self, inv, revision_id)
601
618
 
602
619
        `revision_id` may not be None or 'null:'"""
603
620
        assert None not in revision_ids
604
 
        assert NULL_REVISION not in revision_ids
 
621
        assert _mod_revision.NULL_REVISION not in revision_ids
605
622
        texts = self.get_inventory_weave().get_texts(revision_ids)
606
623
        for text, revision_id in zip(texts, revision_ids):
607
624
            inv = self.deserialise_inventory(revision_id, text)
709
726
        warning("Format %s for %s is deprecated - please use 'bzr upgrade' to get better performance"
710
727
                % (self._format, self.bzrdir.transport.base))
711
728
 
 
729
    def supports_rich_root(self):
 
730
        return self._format.rich_root_data
 
731
 
712
732
 
713
733
class AllInOneRepository(Repository):
714
734
    """Legacy support - the repository behaviour for all-in-one branches."""
777
797
            parent_trees[p_id] = repository.revision_tree(None)
778
798
 
779
799
    inv = revision_tree.inventory
780
 
    
 
800
    entries = inv.iter_entries()
781
801
    # backwards compatability hack: skip the root id.
782
 
    entries = inv.iter_entries()
783
 
    entries.next()
 
802
    if not repository.supports_rich_root():
 
803
        path, root = entries.next()
 
804
        if root.revision != rev.revision_id:
 
805
            raise errors.IncompatibleRevision(repr(repository))
784
806
    # Add the texts that are not already present
785
807
    for path, ie in entries:
786
808
        w = repository.weave_store.get_weave_or_empty(ie.file_id,
923
945
        :return: a dictionary of revision_id->revision_parents_list.
924
946
        """
925
947
        # special case NULL_REVISION
926
 
        if revision_id == NULL_REVISION:
 
948
        if revision_id == _mod_revision.NULL_REVISION:
927
949
            return {}
928
 
        weave = self._get_revision_vf()
929
 
        entire_graph = weave.get_graph()
 
950
        a_weave = self._get_revision_vf()
 
951
        entire_graph = a_weave.get_graph()
930
952
        if revision_id is None:
931
 
            return weave.get_graph()
932
 
        elif revision_id not in weave:
 
953
            return a_weave.get_graph()
 
954
        elif revision_id not in a_weave:
933
955
            raise errors.NoSuchRevision(self, revision_id)
934
956
        else:
935
957
            # add what can be reached from revision_id
937
959
            pending = set([revision_id])
938
960
            while len(pending) > 0:
939
961
                node = pending.pop()
940
 
                result[node] = weave.get_parents(node)
 
962
                result[node] = a_weave.get_parents(node)
941
963
                for revision_id in result[node]:
942
964
                    if revision_id not in result:
943
965
                        pending.add(revision_id)
950
972
        :param revision_ids: an iterable of revisions to graph or None for all.
951
973
        :return: a Graph object with the graph reachable from revision_ids.
952
974
        """
953
 
        result = Graph()
 
975
        result = graph.Graph()
954
976
        vf = self._get_revision_vf()
955
977
        versions = set(vf.versions())
956
978
        if not revision_ids:
959
981
        else:
960
982
            pending = set(revision_ids)
961
983
            # special case NULL_REVISION
962
 
            if NULL_REVISION in pending:
963
 
                pending.remove(NULL_REVISION)
 
984
            if _mod_revision.NULL_REVISION in pending:
 
985
                pending.remove(_mod_revision.NULL_REVISION)
964
986
            required = set(pending)
965
987
        done = set([])
966
988
        while len(pending):
1145
1167
                                  transport,
1146
1168
                                  control_files,
1147
1169
                                  prefixed=True,
1148
 
                                  versionedfile_class=WeaveFile,
 
1170
                                  versionedfile_class=weave.WeaveFile,
1149
1171
                                  versionedfile_kwargs={},
1150
1172
                                  escaped=False):
1151
1173
        weave_transport = control_files._transport.clone(name)
1212
1234
        TODO: when creating split out bzr branch formats, move this to a common
1213
1235
        base for Format5, Format6. or something like that.
1214
1236
        """
1215
 
        from bzrlib.weavefile import write_weave_v5
1216
 
        from bzrlib.weave import Weave
1217
 
 
1218
1237
        if shared:
1219
1238
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
1220
1239
 
1224
1243
        
1225
1244
        # Create an empty weave
1226
1245
        sio = StringIO()
1227
 
        write_weave_v5(Weave(), sio)
 
1246
        weavefile.write_weave_v5(weave.Weave(), sio)
1228
1247
        empty_weave = sio.getvalue()
1229
1248
 
1230
1249
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1234
1253
        
1235
1254
        # FIXME: RBC 20060125 don't peek under the covers
1236
1255
        # NB: no need to escape relative paths that are url safe.
1237
 
        control_files = LockableFiles(a_bzrdir.transport, 'branch-lock',
1238
 
                                      TransportLock)
 
1256
        control_files = lockable_files.LockableFiles(a_bzrdir.transport,
 
1257
                                'branch-lock', lockable_files.TransportLock)
1239
1258
        control_files.create_lock()
1240
1259
        control_files.lock_write()
1241
1260
        control_files._transport.mkdir_multi(dirs,
1405
1424
        # FIXME: RBC 20060125 don't peek under the covers
1406
1425
        # NB: no need to escape relative paths that are url safe.
1407
1426
        repository_transport = a_bzrdir.get_repository_transport(self)
1408
 
        control_files = LockableFiles(repository_transport, 'lock', LockDir)
 
1427
        control_files = lockable_files.LockableFiles(repository_transport,
 
1428
                                'lock', lockdir.LockDir)
1409
1429
        control_files.create_lock()
1410
1430
        return control_files
1411
1431
 
1477
1497
        :param shared: If true the repository will be initialized as a shared
1478
1498
                       repository.
1479
1499
        """
1480
 
        from bzrlib.weavefile import write_weave_v5
1481
 
        from bzrlib.weave import Weave
1482
 
 
1483
1500
        # Create an empty weave
1484
1501
        sio = StringIO()
1485
 
        write_weave_v5(Weave(), sio)
 
1502
        weavefile.write_weave_v5(weave.Weave(), sio)
1486
1503
        empty_weave = sio.getvalue()
1487
1504
 
1488
1505
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1508
1525
            repo_transport = _override_transport
1509
1526
        else:
1510
1527
            repo_transport = a_bzrdir.get_repository_transport(None)
1511
 
        control_files = LockableFiles(repo_transport, 'lock', LockDir)
 
1528
        control_files = lockable_files.LockableFiles(repo_transport,
 
1529
                                'lock', lockdir.LockDir)
1512
1530
        text_store = self._get_text_store(repo_transport, control_files)
1513
1531
        control_store = self._get_control_store(repo_transport, control_files)
1514
1532
        _revision_store = self._get_revision_store(repo_transport, control_files)
1540
1558
            repo_transport,
1541
1559
            prefixed=False,
1542
1560
            file_mode=control_files._file_mode,
1543
 
            versionedfile_class=KnitVersionedFile,
1544
 
            versionedfile_kwargs={'factory':KnitPlainFactory()},
 
1561
            versionedfile_class=knit.KnitVersionedFile,
 
1562
            versionedfile_kwargs={'factory':knit.KnitPlainFactory()},
1545
1563
            )
1546
1564
 
1547
1565
    def _get_revision_store(self, repo_transport, control_files):
1552
1570
            file_mode=control_files._file_mode,
1553
1571
            prefixed=False,
1554
1572
            precious=True,
1555
 
            versionedfile_class=KnitVersionedFile,
1556
 
            versionedfile_kwargs={'delta':False, 'factory':KnitPlainFactory(),},
 
1573
            versionedfile_class=knit.KnitVersionedFile,
 
1574
            versionedfile_kwargs={'delta':False,
 
1575
                                  'factory':knit.KnitPlainFactory(),
 
1576
                                 },
1557
1577
            escaped=True,
1558
1578
            )
1559
1579
        return KnitRevisionStore(versioned_file_store)
1561
1581
    def _get_text_store(self, transport, control_files):
1562
1582
        """See RepositoryFormat._get_text_store()."""
1563
1583
        return self._get_versioned_file_store('knits',
1564
 
                                              transport,
1565
 
                                              control_files,
1566
 
                                              versionedfile_class=KnitVersionedFile,
1567
 
                                              versionedfile_kwargs={
1568
 
                                                  'create_parent_dir':True,
1569
 
                                                  'delay_create':True,
1570
 
                                                  'dir_mode':control_files._dir_mode,
1571
 
                                              },
1572
 
                                              escaped=True)
 
1584
                                  transport,
 
1585
                                  control_files,
 
1586
                                  versionedfile_class=knit.KnitVersionedFile,
 
1587
                                  versionedfile_kwargs={
 
1588
                                      'create_parent_dir':True,
 
1589
                                      'delay_create':True,
 
1590
                                      'dir_mode':control_files._dir_mode,
 
1591
                                  },
 
1592
                                  escaped=True)
1573
1593
 
1574
1594
    def initialize(self, a_bzrdir, shared=False):
1575
1595
        """Create a knit format 1 repository.
1586
1606
        
1587
1607
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1588
1608
        repo_transport = a_bzrdir.get_repository_transport(None)
1589
 
        control_files = LockableFiles(repo_transport, 'lock', LockDir)
 
1609
        control_files = lockable_files.LockableFiles(repo_transport,
 
1610
                                'lock', lockdir.LockDir)
1590
1611
        control_store = self._get_control_store(repo_transport, control_files)
1591
1612
        transaction = transactions.WriteTransaction()
1592
1613
        # trigger a write of the inventory store.
1610
1631
            repo_transport = _override_transport
1611
1632
        else:
1612
1633
            repo_transport = a_bzrdir.get_repository_transport(None)
1613
 
        control_files = LockableFiles(repo_transport, 'lock', LockDir)
 
1634
        control_files = lockable_files.LockableFiles(repo_transport,
 
1635
                                'lock', lockdir.LockDir)
1614
1636
        text_store = self._get_text_store(repo_transport, control_files)
1615
1637
        control_store = self._get_control_store(repo_transport, control_files)
1616
1638
        _revision_store = self._get_revision_store(repo_transport, control_files)
1695
1717
            repo_transport = _override_transport
1696
1718
        else:
1697
1719
            repo_transport = a_bzrdir.get_repository_transport(None)
1698
 
        control_files = LockableFiles(repo_transport, 'lock', LockDir)
 
1720
        control_files = lockable_files.LockableFiles(repo_transport, 'lock',
 
1721
                                                     lockdir.LockDir)
1699
1722
        text_store = self._get_text_store(repo_transport, control_files)
1700
1723
        control_store = self._get_control_store(repo_transport, control_files)
1701
1724
        _revision_store = self._get_revision_store(repo_transport, control_files)
1816
1839
        if basis is not None:
1817
1840
            self.target.fetch(basis, revision_id=revision_id)
1818
1841
        # but don't bother fetching if we have the needed data now.
1819
 
        if (revision_id not in (None, NULL_REVISION) and 
 
1842
        if (revision_id not in (None, _mod_revision.NULL_REVISION) and 
1820
1843
            self.target.has_revision(revision_id)):
1821
1844
            return
1822
1845
        self.target.fetch(self.source, revision_id=revision_id)
2060
2083
        if basis is not None:
2061
2084
            self.target.fetch(basis, revision_id=revision_id)
2062
2085
        # but don't bother fetching if we have the needed data now.
2063
 
        if (revision_id not in (None, NULL_REVISION) and 
 
2086
        if (revision_id not in (None, _mod_revision.NULL_REVISION) and 
2064
2087
            self.target.has_revision(revision_id)):
2065
2088
            return
2066
2089
        self.target.fetch(self.source, revision_id=revision_id)
2115
2138
        self._formats = formats
2116
2139
    
2117
2140
    def adapt(self, test):
2118
 
        result = TestSuite()
 
2141
        result = unittest.TestSuite()
2119
2142
        for repository_format, bzrdir_format in self._formats:
2120
2143
            new_test = deepcopy(test)
2121
2144
            new_test.transport_server = self._transport_server
2145
2168
        self._formats = formats
2146
2169
    
2147
2170
    def adapt(self, test):
2148
 
        result = TestSuite()
 
2171
        result = unittest.TestSuite()
2149
2172
        for interrepo_class, repository_format, repository_format_to in self._formats:
2150
2173
            new_test = deepcopy(test)
2151
2174
            new_test.transport_server = self._transport_server
2294
2317
 
2295
2318
        :return: The revision id of the recorded revision.
2296
2319
        """
2297
 
        rev = Revision(timestamp=self._timestamp,
 
2320
        rev = _mod_revision.Revision(
 
2321
                       timestamp=self._timestamp,
2298
2322
                       timezone=self._timezone,
2299
2323
                       committer=self._committer,
2300
2324
                       message=message,
2306
2330
            self.new_inventory, self._config)
2307
2331
        return self._new_revision_id
2308
2332
 
 
2333
    def revision_tree(self):
 
2334
        """Return the tree that was just committed.
 
2335
 
 
2336
        After calling commit() this can be called to get a RevisionTree
 
2337
        representing the newly committed tree. This is preferred to
 
2338
        calling Repository.revision_tree() because that may require
 
2339
        deserializing the inventory, while we already have a copy in
 
2340
        memory.
 
2341
        """
 
2342
        return RevisionTree(self.repository, self.new_inventory,
 
2343
                            self._new_revision_id)
 
2344
 
2309
2345
    def finish_inventory(self):
2310
2346
        """Tell the builder that the inventory is finished."""
2311
2347
        if self.new_inventory.root is None:
2322
2358
 
2323
2359
    def _gen_revision_id(self):
2324
2360
        """Return new revision-id."""
2325
 
        s = '%s-%s-' % (self._config.user_email(), 
2326
 
                        compact_date(self._timestamp))
2327
 
        s += hexlify(rand_bytes(8))
2328
 
        return s
 
2361
        return generate_ids.gen_revision_id(self._config.username(),
 
2362
                                            self._timestamp)
2329
2363
 
2330
2364
    def _generate_revision_if_needed(self):
2331
2365
        """Create a revision id if None was supplied.
2367
2401
 
2368
2402
        # In this revision format, root entries have no knit or weave
2369
2403
        if ie is self.new_inventory.root:
2370
 
            if len(parent_invs):
2371
 
                ie.revision = parent_invs[0].root.revision
2372
 
            else:
2373
 
                ie.revision = None
 
2404
            # When serializing out to disk and back in
 
2405
            # root.revision is always _new_revision_id
 
2406
            ie.revision = self._new_revision_id
2374
2407
            return
2375
2408
        previous_entries = ie.find_previous_heads(
2376
2409
            parent_invs,
2501
2534
    """Unescape predefined XML entities in a string of data."""
2502
2535
    global _unescape_re
2503
2536
    if _unescape_re is None:
2504
 
        _unescape_re = re.compile('\&([^;]*);')
 
2537
        _unescape_re = re.compile('\&([^;]*);')
2505
2538
    return _unescape_re.sub(_unescaper, data)