Skip to content
Snippets Groups Projects
Commit 7525e77b5eac authored by Nikita Slyusarev's avatar Nikita Slyusarev :construction_worker_tone2:
Browse files

convert: option to set date and time for svn commits

Converting to subversion repository is not preserving original commit dates as
it may break some subversion functionality if commit dates are not monotonically
increasing.

This patch adds `convert.svn.dangerous-set-commit-dates` configuration option
to change this behaviour and enable commit dates convertion for those who want
to take risks.

Subversion always uses commit dates with UTC timezone, so only timestamps
are used.

Test `test-convert-svn-sink.t` uses `svnxml.py` script to dump history of svn
repositories. Atm the script is not printing `date` field from svn log. This
patch changes this to allow checks on correctness of date and time convertion.

Documentation is updated. Additional test case is added to test commit dates
convertion.

Differential Revision: https://phab.mercurial-scm.org/D9721
parent 1d6d1a15a963
No related branches found
No related tags found
1 merge request!72ci: hook network-io tests into the pipeline
......@@ -491,6 +491,22 @@
:convert.skiptags: does not convert tags from the source repo to the target
repo. The default is False.
Subversion Destination
######################
Original commit dates are not preserved by default.
:convert.svn.dangerous-set-commit-dates: preserve original commit dates,
forcefully setting ``svn:date`` revision properties. This option is
DANGEROUS and may break some subversion functionality for the resulting
repository (e.g. filtering revisions with date ranges in ``svn log``),
as original commit dates are not guaranteed to be monotonically
increasing.
For commit dates setting to work destination repository must have
``pre-revprop-change`` hook configured to allow setting of ``svn:date``
revision properties. See Subversion documentation for more details.
"""
return convcmd.convert(ui, src, dest, revmapfile, **opts)
......
......@@ -97,6 +97,17 @@
return s.decode(fsencoding).encode('utf-8')
def formatsvndate(date):
return dateutil.datestr(date, b'%Y-%m-%dT%H:%M:%S.000000Z')
def parsesvndate(s):
# Example SVN datetime. Includes microseconds.
# ISO-8601 conformant
# '2007-01-04T17:35:00.902377Z'
return dateutil.parsedate(s[:19] + b' UTC', [b'%Y-%m-%dT%H:%M:%S'])
class SvnPathNotFound(Exception):
pass
......@@ -1158,12 +1169,7 @@
continue
paths.append((path, ent))
# Example SVN datetime. Includes microseconds.
# ISO-8601 conformant
# '2007-01-04T17:35:00.902377Z'
date = dateutil.parsedate(
date[:19] + b" UTC", [b"%Y-%m-%dT%H:%M:%S"]
)
date = parsesvndate(date)
if self.ui.configbool(b'convert', b'localtimezone'):
date = makedatetimestamp(date[0])
......@@ -1380,7 +1386,7 @@
return logstream(stdout)
pre_revprop_change = b'''#!/bin/sh
pre_revprop_change_template = b'''#!/bin/sh
REPOS="$1"
REV="$2"
......@@ -1388,12 +1394,10 @@
PROPNAME="$4"
ACTION="$5"
if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-branch" ]; then exit 0; fi
if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-rev" ]; then exit 0; fi
%(rules)s
echo "Changing prohibited revision property" >&2
exit 1
'''
......@@ -1394,9 +1398,22 @@
echo "Changing prohibited revision property" >&2
exit 1
'''
def gen_pre_revprop_change_hook(prop_actions_allowed):
rules = []
for action, propname in prop_actions_allowed:
rules.append(
(
b'if [ "$ACTION" = "%s" -a "$PROPNAME" = "%s" ]; '
b'then exit 0; fi'
)
% (action, propname)
)
return pre_revprop_change_template % {b'rules': b'\n'.join(rules)}
class svn_sink(converter_sink, commandline):
commit_re = re.compile(br'Committed revision (\d+).', re.M)
uuid_re = re.compile(br'Repository UUID:\s*(\S+)', re.M)
......@@ -1470,5 +1487,16 @@
self.is_exec = None
if created:
prop_actions_allowed = [
(b'M', b'svn:log'),
(b'A', b'hg:convert-branch'),
(b'A', b'hg:convert-rev'),
]
if self.ui.configbool(
b'convert', b'svn.dangerous-set-commit-dates'
):
prop_actions_allowed.append((b'M', b'svn:date'))
hook = os.path.join(created, b'hooks', b'pre-revprop-change')
fp = open(hook, b'wb')
......@@ -1473,6 +1501,6 @@
hook = os.path.join(created, b'hooks', b'pre-revprop-change')
fp = open(hook, b'wb')
fp.write(pre_revprop_change)
fp.write(gen_pre_revprop_change_hook(prop_actions_allowed))
fp.close()
util.setflags(hook, False, True)
......@@ -1667,6 +1695,23 @@
revprop=True,
revision=rev,
)
if self.ui.configbool(
b'convert', b'svn.dangerous-set-commit-dates'
):
# Subverson always uses UTC to represent date and time
date = dateutil.parsedate(commit.date)
date = (date[0], 0)
# The only way to set date and time for svn commit is to use propset after commit is done
self.run(
b'propset',
b'svn:date',
formatsvndate(date),
revprop=True,
revision=rev,
)
for parent in parents:
self.addchild(parent, rev)
return self.revid(rev)
......
......@@ -570,6 +570,11 @@
default=0,
)
coreconfigitem(
b'convert',
b'svn.dangerous-set-commit-dates',
default=False,
)
coreconfigitem(
b'debug',
b'dirstate.delaywrite',
default=0,
......
......@@ -15,6 +15,7 @@
e['revision'] = entry.getAttribute('revision')
e['author'] = xmltext(entry.getElementsByTagName('author')[0])
e['msg'] = xmltext(entry.getElementsByTagName('msg')[0])
e['date'] = xmltext(entry.getElementsByTagName('date')[0])
e['paths'] = []
paths = entry.getElementsByTagName('paths')
if paths:
......@@ -42,7 +43,7 @@
except AttributeError:
fp = sys.stdout
for e in entries:
for k in ('revision', 'author', 'msg'):
for k in ('revision', 'author', 'date', 'msg'):
fp.write(('%s: %s\n' % (k, e[k])).encode('utf-8'))
for path, action, fpath, frev in sorted(e['paths']):
frominfo = b''
......
......@@ -54,7 +54,8 @@
2 2 test a
revision: 2
author: test
date: * (glob)
msg: modify a file
M /a
revision: 1
author: test
......@@ -57,7 +58,8 @@
msg: modify a file
M /a
revision: 1
author: test
date: * (glob)
msg: add a file
A /a
A /d1
......@@ -95,6 +97,7 @@
3 3 test b
revision: 3
author: test
date: * (glob)
msg: rename a file
D /a
A /b (from /a@2)
......@@ -131,6 +134,7 @@
4 4 test c
revision: 4
author: test
date: * (glob)
msg: copy a file
A /c (from /b@3)
$ ls a a-hg-wc
......@@ -167,6 +171,7 @@
5 5 test .
revision: 5
author: test
date: * (glob)
msg: remove a file
D /b
$ ls a a-hg-wc
......@@ -209,6 +214,7 @@
6 6 test c
revision: 6
author: test
date: * (glob)
msg: make a file executable
M /c
#if execbit
......@@ -247,6 +253,7 @@
8 8 test newlink
revision: 8
author: test
date: * (glob)
msg: move symlink
D /link
A /newlink (from /link@7)
......@@ -278,6 +285,7 @@
7 7 test f
revision: 7
author: test
date: * (glob)
msg: f
D /c
A /d
......@@ -315,6 +323,7 @@
1 1 test d1/a
revision: 1
author: test
date: * (glob)
msg: add executable file in new directory
A /d1
A /d1/a
......@@ -343,6 +352,7 @@
2 2 test d2/a
revision: 2
author: test
date: * (glob)
msg: copy file to new directory
A /d2
A /d2/a (from /d1/a@1)
......@@ -416,8 +426,9 @@
4 4 test right-2
revision: 4
author: test
date: * (glob)
msg: merge
A /right-1
A /right-2
revision: 3
author: test
......@@ -419,10 +430,11 @@
msg: merge
A /right-1
A /right-2
revision: 3
author: test
date: * (glob)
msg: left-2
M /b
A /left-2
revision: 2
author: test
......@@ -424,10 +436,11 @@
msg: left-2
M /b
A /left-2
revision: 2
author: test
date: * (glob)
msg: left-1
M /b
A /left-1
revision: 1
author: test
......@@ -429,8 +442,9 @@
msg: left-1
M /b
A /left-1
revision: 1
author: test
date: * (glob)
msg: base
A /b
......@@ -459,7 +473,8 @@
2 2 test .hgtags
revision: 2
author: test
date: * (glob)
msg: Tagged as v1.0
A /.hgtags
revision: 1
author: test
......@@ -462,7 +477,8 @@
msg: Tagged as v1.0
A /.hgtags
revision: 1
author: test
date: * (glob)
msg: Add file a
A /a
$ rm -rf a a-hg a-hg-wc
......@@ -494,7 +510,8 @@
2 2 test exec
revision: 2
author: test
date: * (glob)
msg: remove executable bit
M /exec
revision: 1
author: test
......@@ -497,7 +514,8 @@
msg: remove executable bit
M /exec
revision: 1
author: test
date: * (glob)
msg: create executable
A /exec
$ test ! -x a-hg-wc/exec
......@@ -540,7 +558,8 @@
2 2 test b
revision: 2
author: test
date: * (glob)
msg: Another change
A /b
revision: 1
author: test
......@@ -543,8 +562,9 @@
msg: Another change
A /b
revision: 1
author: test
date: * (glob)
msg: Some change
A /a
$ rm -rf a a-hg a-hg-wc
......@@ -547,4 +567,68 @@
msg: Some change
A /a
$ rm -rf a a-hg a-hg-wc
Commit dates convertion
$ hg init a
$ echo a >> a/a
$ hg add a
adding a/a
$ hg --cwd a ci -d '1 0' -A -m 'Change 1'
$ echo a >> a/a
$ hg --cwd a ci -d '2 0' -m 'Change 2'
$ echo a >> a/a
$ hg --cwd a ci -d '2 0' -m 'Change at the same time'
$ echo a >> a/a
$ hg --cwd a ci -d '1 0' -m 'Change in the past'
$ echo a >> a/a
$ hg --cwd a ci -d '3 0' -m 'Change in the future'
$ hg convert --config convert.svn.dangerous-set-commit-dates=true -d svn a
assuming destination a-hg
initializing svn repository 'a-hg'
initializing svn working copy 'a-hg-wc'
scanning source...
sorting...
converting...
4 Change 1
3 Change 2
2 Change at the same time
1 Change in the past
0 Change in the future
$ svnupanddisplay a-hg-wc 0
5 5 test .
5 5 test a
revision: 5
author: test
date: 1970-01-01T00:00:03.000000Z
msg: Change in the future
M /a
revision: 4
author: test
date: 1970-01-01T00:00:01.000000Z
msg: Change in the past
M /a
revision: 3
author: test
date: 1970-01-01T00:00:02.000000Z
msg: Change at the same time
M /a
revision: 2
author: test
date: 1970-01-01T00:00:02.000000Z
msg: Change 2
M /a
revision: 1
author: test
date: 1970-01-01T00:00:01.000000Z
msg: Change 1
A /a
$ rm -rf a a-hg a-hg-wc
......@@ -388,6 +388,23 @@
does not convert tags from the source repo to the target
repo. The default is False.
Subversion Destination
######################
Original commit dates are not preserved by default.
convert.svn.dangerous-set-commit-dates
preserve original commit dates, forcefully setting
"svn:date" revision properties. This option is DANGEROUS and
may break some subversion functionality for the resulting
repository (e.g. filtering revisions with date ranges in
"svn log"), as original commit dates are not guaranteed to
be monotonically increasing.
For commit dates setting to work destination repository must have "pre-
revprop-change" hook configured to allow setting of "svn:date" revision
properties. See Subversion documentation for more details.
options ([+] can be repeated):
-s --source-type TYPE source repository type
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment