216 |
216 |
217 copyfrom = {} # Map of entrypath, revision for finding source of deleted revisions. |
217 copyfrom = {} # Map of entrypath, revision for finding source of deleted revisions. |
218 copies = {} |
218 copies = {} |
219 entries = [] |
219 entries = [] |
220 self.ui.debug("Parsing revision %d\n" % revnum) |
220 self.ui.debug("Parsing revision %d\n" % revnum) |
221 if orig_paths is not None: |
221 if orig_paths is None: |
222 rev = self.rev(revnum) |
222 return |
223 try: |
223 |
224 branch = self.module.split("/")[-1] |
224 rev = self.rev(revnum) |
225 if branch == 'trunk': |
225 try: |
226 branch = '' |
226 branch = self.module.split("/")[-1] |
227 except IndexError: |
227 if branch == 'trunk': |
228 branch = None |
228 branch = '' |
|
229 except IndexError: |
|
230 branch = None |
229 |
231 |
230 for path in orig_paths: |
232 for path in orig_paths: |
231 # self.ui.write("path %s\n" % path) |
233 # self.ui.write("path %s\n" % path) |
232 if path == self.module: # Follow branching back in history |
234 if path == self.module: # Follow branching back in history |
233 ent = orig_paths[path] |
|
234 if ent: |
|
235 if ent.copyfrom_path: |
|
236 self.modulemap[ent.copyfrom_rev] = ent.copyfrom_path |
|
237 else: |
|
238 self.ui.debug("No copyfrom path, don't know what to do.\n") |
|
239 # Maybe it was added and there is no more history. |
|
240 entrypath = get_entry_from_path(path, module=self.module) |
|
241 # self.ui.write("entrypath %s\n" % entrypath) |
|
242 if entrypath is None: |
|
243 # Outside our area of interest |
|
244 self.ui.debug("boring@%s: %s\n" % (revnum, path)) |
|
245 continue |
|
246 entry = entrypath.decode(self.encoding) |
|
247 ent = orig_paths[path] |
235 ent = orig_paths[path] |
248 if not entrypath: |
236 if ent: |
249 # TODO: branch creation event |
|
250 pass |
|
251 |
|
252 kind = svn.ra.check_path(self.ra, entrypath, revnum) |
|
253 if kind == svn.core.svn_node_file: |
|
254 if ent.copyfrom_path: |
237 if ent.copyfrom_path: |
255 copyfrom_path = get_entry_from_path(ent.copyfrom_path) |
238 self.modulemap[ent.copyfrom_rev] = ent.copyfrom_path |
256 if copyfrom_path: |
239 else: |
257 self.ui.debug("Copied to %s from %s@%s\n" % (entry, copyfrom_path, ent.copyfrom_rev)) |
240 self.ui.debug("No copyfrom path, don't know what to do.\n") |
258 # It's probably important for hg that the source |
241 # Maybe it was added and there is no more history. |
259 # exists in the revision's parent, not just the |
242 entrypath = get_entry_from_path(path, module=self.module) |
260 # ent.copyfrom_rev |
243 # self.ui.write("entrypath %s\n" % entrypath) |
261 fromkind = svn.ra.check_path(self.ra, copyfrom_path, ent.copyfrom_rev) |
244 if entrypath is None: |
262 if fromkind != 0: |
245 # Outside our area of interest |
263 copies[self.recode(entry)] = self.recode(copyfrom_path) |
246 self.ui.debug("boring@%s: %s\n" % (revnum, path)) |
|
247 continue |
|
248 entry = entrypath.decode(self.encoding) |
|
249 ent = orig_paths[path] |
|
250 if not entrypath: |
|
251 # TODO: branch creation event |
|
252 pass |
|
253 |
|
254 kind = svn.ra.check_path(self.ra, entrypath, revnum) |
|
255 if kind == svn.core.svn_node_file: |
|
256 if ent.copyfrom_path: |
|
257 copyfrom_path = get_entry_from_path(ent.copyfrom_path) |
|
258 if copyfrom_path: |
|
259 self.ui.debug("Copied to %s from %s@%s\n" % (entry, copyfrom_path, ent.copyfrom_rev)) |
|
260 # It's probably important for hg that the source |
|
261 # exists in the revision's parent, not just the |
|
262 # ent.copyfrom_rev |
|
263 fromkind = svn.ra.check_path(self.ra, copyfrom_path, ent.copyfrom_rev) |
|
264 if fromkind != 0: |
|
265 copies[self.recode(entry)] = self.recode(copyfrom_path) |
|
266 entries.append(self.recode(entry)) |
|
267 elif kind == 0: # gone, but had better be a deleted *file* |
|
268 self.ui.debug("gone from %s\n" % ent.copyfrom_rev) |
|
269 |
|
270 fromrev = revnum - 1 |
|
271 # might always need to be revnum - 1 in these 3 lines? |
|
272 old_module = self.modulemap.get(fromrev, self.module) |
|
273 basepath = old_module + "/" + get_entry_from_path(path, module=self.module) |
|
274 entrypath = old_module + "/" + get_entry_from_path(path, module=self.module) |
|
275 |
|
276 def lookup_parts(p): |
|
277 rc = None |
|
278 parts = p.split("/") |
|
279 for i in range(len(parts)): |
|
280 part = "/".join(parts[:i]) |
|
281 info = part, copyfrom.get(part, None) |
|
282 if info[1] is not None: |
|
283 self.ui.debug("Found parent directory %s\n" % info) |
|
284 rc = info |
|
285 return rc |
|
286 |
|
287 self.ui.debug("base, entry %s %s\n" % (basepath, entrypath)) |
|
288 |
|
289 frompath, froment = lookup_parts(entrypath) or (None, revnum - 1) |
|
290 |
|
291 # need to remove fragment from lookup_parts and replace with copyfrom_path |
|
292 if frompath is not None: |
|
293 self.ui.debug("munge-o-matic\n") |
|
294 self.ui.debug(entrypath + '\n') |
|
295 self.ui.debug(entrypath[len(frompath):] + '\n') |
|
296 entrypath = froment.copyfrom_path + entrypath[len(frompath):] |
|
297 fromrev = froment.copyfrom_rev |
|
298 self.ui.debug("Info: %s %s %s %s\n" % (frompath, froment, ent, entrypath)) |
|
299 |
|
300 fromkind = svn.ra.check_path(self.ra, entrypath, fromrev) |
|
301 if fromkind == svn.core.svn_node_file: # a deleted file |
264 entries.append(self.recode(entry)) |
302 entries.append(self.recode(entry)) |
265 elif kind == 0: # gone, but had better be a deleted *file* |
303 else: |
266 self.ui.debug("gone from %s\n" % ent.copyfrom_rev) |
304 # print "Deleted/moved non-file:", revnum, path, ent |
267 |
305 # children = self._find_children(path, revnum - 1) |
268 fromrev = revnum - 1 |
306 # print "find children %s@%d from %d action %s" % (path, revnum, ent.copyfrom_rev, ent.action) |
269 # might always need to be revnum - 1 in these 3 lines? |
307 # Sometimes this is tricky. For example: in |
270 old_module = self.modulemap.get(fromrev, self.module) |
308 # The Subversion Repository revision 6940 a dir |
271 basepath = old_module + "/" + get_entry_from_path(path, module=self.module) |
309 # was copied and one of its files was deleted |
272 entrypath = old_module + "/" + get_entry_from_path(path, module=self.module) |
310 # from the new location in the same commit. This |
273 |
311 # code can't deal with that yet. |
274 def lookup_parts(p): |
312 if ent.action == 'C': |
275 rc = None |
313 children = self._find_children(path, fromrev) |
276 parts = p.split("/") |
|
277 for i in range(len(parts)): |
|
278 part = "/".join(parts[:i]) |
|
279 info = part, copyfrom.get(part, None) |
|
280 if info[1] is not None: |
|
281 self.ui.debug("Found parent directory %s\n" % info) |
|
282 rc = info |
|
283 return rc |
|
284 |
|
285 self.ui.debug("base, entry %s %s\n" % (basepath, entrypath)) |
|
286 |
|
287 frompath, froment = lookup_parts(entrypath) or (None, revnum - 1) |
|
288 |
|
289 # need to remove fragment from lookup_parts and replace with copyfrom_path |
|
290 if frompath is not None: |
|
291 self.ui.debug("munge-o-matic\n") |
|
292 self.ui.debug(entrypath + '\n') |
|
293 self.ui.debug(entrypath[len(frompath):] + '\n') |
|
294 entrypath = froment.copyfrom_path + entrypath[len(frompath):] |
|
295 fromrev = froment.copyfrom_rev |
|
296 self.ui.debug("Info: %s %s %s %s\n" % (frompath, froment, ent, entrypath)) |
|
297 |
|
298 fromkind = svn.ra.check_path(self.ra, entrypath, fromrev) |
|
299 if fromkind == svn.core.svn_node_file: # a deleted file |
|
300 entries.append(self.recode(entry)) |
|
301 else: |
314 else: |
302 # print "Deleted/moved non-file:", revnum, path, ent |
315 oroot = entrypath.strip('/') |
303 # children = self._find_children(path, revnum - 1) |
316 nroot = path.strip('/') |
304 # print "find children %s@%d from %d action %s" % (path, revnum, ent.copyfrom_rev, ent.action) |
317 children = self._find_children(oroot, fromrev) |
305 # Sometimes this is tricky. For example: in |
318 children = [s.replace(oroot,nroot) for s in children] |
306 # The Subversion Repository revision 6940 a dir |
319 # Mark all [files, not directories] as deleted. |
307 # was copied and one of its files was deleted |
|
308 # from the new location in the same commit. This |
|
309 # code can't deal with that yet. |
|
310 if ent.action == 'C': |
|
311 children = self._find_children(path, fromrev) |
|
312 else: |
|
313 oroot = entrypath.strip('/') |
|
314 nroot = path.strip('/') |
|
315 children = self._find_children(oroot, fromrev) |
|
316 children = [s.replace(oroot,nroot) for s in children] |
|
317 # Mark all [files, not directories] as deleted. |
|
318 for child in children: |
|
319 # Can we move a child directory and its |
|
320 # parent in the same commit? (probably can). Could |
|
321 # cause problems if instead of revnum -1, |
|
322 # we have to look in (copyfrom_path, revnum - 1) |
|
323 entrypath = get_entry_from_path("/" + child, module=old_module) |
|
324 if entrypath: |
|
325 entry = self.recode(entrypath.decode(self.encoding)) |
|
326 if entry in copies: |
|
327 # deleted file within a copy |
|
328 del copies[entry] |
|
329 else: |
|
330 entries.append(entry) |
|
331 elif kind == svn.core.svn_node_dir: |
|
332 # Should probably synthesize normal file entries |
|
333 # and handle as above to clean up copy/rename handling. |
|
334 |
|
335 # If the directory just had a prop change, |
|
336 # then we shouldn't need to look for its children. |
|
337 # Also this could create duplicate entries. Not sure |
|
338 # whether this will matter. Maybe should make entries a set. |
|
339 # print "Changed directory", revnum, path, ent.action, ent.copyfrom_path, ent.copyfrom_rev |
|
340 # This will fail if a directory was copied |
|
341 # from another branch and then some of its files |
|
342 # were deleted in the same transaction. |
|
343 children = self._find_children(path, revnum) |
|
344 children.sort() |
|
345 for child in children: |
320 for child in children: |
346 # Can we move a child directory and its |
321 # Can we move a child directory and its |
347 # parent in the same commit? (probably can). Could |
322 # parent in the same commit? (probably can). Could |
348 # cause problems if instead of revnum -1, |
323 # cause problems if instead of revnum -1, |
349 # we have to look in (copyfrom_path, revnum - 1) |
324 # we have to look in (copyfrom_path, revnum - 1) |
350 entrypath = get_entry_from_path("/" + child, module=self.module) |
325 entrypath = get_entry_from_path("/" + child, module=old_module) |
351 # print child, self.module, entrypath |
|
352 if entrypath: |
326 if entrypath: |
353 # Need to filter out directories here... |
327 entry = self.recode(entrypath.decode(self.encoding)) |
354 kind = svn.ra.check_path(self.ra, entrypath, revnum) |
328 if entry in copies: |
355 if kind != svn.core.svn_node_dir: |
329 # deleted file within a copy |
356 entries.append(self.recode(entrypath)) |
330 del copies[entry] |
357 |
331 else: |
358 # Copies here (must copy all from source) |
332 entries.append(entry) |
359 # Probably not a real problem for us if |
333 elif kind == svn.core.svn_node_dir: |
360 # source does not exist |
334 # Should probably synthesize normal file entries |
361 |
335 # and handle as above to clean up copy/rename handling. |
362 # Can do this with the copy command "hg copy" |
336 |
363 # if ent.copyfrom_path: |
337 # If the directory just had a prop change, |
364 # copyfrom_entry = get_entry_from_path(ent.copyfrom_path.decode(self.encoding), |
338 # then we shouldn't need to look for its children. |
365 # module=self.module) |
339 # Also this could create duplicate entries. Not sure |
366 # copyto_entry = entrypath |
340 # whether this will matter. Maybe should make entries a set. |
367 # |
341 # print "Changed directory", revnum, path, ent.action, ent.copyfrom_path, ent.copyfrom_rev |
368 # print "copy directory", copyfrom_entry, 'to', copyto_entry |
342 # This will fail if a directory was copied |
369 # |
343 # from another branch and then some of its files |
370 # copies.append((copyfrom_entry, copyto_entry)) |
344 # were deleted in the same transaction. |
371 |
345 children = self._find_children(path, revnum) |
372 if ent.copyfrom_path: |
346 children.sort() |
373 copyfrom_path = ent.copyfrom_path.decode(self.encoding) |
347 for child in children: |
374 copyfrom_entry = get_entry_from_path(copyfrom_path, module=self.module) |
348 # Can we move a child directory and its |
375 if copyfrom_entry: |
349 # parent in the same commit? (probably can). Could |
376 copyfrom[path] = ent |
350 # cause problems if instead of revnum -1, |
377 self.ui.debug("mark %s came from %s\n" % (path, copyfrom[path])) |
351 # we have to look in (copyfrom_path, revnum - 1) |
378 |
352 entrypath = get_entry_from_path("/" + child, module=self.module) |
379 # Good, /probably/ a regular copy. Really should check |
353 # print child, self.module, entrypath |
380 # to see whether the parent revision actually contains |
354 if entrypath: |
381 # the directory in question. |
355 # Need to filter out directories here... |
382 children = self._find_children(self.recode(copyfrom_path), ent.copyfrom_rev) |
356 kind = svn.ra.check_path(self.ra, entrypath, revnum) |
383 children.sort() |
357 if kind != svn.core.svn_node_dir: |
384 for child in children: |
358 entries.append(self.recode(entrypath)) |
385 entrypath = get_entry_from_path("/" + child, module=self.module) |
359 |
386 if entrypath: |
360 # Copies here (must copy all from source) |
387 entry = entrypath.decode(self.encoding) |
361 # Probably not a real problem for us if |
388 # print "COPY COPY From", copyfrom_entry, entry |
362 # source does not exist |
389 copyto_path = path + entry[len(copyfrom_entry):] |
363 |
390 copyto_entry = get_entry_from_path(copyto_path, module=self.module) |
364 # Can do this with the copy command "hg copy" |
391 # print "COPY", entry, "COPY To", copyto_entry |
365 # if ent.copyfrom_path: |
392 copies[self.recode(copyto_entry)] = self.recode(entry) |
366 # copyfrom_entry = get_entry_from_path(ent.copyfrom_path.decode(self.encoding), |
393 # copy from quux splort/quuxfile |
367 # module=self.module) |
394 |
368 # copyto_entry = entrypath |
395 self.modulemap[revnum] = self.module # track backwards in time |
369 # |
396 # a list of (filename, id) where id lets us retrieve the file. |
370 # print "copy directory", copyfrom_entry, 'to', copyto_entry |
397 # eg in git, id is the object hash. for svn it'll be the |
371 # |
398 self.files[rev] = zip(entries, [rev] * len(entries)) |
372 # copies.append((copyfrom_entry, copyto_entry)) |
399 if not entries: |
373 |
400 return |
374 if ent.copyfrom_path: |
401 |
375 copyfrom_path = ent.copyfrom_path.decode(self.encoding) |
402 # Example SVN datetime. Includes microseconds. |
376 copyfrom_entry = get_entry_from_path(copyfrom_path, module=self.module) |
403 # ISO-8601 conformant |
377 if copyfrom_entry: |
404 # '2007-01-04T17:35:00.902377Z' |
378 copyfrom[path] = ent |
405 date = util.parsedate(date[:18] + " UTC", ["%Y-%m-%dT%H:%M:%S"]) |
379 self.ui.debug("mark %s came from %s\n" % (path, copyfrom[path])) |
406 |
380 |
407 log = message and self.recode(message) |
381 # Good, /probably/ a regular copy. Really should check |
408 author = author and self.recode(author) or '' |
382 # to see whether the parent revision actually contains |
409 |
383 # the directory in question. |
410 cset = commit(author=author, |
384 children = self._find_children(self.recode(copyfrom_path), ent.copyfrom_rev) |
411 date=util.datestr(date), |
385 children.sort() |
412 desc=log, |
386 for child in children: |
413 parents=[], |
387 entrypath = get_entry_from_path("/" + child, module=self.module) |
414 copies=copies, |
388 if entrypath: |
415 branch=branch) |
389 entry = entrypath.decode(self.encoding) |
416 |
390 # print "COPY COPY From", copyfrom_entry, entry |
417 if self.child_cset and self.child_rev != rev: |
391 copyto_path = path + entry[len(copyfrom_entry):] |
418 self.child_cset.parents = [rev] |
392 copyto_entry = get_entry_from_path(copyto_path, module=self.module) |
419 self.commits[self.child_rev] = self.child_cset |
393 # print "COPY", entry, "COPY To", copyto_entry |
420 self.child_cset = cset |
394 copies[self.recode(copyto_entry)] = self.recode(entry) |
421 self.child_rev = rev |
395 # copy from quux splort/quuxfile |
|
396 |
|
397 self.modulemap[revnum] = self.module # track backwards in time |
|
398 # a list of (filename, id) where id lets us retrieve the file. |
|
399 # eg in git, id is the object hash. for svn it'll be the |
|
400 self.files[rev] = zip(entries, [rev] * len(entries)) |
|
401 if not entries: |
|
402 return |
|
403 |
|
404 # Example SVN datetime. Includes microseconds. |
|
405 # ISO-8601 conformant |
|
406 # '2007-01-04T17:35:00.902377Z' |
|
407 date = util.parsedate(date[:18] + " UTC", ["%Y-%m-%dT%H:%M:%S"]) |
|
408 |
|
409 log = message and self.recode(message) |
|
410 author = author and self.recode(author) or '' |
|
411 |
|
412 cset = commit(author=author, |
|
413 date=util.datestr(date), |
|
414 desc=log, |
|
415 parents=[], |
|
416 copies=copies, |
|
417 branch=branch) |
|
418 |
|
419 if self.child_cset and self.child_rev != rev: |
|
420 self.child_cset.parents = [rev] |
|
421 self.commits[self.child_rev] = self.child_cset |
|
422 self.child_cset = cset |
|
423 self.child_rev = rev |
422 |
424 |
423 try: |
425 try: |
424 discover_changed_paths = True |
426 discover_changed_paths = True |
425 strict_node_history = False |
427 strict_node_history = False |
426 svn.ra.get_log(self.ra, [self.module], from_revnum, to_revnum, |
428 svn.ra.get_log(self.ra, [self.module], from_revnum, to_revnum, |