##// END OF EJS Templates
convert: option to set date and time for svn commits...
Nikita Slyusarev -
r47129:7525e77b default
parent child Browse files
Show More
@@ -491,6 +491,22 b' def convert(ui, src, dest=None, revmapfi'
491
491
492 :convert.skiptags: does not convert tags from the source repo to the target
492 :convert.skiptags: does not convert tags from the source repo to the target
493 repo. The default is False.
493 repo. The default is False.
494
495 Subversion Destination
496 ######################
497
498 Original commit dates are not preserved by default.
499
500 :convert.svn.dangerous-set-commit-dates: preserve original commit dates,
501 forcefully setting ``svn:date`` revision properties. This option is
502 DANGEROUS and may break some subversion functionality for the resulting
503 repository (e.g. filtering revisions with date ranges in ``svn log``),
504 as original commit dates are not guaranteed to be monotonically
505 increasing.
506
507 For commit dates setting to work destination repository must have
508 ``pre-revprop-change`` hook configured to allow setting of ``svn:date``
509 revision properties. See Subversion documentation for more details.
494 """
510 """
495 return convcmd.convert(ui, src, dest, revmapfile, **opts)
511 return convcmd.convert(ui, src, dest, revmapfile, **opts)
496
512
@@ -97,6 +97,17 b' def fs2svn(s):'
97 return s.decode(fsencoding).encode('utf-8')
97 return s.decode(fsencoding).encode('utf-8')
98
98
99
99
100 def formatsvndate(date):
101 return dateutil.datestr(date, b'%Y-%m-%dT%H:%M:%S.000000Z')
102
103
104 def parsesvndate(s):
105 # Example SVN datetime. Includes microseconds.
106 # ISO-8601 conformant
107 # '2007-01-04T17:35:00.902377Z'
108 return dateutil.parsedate(s[:19] + b' UTC', [b'%Y-%m-%dT%H:%M:%S'])
109
110
100 class SvnPathNotFound(Exception):
111 class SvnPathNotFound(Exception):
101 pass
112 pass
102
113
@@ -1158,12 +1169,7 b' class svn_source(converter_source):'
1158 continue
1169 continue
1159 paths.append((path, ent))
1170 paths.append((path, ent))
1160
1171
1161 # Example SVN datetime. Includes microseconds.
1172 date = parsesvndate(date)
1162 # ISO-8601 conformant
1163 # '2007-01-04T17:35:00.902377Z'
1164 date = dateutil.parsedate(
1165 date[:19] + b" UTC", [b"%Y-%m-%dT%H:%M:%S"]
1166 )
1167 if self.ui.configbool(b'convert', b'localtimezone'):
1173 if self.ui.configbool(b'convert', b'localtimezone'):
1168 date = makedatetimestamp(date[0])
1174 date = makedatetimestamp(date[0])
1169
1175
@@ -1380,7 +1386,7 b' class svn_source(converter_source):'
1380 return logstream(stdout)
1386 return logstream(stdout)
1381
1387
1382
1388
1383 pre_revprop_change = b'''#!/bin/sh
1389 pre_revprop_change_template = b'''#!/bin/sh
1384
1390
1385 REPOS="$1"
1391 REPOS="$1"
1386 REV="$2"
1392 REV="$2"
@@ -1388,15 +1394,26 b' USER="$3"'
1388 PROPNAME="$4"
1394 PROPNAME="$4"
1389 ACTION="$5"
1395 ACTION="$5"
1390
1396
1391 if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
1397 %(rules)s
1392 if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-branch" ]; then exit 0; fi
1393 if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-rev" ]; then exit 0; fi
1394
1398
1395 echo "Changing prohibited revision property" >&2
1399 echo "Changing prohibited revision property" >&2
1396 exit 1
1400 exit 1
1397 '''
1401 '''
1398
1402
1399
1403
1404 def gen_pre_revprop_change_hook(prop_actions_allowed):
1405 rules = []
1406 for action, propname in prop_actions_allowed:
1407 rules.append(
1408 (
1409 b'if [ "$ACTION" = "%s" -a "$PROPNAME" = "%s" ]; '
1410 b'then exit 0; fi'
1411 )
1412 % (action, propname)
1413 )
1414 return pre_revprop_change_template % {b'rules': b'\n'.join(rules)}
1415
1416
1400 class svn_sink(converter_sink, commandline):
1417 class svn_sink(converter_sink, commandline):
1401 commit_re = re.compile(br'Committed revision (\d+).', re.M)
1418 commit_re = re.compile(br'Committed revision (\d+).', re.M)
1402 uuid_re = re.compile(br'Repository UUID:\s*(\S+)', re.M)
1419 uuid_re = re.compile(br'Repository UUID:\s*(\S+)', re.M)
@@ -1470,9 +1487,20 b' class svn_sink(converter_sink, commandli'
1470 self.is_exec = None
1487 self.is_exec = None
1471
1488
1472 if created:
1489 if created:
1490 prop_actions_allowed = [
1491 (b'M', b'svn:log'),
1492 (b'A', b'hg:convert-branch'),
1493 (b'A', b'hg:convert-rev'),
1494 ]
1495
1496 if self.ui.configbool(
1497 b'convert', b'svn.dangerous-set-commit-dates'
1498 ):
1499 prop_actions_allowed.append((b'M', b'svn:date'))
1500
1473 hook = os.path.join(created, b'hooks', b'pre-revprop-change')
1501 hook = os.path.join(created, b'hooks', b'pre-revprop-change')
1474 fp = open(hook, b'wb')
1502 fp = open(hook, b'wb')
1475 fp.write(pre_revprop_change)
1503 fp.write(gen_pre_revprop_change_hook(prop_actions_allowed))
1476 fp.close()
1504 fp.close()
1477 util.setflags(hook, False, True)
1505 util.setflags(hook, False, True)
1478
1506
@@ -1667,6 +1695,23 b' class svn_sink(converter_sink, commandli'
1667 revprop=True,
1695 revprop=True,
1668 revision=rev,
1696 revision=rev,
1669 )
1697 )
1698
1699 if self.ui.configbool(
1700 b'convert', b'svn.dangerous-set-commit-dates'
1701 ):
1702 # Subverson always uses UTC to represent date and time
1703 date = dateutil.parsedate(commit.date)
1704 date = (date[0], 0)
1705
1706 # The only way to set date and time for svn commit is to use propset after commit is done
1707 self.run(
1708 b'propset',
1709 b'svn:date',
1710 formatsvndate(date),
1711 revprop=True,
1712 revision=rev,
1713 )
1714
1670 for parent in parents:
1715 for parent in parents:
1671 self.addchild(parent, rev)
1716 self.addchild(parent, rev)
1672 return self.revid(rev)
1717 return self.revid(rev)
@@ -570,6 +570,11 b' coreconfigitem('
570 default=0,
570 default=0,
571 )
571 )
572 coreconfigitem(
572 coreconfigitem(
573 b'convert',
574 b'svn.dangerous-set-commit-dates',
575 default=False,
576 )
577 coreconfigitem(
573 b'debug',
578 b'debug',
574 b'dirstate.delaywrite',
579 b'dirstate.delaywrite',
575 default=0,
580 default=0,
@@ -15,6 +15,7 b' def parseentry(entry):'
15 e['revision'] = entry.getAttribute('revision')
15 e['revision'] = entry.getAttribute('revision')
16 e['author'] = xmltext(entry.getElementsByTagName('author')[0])
16 e['author'] = xmltext(entry.getElementsByTagName('author')[0])
17 e['msg'] = xmltext(entry.getElementsByTagName('msg')[0])
17 e['msg'] = xmltext(entry.getElementsByTagName('msg')[0])
18 e['date'] = xmltext(entry.getElementsByTagName('date')[0])
18 e['paths'] = []
19 e['paths'] = []
19 paths = entry.getElementsByTagName('paths')
20 paths = entry.getElementsByTagName('paths')
20 if paths:
21 if paths:
@@ -42,7 +43,7 b' def printentries(entries):'
42 except AttributeError:
43 except AttributeError:
43 fp = sys.stdout
44 fp = sys.stdout
44 for e in entries:
45 for e in entries:
45 for k in ('revision', 'author', 'msg'):
46 for k in ('revision', 'author', 'date', 'msg'):
46 fp.write(('%s: %s\n' % (k, e[k])).encode('utf-8'))
47 fp.write(('%s: %s\n' % (k, e[k])).encode('utf-8'))
47 for path, action, fpath, frev in sorted(e['paths']):
48 for path, action, fpath, frev in sorted(e['paths']):
48 frominfo = b''
49 frominfo = b''
@@ -54,10 +54,12 b' Modify'
54 2 2 test a
54 2 2 test a
55 revision: 2
55 revision: 2
56 author: test
56 author: test
57 date: * (glob)
57 msg: modify a file
58 msg: modify a file
58 M /a
59 M /a
59 revision: 1
60 revision: 1
60 author: test
61 author: test
62 date: * (glob)
61 msg: add a file
63 msg: add a file
62 A /a
64 A /a
63 A /d1
65 A /d1
@@ -95,6 +97,7 b' Rename'
95 3 3 test b
97 3 3 test b
96 revision: 3
98 revision: 3
97 author: test
99 author: test
100 date: * (glob)
98 msg: rename a file
101 msg: rename a file
99 D /a
102 D /a
100 A /b (from /a@2)
103 A /b (from /a@2)
@@ -131,6 +134,7 b' Copy'
131 4 4 test c
134 4 4 test c
132 revision: 4
135 revision: 4
133 author: test
136 author: test
137 date: * (glob)
134 msg: copy a file
138 msg: copy a file
135 A /c (from /b@3)
139 A /c (from /b@3)
136 $ ls a a-hg-wc
140 $ ls a a-hg-wc
@@ -167,6 +171,7 b' Remove'
167 5 5 test .
171 5 5 test .
168 revision: 5
172 revision: 5
169 author: test
173 author: test
174 date: * (glob)
170 msg: remove a file
175 msg: remove a file
171 D /b
176 D /b
172 $ ls a a-hg-wc
177 $ ls a a-hg-wc
@@ -209,6 +214,7 b' Executable'
209 6 6 test c
214 6 6 test c
210 revision: 6
215 revision: 6
211 author: test
216 author: test
217 date: * (glob)
212 msg: make a file executable
218 msg: make a file executable
213 M /c
219 M /c
214 #if execbit
220 #if execbit
@@ -247,6 +253,7 b' Symlinks'
247 8 8 test newlink
253 8 8 test newlink
248 revision: 8
254 revision: 8
249 author: test
255 author: test
256 date: * (glob)
250 msg: move symlink
257 msg: move symlink
251 D /link
258 D /link
252 A /newlink (from /link@7)
259 A /newlink (from /link@7)
@@ -278,6 +285,7 b' Convert with --full adds and removes fil'
278 7 7 test f
285 7 7 test f
279 revision: 7
286 revision: 7
280 author: test
287 author: test
288 date: * (glob)
281 msg: f
289 msg: f
282 D /c
290 D /c
283 A /d
291 A /d
@@ -315,6 +323,7 b' Executable in new directory'
315 1 1 test d1/a
323 1 1 test d1/a
316 revision: 1
324 revision: 1
317 author: test
325 author: test
326 date: * (glob)
318 msg: add executable file in new directory
327 msg: add executable file in new directory
319 A /d1
328 A /d1
320 A /d1/a
329 A /d1/a
@@ -343,6 +352,7 b' Copy to new directory'
343 2 2 test d2/a
352 2 2 test d2/a
344 revision: 2
353 revision: 2
345 author: test
354 author: test
355 date: * (glob)
346 msg: copy file to new directory
356 msg: copy file to new directory
347 A /d2
357 A /d2
348 A /d2/a (from /d1/a@1)
358 A /d2/a (from /d1/a@1)
@@ -416,21 +426,25 b' Expect 4 changes'
416 4 4 test right-2
426 4 4 test right-2
417 revision: 4
427 revision: 4
418 author: test
428 author: test
429 date: * (glob)
419 msg: merge
430 msg: merge
420 A /right-1
431 A /right-1
421 A /right-2
432 A /right-2
422 revision: 3
433 revision: 3
423 author: test
434 author: test
435 date: * (glob)
424 msg: left-2
436 msg: left-2
425 M /b
437 M /b
426 A /left-2
438 A /left-2
427 revision: 2
439 revision: 2
428 author: test
440 author: test
441 date: * (glob)
429 msg: left-1
442 msg: left-1
430 M /b
443 M /b
431 A /left-1
444 A /left-1
432 revision: 1
445 revision: 1
433 author: test
446 author: test
447 date: * (glob)
434 msg: base
448 msg: base
435 A /b
449 A /b
436
450
@@ -459,10 +473,12 b' Tags are not supported, but must not bre'
459 2 2 test .hgtags
473 2 2 test .hgtags
460 revision: 2
474 revision: 2
461 author: test
475 author: test
476 date: * (glob)
462 msg: Tagged as v1.0
477 msg: Tagged as v1.0
463 A /.hgtags
478 A /.hgtags
464 revision: 1
479 revision: 1
465 author: test
480 author: test
481 date: * (glob)
466 msg: Add file a
482 msg: Add file a
467 A /a
483 A /a
468 $ rm -rf a a-hg a-hg-wc
484 $ rm -rf a a-hg a-hg-wc
@@ -494,10 +510,12 b' Executable bit removal'
494 2 2 test exec
510 2 2 test exec
495 revision: 2
511 revision: 2
496 author: test
512 author: test
513 date: * (glob)
497 msg: remove executable bit
514 msg: remove executable bit
498 M /exec
515 M /exec
499 revision: 1
516 revision: 1
500 author: test
517 author: test
518 date: * (glob)
501 msg: create executable
519 msg: create executable
502 A /exec
520 A /exec
503 $ test ! -x a-hg-wc/exec
521 $ test ! -x a-hg-wc/exec
@@ -540,11 +558,77 b' Skipping empty commits'
540 2 2 test b
558 2 2 test b
541 revision: 2
559 revision: 2
542 author: test
560 author: test
561 date: * (glob)
543 msg: Another change
562 msg: Another change
544 A /b
563 A /b
545 revision: 1
564 revision: 1
546 author: test
565 author: test
566 date: * (glob)
547 msg: Some change
567 msg: Some change
548 A /a
568 A /a
549
569
550 $ rm -rf a a-hg a-hg-wc
570 $ rm -rf a a-hg a-hg-wc
571
572 Commit dates convertion
573
574 $ hg init a
575
576 $ echo a >> a/a
577 $ hg add a
578 adding a/a
579 $ hg --cwd a ci -d '1 0' -A -m 'Change 1'
580
581 $ echo a >> a/a
582 $ hg --cwd a ci -d '2 0' -m 'Change 2'
583
584 $ echo a >> a/a
585 $ hg --cwd a ci -d '2 0' -m 'Change at the same time'
586
587 $ echo a >> a/a
588 $ hg --cwd a ci -d '1 0' -m 'Change in the past'
589
590 $ echo a >> a/a
591 $ hg --cwd a ci -d '3 0' -m 'Change in the future'
592
593 $ hg convert --config convert.svn.dangerous-set-commit-dates=true -d svn a
594 assuming destination a-hg
595 initializing svn repository 'a-hg'
596 initializing svn working copy 'a-hg-wc'
597 scanning source...
598 sorting...
599 converting...
600 4 Change 1
601 3 Change 2
602 2 Change at the same time
603 1 Change in the past
604 0 Change in the future
605 $ svnupanddisplay a-hg-wc 0
606 5 5 test .
607 5 5 test a
608 revision: 5
609 author: test
610 date: 1970-01-01T00:00:03.000000Z
611 msg: Change in the future
612 M /a
613 revision: 4
614 author: test
615 date: 1970-01-01T00:00:01.000000Z
616 msg: Change in the past
617 M /a
618 revision: 3
619 author: test
620 date: 1970-01-01T00:00:02.000000Z
621 msg: Change at the same time
622 M /a
623 revision: 2
624 author: test
625 date: 1970-01-01T00:00:02.000000Z
626 msg: Change 2
627 M /a
628 revision: 1
629 author: test
630 date: 1970-01-01T00:00:01.000000Z
631 msg: Change 1
632 A /a
633
634 $ rm -rf a a-hg a-hg-wc
@@ -388,6 +388,23 b''
388 does not convert tags from the source repo to the target
388 does not convert tags from the source repo to the target
389 repo. The default is False.
389 repo. The default is False.
390
390
391 Subversion Destination
392 ######################
393
394 Original commit dates are not preserved by default.
395
396 convert.svn.dangerous-set-commit-dates
397 preserve original commit dates, forcefully setting
398 "svn:date" revision properties. This option is DANGEROUS and
399 may break some subversion functionality for the resulting
400 repository (e.g. filtering revisions with date ranges in
401 "svn log"), as original commit dates are not guaranteed to
402 be monotonically increasing.
403
404 For commit dates setting to work destination repository must have "pre-
405 revprop-change" hook configured to allow setting of "svn:date" revision
406 properties. See Subversion documentation for more details.
407
391 options ([+] can be repeated):
408 options ([+] can be repeated):
392
409
393 -s --source-type TYPE source repository type
410 -s --source-type TYPE source repository type
General Comments 0
You need to be logged in to leave comments. Login now