31
31
from bzrlib.plugins.svn.errors import InvalidFileName
32
from mapping import (SVN_PROP_BZR_ANCESTRY, SVN_PROP_BZR_MERGE,
32
from logwalker import lazy_dict
33
from bzrlib.plugins.svn.mapping import (SVN_PROP_BZR_MERGE,
33
34
SVN_PROP_BZR_PREFIX, SVN_PROP_BZR_REVISION_INFO,
34
SVN_PROP_BZR_BRANCHING_SCHEME, SVN_PROP_BZR_REVISION_ID,
35
SVN_PROP_BZR_REVISION_ID,
35
36
SVN_PROP_BZR_FILEIDS, SVN_REVPROP_BZR_SIGNATURE,
36
37
parse_merge_property,
37
38
parse_revision_metadata)
38
from repository import (SvnRepository, SvnRepositoryFormat)
39
from repository import SvnRepository, SvnRepositoryFormat
39
40
from svk import SVN_PROP_SVK_MERGE
40
41
from tree import (apply_txdelta_handler, parse_externals_description,
41
42
inventory_add_external)
93
94
self.source = source
94
95
self.transact = target.get_transaction()
96
def start_revision(self, revid, prev_inventory):
97
def start_revision(self, revid, prev_inventory, revmeta):
98
99
(self.branch_path, self.revnum, self.mapping) = self.source.lookup_revision_id(revid)
99
self.svn_revprops = self.source._log._get_transport().revprop_list(self.revnum)
100
changes = self.source._log.get_revision_paths(self.revnum, self.branch_path)
101
renames = self.source.revision_fileid_renames(self.branch_path, self.revnum, self.mapping,
102
revprops=self.svn_revprops)
103
self.id_map = self.source.transform_fileid_map(self.source.uuid,
104
self.revnum, self.branch_path, changes, renames,
100
self.revmeta = revmeta
106
102
self.dir_baserev = {}
107
103
self._revinfo = None
108
self._bzr_merges = ()
109
self._svk_merges = []
110
104
self._premature_deletes = set()
111
105
self.pool = Pool()
112
106
self.old_inventory = prev_inventory
113
107
self.inventory = prev_inventory.copy()
114
self._branch_fileprops = {}
115
108
self._start_revision()
117
def _get_parent_ids(self):
118
return self.source.revision_parents(self.revid, self._branch_fileprops)
110
def _get_id_map(self):
111
if self._id_map is not None:
114
renames = self.mapping.import_fileid_map(self.revmeta.revprops, self.revmeta.fileprops)
115
self._id_map = self.source.transform_fileid_map(self.source.uuid,
116
self.revnum, self.branch_path, self.revmeta.paths, renames,
120
121
def _get_revision(self, revid):
121
122
"""Creates the revision object.
171
170
def _get_new_id(self, parent_id, new_path):
172
171
assert isinstance(new_path, unicode)
173
172
assert isinstance(parent_id, str)
174
if self.id_map.has_key(new_path):
175
return self.id_map[new_path]
173
ret = self._get_id_map().get(new_path)
176
176
return self.mapping.generate_file_id(self.source.uuid, self.revnum, self.branch_path, new_path)
178
178
def _rename(self, file_id, parent_id, path):
257
257
def change_dir_prop(self, (old_id, new_id), name, value, pool):
258
258
if new_id == self.inventory.root.file_id:
259
self._branch_fileprops[name] = value
259
# Replay lazy_dict, since it may be more expensive
260
if type(self.revmeta.fileprops) != dict:
261
self.revmeta.fileprops = {}
262
self.revmeta.fileprops[name] = value
261
if name == SVN_PROP_BZR_BRANCHING_SCHEME:
262
if new_id != self.inventory.root.file_id:
263
mutter('rogue %r on non-root directory' % name)
265
elif name == SVN_PROP_BZR_ANCESTRY+str(self.mapping.scheme):
266
if new_id != self.inventory.root.file_id:
267
mutter('rogue %r on non-root directory' % name)
270
self._bzr_merges = parse_merge_property(value.splitlines()[-1])
271
elif name == SVN_PROP_SVK_MERGE:
272
self._svk_merges = None # Force Repository.revision_parents() to look it up
273
elif name == SVN_PROP_BZR_REVISION_INFO:
274
if new_id != self.inventory.root.file_id:
275
mutter('rogue %r on non-root directory' % SVN_PROP_BZR_REVISION_INFO)
278
elif name in (svn.core.SVN_PROP_ENTRY_COMMITTED_DATE,
264
if name in (svn.core.SVN_PROP_ENTRY_COMMITTED_DATE,
279
265
svn.core.SVN_PROP_ENTRY_COMMITTED_REV,
280
266
svn.core.SVN_PROP_ENTRY_LAST_AUTHOR,
281
267
svn.core.SVN_PROP_ENTRY_LOCK_TOKEN,
282
268
svn.core.SVN_PROP_ENTRY_UUID,
283
svn.core.SVN_PROP_EXECUTABLE,
284
SVN_PROP_BZR_MERGE, SVN_PROP_BZR_FILEIDS):
286
elif (name.startswith(SVN_PROP_BZR_ANCESTRY) or
287
name.startswith(SVN_PROP_BZR_REVISION_ID) or
288
name.startswith(svn.core.SVN_PROP_WC_PREFIX)):
290
elif (name.startswith(svn.core.SVN_PROP_PREFIX) or
291
name.startswith(SVN_PROP_BZR_PREFIX)):
269
svn.core.SVN_PROP_EXECUTABLE):
271
elif (name.startswith(svn.core.SVN_PROP_WC_PREFIX)):
273
elif name.startswith(svn.core.SVN_PROP_PREFIX):
292
274
mutter('unsupported dir property %r' % name)
294
276
def change_file_prop(self, id, name, value, pool):
520
501
def _get_repo_format_to_test():
504
def _find_all(self, mapping, pb=None):
524
505
"""Find all revisions from the source repository that are not
525
506
yet in the target repository.
528
needed = filter(lambda x: not self.target.has_revision(x),
529
self.source.all_revision_ids())
531
(branch, revnum, mapping) = self.source.lookup_revision_id(revid)
532
parents[revid] = self.source.lhs_revision_parent(branch, revnum, mapping)
534
return (needed, parents)
510
graph = self.source.get_graph()
511
available_revs = set()
512
for revmeta in self.source.iter_all_changes(pb=pb):
513
revid = revmeta.get_revision_id(mapping)
514
available_revs.add(revid)
515
meta_map[revid] = revmeta
516
missing = available_revs.difference(self.target.has_revisions(available_revs))
517
needed = list(graph.iter_topo_order(missing))
518
parents = graph.get_parent_map(needed)
519
return [(revid, parents[revid][0], meta_map[revid]) for revid in needed]
536
def _find_branches(self, branches, find_ghosts=False):
521
def _find_branches(self, branches, find_ghosts=False, fetch_rhs_ancestry=False, pb=None):
537
522
set_needed = set()
538
523
ret_needed = list()
540
524
for revid in branches:
541
(needed, parents) = self._find_until(revid, find_ghosts=find_ghosts)
543
if not rev in set_needed:
544
ret_needed.append(rev)
546
ret_parents.update(parents)
547
return ret_needed, ret_parents
526
pb.update("determining revisions to fetch", branches.index(revid), len(branches))
528
nestedpb = ui.ui_factory.nested_progress_bar()
529
for rev in self._find_until(revid, find_ghosts=find_ghosts, fetch_rhs_ancestry=False,
531
if rev[0] not in set_needed:
532
ret_needed.append(rev)
533
set_needed.add(rev[0])
549
def _find_until(self, revision_id, find_ghosts=False):
538
def _find_until(self, revision_id, find_ghosts=False, fetch_rhs_ancestry=False, pb=None):
550
539
"""Find all missing revisions until revision_id
552
541
:param revision_id: Stop revision
553
542
:param find_ghosts: Find ghosts
543
:param fetch_rhs_ancestry: Fetch right hand side ancestors
554
544
:return: Tuple with revisions missing and a dictionary with
555
545
parents for those revision.
561
pb = ui.ui_factory.nested_progress_bar()
563
for revid in self.source.iter_lhs_ancestry(revision_id, pb):
565
if prev_revid is not None:
566
parents[prev_revid] = revid
552
def check_revid(revision_id):
554
(branch_path, revnum, mapping) = self.source.lookup_revision_id(revision_id)
555
for revmeta in self.source.iter_reverse_branch_changes(branch_path, revnum, mapping):
557
pb.update("determining revisions to fetch", revnum-revmeta.revnum, revnum)
558
revid = revmeta.get_revision_id(mapping)
559
lhs_parent[prev] = revid
560
meta_map[revid] = revmeta
561
if fetch_rhs_ancestry:
562
extra.update(revmeta.get_rhs_parents(mapping))
570
563
if not self.target.has_revision(revid):
572
565
elif not find_ghosts:
577
parents[prev_revid] = None
579
return (needed, parents)
569
lhs_parent[prev] = NULL_REVISION
571
check_revid(revision_id)
574
if revid not in revs:
577
needed = [(revid, lhs_parent[revid], meta_map[revid]) for revid in reversed(revs)]
581
581
def copy_content(self, revision_id=None, pb=None):
582
582
"""See InterRepository.copy_content."""
591
591
raise NotImplementedError(self._copy_revisions_replay)
593
def _fetch_switch(self, revids, pb=None, lhs_parent=None):
593
def _fetch_switch(self, conn, revids, pb=None):
594
594
"""Copy a set of related revisions using svn.ra.switch.
596
596
:param revids: List of revision ids of revisions to copy,
598
598
:param pb: Optional progress bar.
600
repos_root = self.source.transport.get_svn_repos_root()
600
repos_root = conn.get_repos_root()
602
602
prev_revid = None
603
transport = self.source.transport
605
604
pb = ui.ui_factory.nested_progress_bar()
614
613
editor = revbuildklass(self.source, self.target)
616
for (revid, parent_revid, revmeta) in revids:
618
617
pb.update('copying revision', num, len(revids))
620
parent_revid = lhs_parent[revid]
619
assert parent_revid is not None
622
if parent_revid is None:
621
if parent_revid == NULL_REVISION:
623
622
parent_inv = Inventory(root_id=None)
624
623
elif prev_revid != parent_revid:
625
624
parent_inv = self.target.get_inventory(parent_revid)
627
626
parent_inv = prev_inv
629
editor.start_revision(revid, parent_inv)
628
editor.start_revision(revid, parent_inv, revmeta)
634
if parent_revid is None:
633
if parent_revid == NULL_REVISION:
635
634
branch_url = urlutils.join(repos_root,
636
635
editor.branch_path)
637
transport.reparent(branch_url)
638
assert transport.svn_url == branch_url.rstrip("/"), \
639
"Expected %r, got %r" % (transport.svn_url, branch_url)
640
reporter = transport.do_update(editor.revnum, True,
636
conn.reparent(branch_url)
637
assert conn.url == branch_url, \
638
"Expected %r, got %r" % (conn.url, branch_url)
639
reporter = conn.do_update(editor.revnum, True,
643
642
# Report status of existing paths
646
645
(parent_branch, parent_revnum, mapping) = \
647
646
self.source.lookup_revision_id(parent_revid)
648
transport.reparent(urlutils.join(repos_root, parent_branch))
647
conn.reparent(urlutils.join(repos_root, parent_branch))
650
649
if parent_branch != editor.branch_path:
651
reporter = transport.do_switch(editor.revnum, True,
650
reporter = conn.do_switch(editor.revnum, True,
652
651
urlutils.join(repos_root, editor.branch_path),
655
reporter = transport.do_update(editor.revnum, True, editor)
654
reporter = conn.do_update(editor.revnum, True, editor)
657
656
# Report status of existing paths
658
657
reporter.set_path("", parent_revnum, False, None, pool)
660
lock = transport.lock_read(".")
661
659
reporter.finish_report(pool)
664
661
editor.abort_edit()
672
669
self.target.unlock()
673
670
if nested_pb is not None:
674
671
nested_pb.finished()
675
self.source.transport.reparent_root()
677
673
def fetch(self, revision_id=None, pb=None, find_ghosts=False,
674
branches=None, fetch_rhs_ancestry=False):
679
675
"""Fetch revisions. """
680
676
if revision_id == NULL_REVISION:
682
678
# Dictionary with paths as keys, revnums as values
681
pb.update("determining revisions to fetch", 0, 2)
684
683
# Loop over all the revnums until revision_id
685
684
# (or youngest_revnum) and call self.target.add_revision()
686
685
# or self.target.add_inventory() each time
687
686
self.target.lock_read()
689
688
if branches is not None:
690
(needed, lhs_parent) = self._find_branches(branches,
689
needed = self._find_branches(branches, find_ghosts, fetch_rhs_ancestry, pb=pb)
692
690
elif revision_id is None:
693
(needed, lhs_parent) = self._find_all()
691
needed = self._find_all(self.source.get_mapping(), pb=pb)
695
(needed, lhs_parent) = self._find_until(revision_id,
693
needed = self._find_until(revision_id, find_ghosts, fetch_rhs_ancestry, pb=pb)
698
695
self.target.unlock()