annotate push_cmd.py @ 134:22248b34b15a

Add notes on how metadata is stored and recovered. Note that at this point, none of this has actually been implemented. This is documentation of the improved system to be used in the future.
author Augie Fackler <durin42@gmail.com>
date Mon, 01 Dec 2008 11:13:01 -0600
parents 1da7aafdd323
children 58ae90a65f41
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
1 from mercurial import util as merc_util
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
2 from mercurial import hg
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
3 from svn import core
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
4
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
5 import util
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
6 import hg_delta_editor
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
7 import svnwrap
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
8 import fetch_command
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
9 import utility_commands
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
10
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
11
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
12 @util.register_subcommand('push')
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
13 @util.register_subcommand('dcommit') # for git expats
86
6ecdbd22eb1d push_cmd: add option to push in stupid mode
Patrick Mezard <pmezard@gmail.com>
parents: 85
diff changeset
14 def push_revisions_to_subversion(ui, repo, hg_repo_path, svn_url,
6ecdbd22eb1d push_cmd: add option to push in stupid mode
Patrick Mezard <pmezard@gmail.com>
parents: 85
diff changeset
15 stupid=False, **opts):
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
16 """Push revisions starting at a specified head back to Subversion.
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
17 """
44
85fcac4e2291 Fix an encoding bug that would occur if the local encoding was not utf-8.
Augie Fackler <durin42@gmail.com>
parents: 39
diff changeset
18 oldencoding = merc_util._encoding
85fcac4e2291 Fix an encoding bug that would occur if the local encoding was not utf-8.
Augie Fackler <durin42@gmail.com>
parents: 39
diff changeset
19 merc_util._encoding = 'UTF-8'
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
20 hge = hg_delta_editor.HgChangeReceiver(hg_repo_path,
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
21 ui_=ui)
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
22 svn_commit_hashes = dict(zip(hge.revmap.itervalues(),
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
23 hge.revmap.iterkeys()))
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
24 # Strategy:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
25 # 1. Find all outgoing commits from this head
99
1da7aafdd323 Refactored outgoing_revisions into util where it really belongs.
Augie Fackler <durin42@gmail.com>
parents: 86
diff changeset
26 outgoing = util.outgoing_revisions(ui, repo, hge, svn_commit_hashes)
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
27 if not (outgoing and len(outgoing)):
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
28 ui.status('No revisions to push.')
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
29 return 0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
30 if len(repo.parents()) != 1:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
31 ui.status('Cowardly refusing to push branch merge')
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
32 return 1
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
33 while outgoing:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
34 oldest = outgoing.pop(-1)
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
35 old_ctx = repo[oldest]
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
36 if len(old_ctx.parents()) != 1:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
37 ui.status('Found a branch merge, this needs discussion and '
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
38 'implementation.')
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
39 return 1
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
40 base_n = old_ctx.parents()[0].node()
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
41 old_children = repo[base_n].children()
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
42 # 2. Commit oldest revision that needs to be pushed
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
43 base_revision = svn_commit_hashes[old_ctx.parents()[0].node()][0]
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
44 commit_from_rev(ui, repo, old_ctx, hge, svn_url, base_revision)
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
45 # 3. Fetch revisions from svn
86
6ecdbd22eb1d push_cmd: add option to push in stupid mode
Patrick Mezard <pmezard@gmail.com>
parents: 85
diff changeset
46 r = fetch_command.fetch_revisions(ui, svn_url, hg_repo_path,
6ecdbd22eb1d push_cmd: add option to push in stupid mode
Patrick Mezard <pmezard@gmail.com>
parents: 85
diff changeset
47 stupid=stupid)
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
48 assert not r or r == 0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
49 # 4. Find the new head of the target branch
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
50 repo = hg.repository(ui, hge.path)
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
51 base_c = repo[base_n]
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
52 replacement = [c for c in base_c.children() if c not in old_children
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
53 and c.branch() == old_ctx.branch()]
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
54 assert len(replacement) == 1
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
55 replacement = replacement[0]
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
56 # 5. Rebase all children of the currently-pushing rev to the new branch
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
57 heads = repo.heads(old_ctx.node())
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
58 for needs_transplant in heads:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
59 hg.clean(repo, needs_transplant)
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
60 utility_commands.rebase_commits(ui, repo, hg_repo_path, **opts)
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
61 repo = hg.repository(ui, hge.path)
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
62 if needs_transplant in outgoing:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
63 hg.clean(repo, repo['tip'].node())
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
64 hge = hg_delta_editor.HgChangeReceiver(hg_repo_path, ui_=ui)
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
65 svn_commit_hashes = dict(zip(hge.revmap.itervalues(),
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
66 hge.revmap.iterkeys()))
99
1da7aafdd323 Refactored outgoing_revisions into util where it really belongs.
Augie Fackler <durin42@gmail.com>
parents: 86
diff changeset
67 outgoing = util.outgoing_revisions(ui, repo, hge,
1da7aafdd323 Refactored outgoing_revisions into util where it really belongs.
Augie Fackler <durin42@gmail.com>
parents: 86
diff changeset
68 svn_commit_hashes)
44
85fcac4e2291 Fix an encoding bug that would occur if the local encoding was not utf-8.
Augie Fackler <durin42@gmail.com>
parents: 39
diff changeset
69 merc_util._encoding = oldencoding
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
70 return 0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
71
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
72 def _getdirchanges(svn, branchpath, parentctx, ctx, changedfiles):
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
73 """Compute directories to add or delete when moving from parentctx
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
74 to ctx, assuming only 'changedfiles' files changed.
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
75
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
76 Return (added, deleted) where 'added' is the list of all added
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
77 directories and 'deleted' the list of deleted directories.
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
78 Intermediate directories are included: if a/b/c is new and requires
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
79 the addition of a/b and a, those will be listed too. Intermediate
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
80 deleted directories are also listed, but item order of undefined
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
81 in either list.
65
b33940d54fe2 push: Fix missing directory creation for the case of a new dir inside a new dir.
Augie Fackler <durin42@gmail.com>
parents: 62
diff changeset
82 """
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
83 def exists(svndir):
65
b33940d54fe2 push: Fix missing directory creation for the case of a new dir inside a new dir.
Augie Fackler <durin42@gmail.com>
parents: 62
diff changeset
84 try:
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
85 svn.list_dir('%s/%s' % (branchpath, svndir))
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
86 return True
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
87 except core.SubversionException:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
88 return False
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
89
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
90 def finddirs(path):
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
91 pos = path.rfind('/')
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
92 while pos != -1:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
93 yield path[:pos]
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
94 pos = path.rfind('/', 0, pos)
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
95
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
96 def getctxdirs(ctx, keptdirs):
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
97 dirs = {}
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
98 for f in ctx.manifest():
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
99 for d in finddirs(f):
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
100 if d in dirs:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
101 break
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
102 if d in keptdirs:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
103 dirs[d] = 1
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
104 return dirs
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
105
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
106 deleted, added = [], []
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
107 changeddirs = {}
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
108 for f in changedfiles:
85
05a0c4f6060f push_cmd: consider only dirs with added/removed files for addition or deletion
Patrick Mezard <pmezard@gmail.com>
parents: 83
diff changeset
109 if f in parentctx and f in ctx:
05a0c4f6060f push_cmd: consider only dirs with added/removed files for addition or deletion
Patrick Mezard <pmezard@gmail.com>
parents: 83
diff changeset
110 # Updated files cannot cause directories to be created
05a0c4f6060f push_cmd: consider only dirs with added/removed files for addition or deletion
Patrick Mezard <pmezard@gmail.com>
parents: 83
diff changeset
111 # or removed.
05a0c4f6060f push_cmd: consider only dirs with added/removed files for addition or deletion
Patrick Mezard <pmezard@gmail.com>
parents: 83
diff changeset
112 continue
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
113 for d in finddirs(f):
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
114 changeddirs[d] = 1
85
05a0c4f6060f push_cmd: consider only dirs with added/removed files for addition or deletion
Patrick Mezard <pmezard@gmail.com>
parents: 83
diff changeset
115 if not changeddirs:
05a0c4f6060f push_cmd: consider only dirs with added/removed files for addition or deletion
Patrick Mezard <pmezard@gmail.com>
parents: 83
diff changeset
116 return added, deleted
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
117 olddirs = getctxdirs(parentctx, changeddirs)
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
118 newdirs = getctxdirs(ctx, changeddirs)
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
119
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
120 for d in newdirs:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
121 if d not in olddirs and not exists(d):
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
122 added.append(d)
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
123
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
124 for d in olddirs:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
125 if d not in newdirs and exists(d):
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
126 deleted.append(d)
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
127
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
128 return added, deleted
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
129
65
b33940d54fe2 push: Fix missing directory creation for the case of a new dir inside a new dir.
Augie Fackler <durin42@gmail.com>
parents: 62
diff changeset
130
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
131 def commit_from_rev(ui, repo, rev_ctx, hg_editor, svn_url, base_revision):
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
132 """Build and send a commit from Mercurial to Subversion.
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
133 """
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
134 file_data = {}
9
9eb6bf2be1e7 Fix adding files that require new directories.
Augie Fackler <durin42@gmail.com>
parents: 6
diff changeset
135 svn = svnwrap.SubversionRepo(svn_url, username=merc_util.getuser())
9eb6bf2be1e7 Fix adding files that require new directories.
Augie Fackler <durin42@gmail.com>
parents: 6
diff changeset
136 parent = rev_ctx.parents()[0]
9eb6bf2be1e7 Fix adding files that require new directories.
Augie Fackler <durin42@gmail.com>
parents: 6
diff changeset
137 parent_branch = rev_ctx.parents()[0].branch()
9eb6bf2be1e7 Fix adding files that require new directories.
Augie Fackler <durin42@gmail.com>
parents: 6
diff changeset
138 branch_path = 'trunk'
9eb6bf2be1e7 Fix adding files that require new directories.
Augie Fackler <durin42@gmail.com>
parents: 6
diff changeset
139
9eb6bf2be1e7 Fix adding files that require new directories.
Augie Fackler <durin42@gmail.com>
parents: 6
diff changeset
140 if parent_branch and parent_branch != 'default':
9eb6bf2be1e7 Fix adding files that require new directories.
Augie Fackler <durin42@gmail.com>
parents: 6
diff changeset
141 branch_path = 'branches/%s' % parent_branch
9eb6bf2be1e7 Fix adding files that require new directories.
Augie Fackler <durin42@gmail.com>
parents: 6
diff changeset
142
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
143 addeddirs, deleteddirs = _getdirchanges(svn, branch_path, parent,
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
144 rev_ctx, rev_ctx.files())
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
145 deleteddirs = set(deleteddirs)
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
146
10
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
147 props = {}
70
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
148 copies = {}
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
149 for file in rev_ctx.files():
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
150 new_data = base_data = ''
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
151 action = ''
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
152 if file in rev_ctx:
70
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
153 fctx = rev_ctx.filectx(file)
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
154 new_data = fctx.data()
10
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
155
70
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
156 if 'x' in fctx.flags():
10
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
157 props.setdefault(file, {})['svn:executable'] = '*'
70
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
158 if 'l' in fctx.flags():
10
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
159 props.setdefault(file, {})['svn:special'] = '*'
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
160
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
161 if file not in parent:
70
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
162 renamed = fctx.renamed()
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
163 if renamed:
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
164 # TODO current model (and perhaps svn model) does not support
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
165 # this kind of renames: a -> b, b -> c
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
166 copies[file] = renamed[0]
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
167 base_data = parent[renamed[0]].data()
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
168
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
169 action = 'add'
9
9eb6bf2be1e7 Fix adding files that require new directories.
Augie Fackler <durin42@gmail.com>
parents: 6
diff changeset
170 dirname = '/'.join(file.split('/')[:-1] + [''])
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
171 else:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
172 base_data = parent.filectx(file).data()
62
cc5ebdb1e8d4 push_cmd: Further simplified some logic thanks to an improved test.
Augie Fackler <durin42@gmail.com>
parents: 60
diff changeset
173 if ('x' in parent.filectx(file).flags()
cc5ebdb1e8d4 push_cmd: Further simplified some logic thanks to an improved test.
Augie Fackler <durin42@gmail.com>
parents: 60
diff changeset
174 and 'x' not in rev_ctx.filectx(file).flags()):
cc5ebdb1e8d4 push_cmd: Further simplified some logic thanks to an improved test.
Augie Fackler <durin42@gmail.com>
parents: 60
diff changeset
175 props.setdefault(file, {})['svn:executable'] = None
60
41dc00c7aef1 Fixed a problem where if you edited an existing symlink by replacing with another symlink, things would get corrupt.
Augie Fackler <durin42@gmail.com>
parents: 57
diff changeset
176 if ('l' in parent.filectx(file).flags()
41dc00c7aef1 Fixed a problem where if you edited an existing symlink by replacing with another symlink, things would get corrupt.
Augie Fackler <durin42@gmail.com>
parents: 57
diff changeset
177 and 'l' not in rev_ctx.filectx(file).flags()):
41dc00c7aef1 Fixed a problem where if you edited an existing symlink by replacing with another symlink, things would get corrupt.
Augie Fackler <durin42@gmail.com>
parents: 57
diff changeset
178 props.setdefault(file, {})['svn:special'] = None
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
179 action = 'modify'
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
180 else:
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
181 pos = file.rfind('/')
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
182 if pos >= 0:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
183 if file[:pos] in deleteddirs:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
184 # This file will be removed when its directory is removed
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
185 continue
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
186 base_data = parent.filectx(file).data()
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
187 action = 'delete'
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
188 file_data[file] = base_data, new_data, action
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
189
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
190 # Now we are done with files, we can prune deleted directories
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
191 # against themselves: ignore a/b if a/ is already removed
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
192 deleteddirs2 = list(deleteddirs)
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
193 deleteddirs2.sort()
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
194 deleteddirs2.reverse()
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
195 for d in deleteddirs2:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
196 pos = d.rfind('/')
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
197 if pos >= 0 and d[:pos] in deleteddirs:
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
198 deleteddirs.remove(d[:pos])
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
199
70
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
200 def svnpath(p):
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
201 return '%s/%s' % (branch_path, p)
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
202
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
203 newcopies = {}
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
204 for source, dest in copies.iteritems():
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
205 newcopies[svnpath(source)] = (svnpath(dest), base_revision)
49b7cbe4c8e3 push_cmd: handle copies at file level
Patrick Mezard <pmezard@gmail.com>
parents: 65
diff changeset
206
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
207 new_target_files = [svnpath(f) for f in file_data]
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
208 for tf, ntf in zip(file_data, new_target_files):
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
209 if tf in file_data:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
210 file_data[ntf] = file_data[tf]
10
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
211 if tf in props:
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
212 props[ntf] = props[tf]
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
213 del props[tf]
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
214 if merc_util.binary(file_data[ntf][1]):
dfdc078661db Auto-set executable, symlink, and auto-props.
Augie Fackler <durin42@gmail.com>
parents: 9
diff changeset
215 props.setdefault(ntf, {}).update(props.get(ntf, {}))
12
c5039390332f Fix partial implementation.
Augie Fackler <durin42@gmail.com>
parents: 10
diff changeset
216 props.setdefault(ntf, {})['svn:mime-type'] = 'application/octet-stream'
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
217 del file_data[tf]
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
218
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
219 addeddirs = [svnpath(d) for d in addeddirs]
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
220 deleteddirs = [svnpath(d) for d in deleteddirs]
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
221 new_target_files += addeddirs + deleteddirs
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
222 try:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
223 svn.commit(new_target_files, rev_ctx.description(), file_data,
83
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
224 base_revision, set(addeddirs), set(deleteddirs),
6c9b7cf1c5aa push_cmd: delete empty svn directories, refactor directory creation
Patrick Mezard <pmezard@gmail.com>
parents: 70
diff changeset
225 props, newcopies)
0
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
226 except core.SubversionException, e:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
227 if hasattr(e, 'apr_err') and e.apr_err == 160028:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
228 raise merc_util.Abort('Base text was out of date, maybe rebase?')
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
229 else:
f2636cfed115 Initial import of hgsubversion into a public repository.
Augie Fackler <durin42@gmail.com>
parents:
diff changeset
230 raise