Mercurial > hgsubversion
comparison push_cmd.py @ 0:f2636cfed115
Initial import of hgsubversion into a public repository.
author | Augie Fackler <durin42@gmail.com> |
---|---|
date | Tue, 30 Sep 2008 11:42:52 -0500 |
parents | |
children | 1a5bb173170b |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f2636cfed115 |
---|---|
1 from mercurial import util as merc_util | |
2 from mercurial import hg | |
3 from svn import core | |
4 | |
5 import util | |
6 import hg_delta_editor | |
7 import svnwrap | |
8 import fetch_command | |
9 import utility_commands | |
10 | |
11 | |
12 @util.register_subcommand('push') | |
13 @util.register_subcommand('dcommit') # for git expats | |
14 def push_revisions_to_subversion(ui, repo, hg_repo_path, svn_url, **opts): | |
15 """Push revisions starting at a specified head back to Subversion. | |
16 """ | |
17 #assert False # safety while the command is partially implemented. | |
18 hge = hg_delta_editor.HgChangeReceiver(hg_repo_path, | |
19 ui_=ui) | |
20 svn_commit_hashes = dict(zip(hge.revmap.itervalues(), | |
21 hge.revmap.iterkeys())) | |
22 # Strategy: | |
23 # 1. Find all outgoing commits from this head | |
24 outgoing = utility_commands.outgoing_revisions(ui, repo, hge, | |
25 svn_commit_hashes) | |
26 if not (outgoing and len(outgoing)): | |
27 ui.status('No revisions to push.') | |
28 return 0 | |
29 if len(repo.parents()) != 1: | |
30 ui.status('Cowardly refusing to push branch merge') | |
31 return 1 | |
32 while outgoing: | |
33 oldest = outgoing.pop(-1) | |
34 old_ctx = repo[oldest] | |
35 if len(old_ctx.parents()) != 1: | |
36 ui.status('Found a branch merge, this needs discussion and ' | |
37 'implementation.') | |
38 return 1 | |
39 base_n = old_ctx.parents()[0].node() | |
40 old_children = repo[base_n].children() | |
41 # 2. Commit oldest revision that needs to be pushed | |
42 base_revision = svn_commit_hashes[old_ctx.parents()[0].node()][0] | |
43 commit_from_rev(ui, repo, old_ctx, hge, svn_url, base_revision) | |
44 # 3. Fetch revisions from svn | |
45 r = fetch_command.fetch_revisions(ui, svn_url, hg_repo_path) | |
46 assert not r or r == 0 | |
47 # 4. Find the new head of the target branch | |
48 repo = hg.repository(ui, hge.path) | |
49 base_c = repo[base_n] | |
50 replacement = [c for c in base_c.children() if c not in old_children | |
51 and c.branch() == old_ctx.branch()] | |
52 assert len(replacement) == 1 | |
53 replacement = replacement[0] | |
54 # 5. Rebase all children of the currently-pushing rev to the new branch | |
55 heads = repo.heads(old_ctx.node()) | |
56 for needs_transplant in heads: | |
57 hg.clean(repo, needs_transplant) | |
58 utility_commands.rebase_commits(ui, repo, hg_repo_path, **opts) | |
59 repo = hg.repository(ui, hge.path) | |
60 if needs_transplant in outgoing: | |
61 hg.clean(repo, repo['tip'].node()) | |
62 hge = hg_delta_editor.HgChangeReceiver(hg_repo_path, ui_=ui) | |
63 svn_commit_hashes = dict(zip(hge.revmap.itervalues(), | |
64 hge.revmap.iterkeys())) | |
65 outgoing = utility_commands.outgoing_revisions(ui, repo, hge, | |
66 svn_commit_hashes) | |
67 return 0 | |
68 | |
69 | |
70 def commit_from_rev(ui, repo, rev_ctx, hg_editor, svn_url, base_revision): | |
71 """Build and send a commit from Mercurial to Subversion. | |
72 """ | |
73 target_files = [] | |
74 file_data = {} | |
75 for file in rev_ctx.files(): | |
76 parent = rev_ctx.parents()[0] | |
77 new_data = base_data = '' | |
78 action = '' | |
79 if file in rev_ctx: | |
80 new_data = rev_ctx.filectx(file).data() | |
81 if file not in parent: | |
82 target_files.append(file) | |
83 action = 'add' | |
84 # TODO check for mime-type autoprops here | |
85 # TODO check for directory adds here | |
86 else: | |
87 target_files.append(file) | |
88 base_data = parent.filectx(file).data() | |
89 action = 'modify' | |
90 else: | |
91 target_files.append(file) | |
92 base_data = parent.filectx(file).data() | |
93 action = 'delete' | |
94 file_data[file] = base_data, new_data, action | |
95 | |
96 # TODO check for directory deletes here | |
97 svn = svnwrap.SubversionRepo(svn_url) | |
98 parent_branch = rev_ctx.parents()[0].branch() | |
99 branch_path = 'trunk' | |
100 if parent_branch and parent_branch != 'default': | |
101 branch_path = 'branches/%s' % parent_branch | |
102 new_target_files = ['%s/%s' % (branch_path, f) for f in target_files] | |
103 for tf, ntf in zip(target_files, new_target_files): | |
104 if tf in file_data: | |
105 file_data[ntf] = file_data[tf] | |
106 del file_data[tf] | |
107 try: | |
108 svn.commit(new_target_files, rev_ctx.description(), file_data, | |
109 base_revision, set([])) | |
110 except core.SubversionException, e: | |
111 if hasattr(e, 'apr_err') and e.apr_err == 160028: | |
112 raise merc_util.Abort('Base text was out of date, maybe rebase?') | |
113 else: | |
114 raise |