Mercurial > hgsubversion
comparison push_cmd.py @ 83:6c9b7cf1c5aa
push_cmd: delete empty svn directories, refactor directory creation
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Fri, 14 Nov 2008 16:18:24 -0600 |
parents | 49b7cbe4c8e3 |
children | 05a0c4f6060f |
comparison
equal
deleted
inserted
replaced
82:71de43e9f614 | 83:6c9b7cf1c5aa |
---|---|
66 outgoing = utility_commands.outgoing_revisions(ui, repo, hge, | 66 outgoing = utility_commands.outgoing_revisions(ui, repo, hge, |
67 svn_commit_hashes) | 67 svn_commit_hashes) |
68 merc_util._encoding = oldencoding | 68 merc_util._encoding = oldencoding |
69 return 0 | 69 return 0 |
70 | 70 |
71 | 71 def _getdirchanges(svn, branchpath, parentctx, ctx, changedfiles): |
72 def _findmissing(dirname, svn, branch_path): | 72 """Compute directories to add or delete when moving from parentctx |
73 """Find missing directories in svn. dirname *must* end in a / | 73 to ctx, assuming only 'changedfiles' files changed. |
74 | |
75 Return (added, deleted) where 'added' is the list of all added | |
76 directories and 'deleted' the list of deleted directories. | |
77 Intermediate directories are included: if a/b/c is new and requires | |
78 the addition of a/b and a, those will be listed too. Intermediate | |
79 deleted directories are also listed, but item order of undefined | |
80 in either list. | |
74 """ | 81 """ |
75 assert dirname[-1] == '/' | 82 def exists(svndir): |
76 missing = [] | |
77 keep_checking = True | |
78 # check and see if the dir exists svn-side. | |
79 path = dirname | |
80 while keep_checking: | |
81 try: | 83 try: |
82 assert svn.list_dir('%s/%s' % (branch_path, path)) | 84 svn.list_dir('%s/%s' % (branchpath, svndir)) |
83 keep_checking = False | 85 return True |
84 except core.SubversionException, e: | 86 except core.SubversionException: |
85 # dir must not exist | 87 return False |
86 missing.append(path[:-1]) | 88 |
87 path = '/'.join(path.split('/')[:-2] + ['']) | 89 def finddirs(path): |
88 return missing | 90 pos = path.rfind('/') |
91 while pos != -1: | |
92 yield path[:pos] | |
93 pos = path.rfind('/', 0, pos) | |
94 | |
95 def getctxdirs(ctx, keptdirs): | |
96 dirs = {} | |
97 for f in ctx.manifest(): | |
98 for d in finddirs(f): | |
99 if d in dirs: | |
100 break | |
101 if d in keptdirs: | |
102 dirs[d] = 1 | |
103 return dirs | |
104 | |
105 deleted, added = [], [] | |
106 if not changedfiles: | |
107 return added, deleted | |
108 changeddirs = {} | |
109 for f in changedfiles: | |
110 for d in finddirs(f): | |
111 changeddirs[d] = 1 | |
112 olddirs = getctxdirs(parentctx, changeddirs) | |
113 newdirs = getctxdirs(ctx, changeddirs) | |
114 | |
115 for d in newdirs: | |
116 if d not in olddirs and not exists(d): | |
117 added.append(d) | |
118 | |
119 for d in olddirs: | |
120 if d not in newdirs and exists(d): | |
121 deleted.append(d) | |
122 | |
123 return added, deleted | |
124 | |
89 | 125 |
90 def commit_from_rev(ui, repo, rev_ctx, hg_editor, svn_url, base_revision): | 126 def commit_from_rev(ui, repo, rev_ctx, hg_editor, svn_url, base_revision): |
91 """Build and send a commit from Mercurial to Subversion. | 127 """Build and send a commit from Mercurial to Subversion. |
92 """ | 128 """ |
93 file_data = {} | 129 file_data = {} |
97 branch_path = 'trunk' | 133 branch_path = 'trunk' |
98 | 134 |
99 if parent_branch and parent_branch != 'default': | 135 if parent_branch and parent_branch != 'default': |
100 branch_path = 'branches/%s' % parent_branch | 136 branch_path = 'branches/%s' % parent_branch |
101 | 137 |
102 added_dirs = [] | 138 addeddirs, deleteddirs = _getdirchanges(svn, branch_path, parent, |
139 rev_ctx, rev_ctx.files()) | |
140 deleteddirs = set(deleteddirs) | |
141 | |
103 props = {} | 142 props = {} |
104 copies = {} | 143 copies = {} |
105 for file in rev_ctx.files(): | 144 for file in rev_ctx.files(): |
106 new_data = base_data = '' | 145 new_data = base_data = '' |
107 action = '' | 146 action = '' |
122 copies[file] = renamed[0] | 161 copies[file] = renamed[0] |
123 base_data = parent[renamed[0]].data() | 162 base_data = parent[renamed[0]].data() |
124 | 163 |
125 action = 'add' | 164 action = 'add' |
126 dirname = '/'.join(file.split('/')[:-1] + ['']) | 165 dirname = '/'.join(file.split('/')[:-1] + ['']) |
127 # check for new directories | |
128 if not list(parent.walk(util.PrefixMatch(dirname))): | |
129 added_dirs += _findmissing(dirname, svn, branch_path) | |
130 else: | 166 else: |
131 base_data = parent.filectx(file).data() | 167 base_data = parent.filectx(file).data() |
132 if ('x' in parent.filectx(file).flags() | 168 if ('x' in parent.filectx(file).flags() |
133 and 'x' not in rev_ctx.filectx(file).flags()): | 169 and 'x' not in rev_ctx.filectx(file).flags()): |
134 props.setdefault(file, {})['svn:executable'] = None | 170 props.setdefault(file, {})['svn:executable'] = None |
135 if ('l' in parent.filectx(file).flags() | 171 if ('l' in parent.filectx(file).flags() |
136 and 'l' not in rev_ctx.filectx(file).flags()): | 172 and 'l' not in rev_ctx.filectx(file).flags()): |
137 props.setdefault(file, {})['svn:special'] = None | 173 props.setdefault(file, {})['svn:special'] = None |
138 action = 'modify' | 174 action = 'modify' |
139 else: | 175 else: |
176 pos = file.rfind('/') | |
177 if pos >= 0: | |
178 if file[:pos] in deleteddirs: | |
179 # This file will be removed when its directory is removed | |
180 continue | |
140 base_data = parent.filectx(file).data() | 181 base_data = parent.filectx(file).data() |
141 action = 'delete' | 182 action = 'delete' |
142 file_data[file] = base_data, new_data, action | 183 file_data[file] = base_data, new_data, action |
143 | 184 |
144 # TODO check for directory deletes here | 185 # Now we are done with files, we can prune deleted directories |
186 # against themselves: ignore a/b if a/ is already removed | |
187 deleteddirs2 = list(deleteddirs) | |
188 deleteddirs2.sort() | |
189 deleteddirs2.reverse() | |
190 for d in deleteddirs2: | |
191 pos = d.rfind('/') | |
192 if pos >= 0 and d[:pos] in deleteddirs: | |
193 deleteddirs.remove(d[:pos]) | |
194 | |
145 def svnpath(p): | 195 def svnpath(p): |
146 return '%s/%s' % (branch_path, p) | 196 return '%s/%s' % (branch_path, p) |
147 | 197 |
148 newcopies = {} | 198 newcopies = {} |
149 for source, dest in copies.iteritems(): | 199 for source, dest in copies.iteritems(): |
150 newcopies[svnpath(source)] = (svnpath(dest), base_revision) | 200 newcopies[svnpath(source)] = (svnpath(dest), base_revision) |
151 | 201 |
152 new_target_files = [svnpath(f) for f in rev_ctx.files()] | 202 new_target_files = [svnpath(f) for f in file_data] |
153 for tf, ntf in zip(rev_ctx.files(), new_target_files): | 203 for tf, ntf in zip(file_data, new_target_files): |
154 if tf in file_data: | 204 if tf in file_data: |
155 file_data[ntf] = file_data[tf] | 205 file_data[ntf] = file_data[tf] |
156 if tf in props: | 206 if tf in props: |
157 props[ntf] = props[tf] | 207 props[ntf] = props[tf] |
158 del props[tf] | 208 del props[tf] |
159 if merc_util.binary(file_data[ntf][1]): | 209 if merc_util.binary(file_data[ntf][1]): |
160 props.setdefault(ntf, {}).update(props.get(ntf, {})) | 210 props.setdefault(ntf, {}).update(props.get(ntf, {})) |
161 props.setdefault(ntf, {})['svn:mime-type'] = 'application/octet-stream' | 211 props.setdefault(ntf, {})['svn:mime-type'] = 'application/octet-stream' |
162 del file_data[tf] | 212 del file_data[tf] |
163 added_dirs = ['%s/%s' % (branch_path, f) for f in added_dirs] | 213 |
164 added_dirs = set(added_dirs) | 214 addeddirs = [svnpath(d) for d in addeddirs] |
165 new_target_files += added_dirs | 215 deleteddirs = [svnpath(d) for d in deleteddirs] |
216 new_target_files += addeddirs + deleteddirs | |
166 try: | 217 try: |
167 svn.commit(new_target_files, rev_ctx.description(), file_data, | 218 svn.commit(new_target_files, rev_ctx.description(), file_data, |
168 base_revision, set(added_dirs), props, newcopies) | 219 base_revision, set(addeddirs), set(deleteddirs), |
220 props, newcopies) | |
169 except core.SubversionException, e: | 221 except core.SubversionException, e: |
170 if hasattr(e, 'apr_err') and e.apr_err == 160028: | 222 if hasattr(e, 'apr_err') and e.apr_err == 160028: |
171 raise merc_util.Abort('Base text was out of date, maybe rebase?') | 223 raise merc_util.Abort('Base text was out of date, maybe rebase?') |
172 else: | 224 else: |
173 raise | 225 raise |