D9721: convert: set date and time for svn commits
nslsrv (Nikita Slyusarev)
phabricator at mercurial-scm.org
Mon Jan 11 22:56:06 UTC 2021
nslsrv created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.
REVISION SUMMARY
Committing to subversion repository is changed to use commit dates from
the source. Subversion always uses commit dates with UTC timezone, so only
timestamps are used.
By default svn commit dates are kept monotonically increasing by replacing
locally decreasing date and time values. This behaviour is disabled using
`convert.svn.allowdecreasingdates` configuration option.
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.
Additional test cases are added to test commit dates autofixing.
REPOSITORY
rHG Mercurial
BRANCH
default
REVISION DETAIL
https://phab.mercurial-scm.org/D9721
AFFECTED FILES
hgext/convert/__init__.py
hgext/convert/subversion.py
mercurial/configitems.py
tests/svnxml.py
tests/test-convert-hg-svn.t
tests/test-convert-svn-sink.t
tests/test-convert.t
CHANGE DETAILS
diff --git a/tests/test-convert.t b/tests/test-convert.t
--- a/tests/test-convert.t
+++ b/tests/test-convert.t
@@ -388,6 +388,18 @@
does not convert tags from the source repo to the target
repo. The default is False.
+ Subversion Destination
+ ######################
+
+ Commit dates being converted to subversion destination are kept
+ monotonically increasing by default.
+
+ convert.svn.allowdecreasingdates
+ convert commit dates as is allowing svn commit dates to
+ decrease. This may break some subversion functionality when
+ using the resulting repository (e.g. filtering revisions by
+ using date ranges with "svn log").
+
options ([+] can be repeated):
-s --source-type TYPE source repository type
diff --git a/tests/test-convert-svn-sink.t b/tests/test-convert-svn-sink.t
--- a/tests/test-convert-svn-sink.t
+++ b/tests/test-convert-svn-sink.t
@@ -54,10 +54,12 @@
2 2 test a
revision: 2
author: test
+ date: 1970-01-01T00:00:01.000000Z
msg: modify a file
M /a
revision: 1
author: test
+ date: 1970-01-01T00:00:00.000000Z
msg: add a file
A /a
A /d1
@@ -95,6 +97,7 @@
3 3 test b
revision: 3
author: test
+ date: 1970-01-01T00:00:02.000000Z
msg: rename a file
D /a
A /b (from /a at 2)
@@ -131,6 +134,7 @@
4 4 test c
revision: 4
author: test
+ date: 1970-01-01T00:00:03.000000Z
msg: copy a file
A /c (from /b at 3)
$ ls a a-hg-wc
@@ -167,6 +171,7 @@
5 5 test .
revision: 5
author: test
+ date: 1970-01-01T00:00:04.000000Z
msg: remove a file
D /b
$ ls a a-hg-wc
@@ -209,6 +214,7 @@
6 6 test c
revision: 6
author: test
+ date: 1970-01-01T00:00:05.000000Z
msg: make a file executable
M /c
#if execbit
@@ -237,7 +243,9 @@
3 remove a file
2 make a file executable
1 add symlink
+ prevented svn commit date from decreasing for revision 7, used 1970-01-01T00:00:05.000000Z instead of 1970-01-01T00:00:00.000000Z
0 move symlink
+ prevented svn commit date from decreasing for revision 8, used 1970-01-01T00:00:05.000000Z instead of 1970-01-01T00:00:00.000000Z
$ svnupanddisplay a-svnlink-wc 1
8 1 test d1
8 1 test d1/d2
@@ -247,6 +255,7 @@
8 8 test newlink
revision: 8
author: test
+ date: 1970-01-01T00:00:05.000000Z
msg: move symlink
D /link
A /newlink (from /link at 7)
@@ -278,6 +287,7 @@
7 7 test f
revision: 7
author: test
+ date: 1970-01-01T00:00:00.000000Z
msg: f
D /c
A /d
@@ -315,6 +325,7 @@
1 1 test d1/a
revision: 1
author: test
+ date: 1970-01-01T00:00:00.000000Z
msg: add executable file in new directory
A /d1
A /d1/a
@@ -343,6 +354,7 @@
2 2 test d2/a
revision: 2
author: test
+ date: 1970-01-01T00:00:01.000000Z
msg: copy file to new directory
A /d2
A /d2/a (from /d1/a at 1)
@@ -416,21 +428,25 @@
4 4 test right-2
revision: 4
author: test
+ date: 1970-01-01T00:00:05.000000Z
msg: merge
A /right-1
A /right-2
revision: 3
author: test
+ date: 1970-01-01T00:00:02.000000Z
msg: left-2
M /b
A /left-2
revision: 2
author: test
+ date: 1970-01-01T00:00:01.000000Z
msg: left-1
M /b
A /left-1
revision: 1
author: test
+ date: 1970-01-01T00:00:00.000000Z
msg: base
A /b
@@ -459,10 +475,12 @@
2 2 test .hgtags
revision: 2
author: test
+ date: 1970-01-01T00:00:01.000000Z
msg: Tagged as v1.0
A /.hgtags
revision: 1
author: test
+ date: 1970-01-01T00:00:00.000000Z
msg: Add file a
A /a
$ rm -rf a a-hg a-hg-wc
@@ -494,10 +512,12 @@
2 2 test exec
revision: 2
author: test
+ date: 1970-01-01T00:00:02.000000Z
msg: remove executable bit
M /exec
revision: 1
author: test
+ date: 1970-01-01T00:00:01.000000Z
msg: create executable
A /exec
$ test ! -x a-hg-wc/exec
@@ -540,11 +560,122 @@
2 2 test b
revision: 2
author: test
+ date: 1970-01-01T00:00:00.000000Z
msg: Another change
A /b
revision: 1
author: test
+ date: 1970-01-01T00:00:00.000000Z
msg: Some change
A /a
$ rm -rf a a-hg a-hg-wc
+
+Commit dates autofixing
+
+ $ 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 -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
+ prevented svn commit date from decreasing for revision 4, used 1970-01-01T00:00:02.000000Z instead of 1970-01-01T00:00:01.000000Z
+ 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:02.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-hg a-hg-wc
+
+ $ hg convert --config convert.svn.allowdecreasingdates=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
diff --git a/tests/test-convert-hg-svn.t b/tests/test-convert-hg-svn.t
--- a/tests/test-convert-hg-svn.t
+++ b/tests/test-convert-hg-svn.t
@@ -24,6 +24,7 @@
> ACTION="$5"
>
> if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
+ > if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:date" ]; 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
>
diff --git a/tests/svnxml.py b/tests/svnxml.py
--- a/tests/svnxml.py
+++ b/tests/svnxml.py
@@ -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''
diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -570,6 +570,11 @@
default=0,
)
coreconfigitem(
+ b'convert',
+ b'svn.allowdecreasingdates',
+ default=False,
+)
+coreconfigitem(
b'debug',
b'dirstate.delaywrite',
default=0,
diff --git a/hgext/convert/subversion.py b/hgext/convert/subversion.py
--- a/hgext/convert/subversion.py
+++ b/hgext/convert/subversion.py
@@ -97,6 +97,10 @@
return s.decode(fsencoding).encode('utf-8')
+def svndate(date):
+ return dateutil.datestr(date, b'%Y-%m-%dT%H:%M:%S.000000Z')
+
+
class SvnPathNotFound(Exception):
pass
@@ -1389,6 +1393,7 @@
ACTION="$5"
if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
+if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:date" ]; 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
@@ -1479,6 +1484,10 @@
output = self.run0(b'info')
self.uuid = self.uuid_re.search(output).group(1).strip()
+ # Last converted commit date, preserved to track decreasing of commit
+ # dates
+ self.lastdate = None
+
def wjoin(self, *names):
return os.path.join(self.wc, *names)
@@ -1636,6 +1645,11 @@
fp = os.fdopen(fd, 'wb')
fp.write(util.tonativeeol(commit.desc))
fp.close()
+
+ # Subverson always uses UTC to represent date and time
+ date = dateutil.parsedate(commit.date)
+ date = (date[0], 0)
+
try:
output = self.run0(
b'commit',
@@ -1667,6 +1681,29 @@
revprop=True,
revision=rev,
)
+
+ # If svn dates decreasing is not allowed - keep them monotonically
+ # increasing by sacrificing some real date and time values.
+ if not self.ui.configbool(b'convert', b'svn.allowdecreasingdates'):
+ self.lastdate = max(self.lastdate, date) if self.lastdate is not None else date
+ if date != self.lastdate:
+ self.ui.warn(_(b'prevented svn commit date from decreasing '
+ b'for revision %s, '
+ b'used %s instead of %s\n') %
+ (rev,
+ svndate(self.lastdate),
+ svndate(date)))
+ date = self.lastdate
+
+ # 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',
+ svndate(date),
+ revprop=True,
+ revision=rev,
+ )
+
for parent in parents:
self.addchild(parent, rev)
return self.revid(rev)
diff --git a/hgext/convert/__init__.py b/hgext/convert/__init__.py
--- a/hgext/convert/__init__.py
+++ b/hgext/convert/__init__.py
@@ -491,6 +491,17 @@
:convert.skiptags: does not convert tags from the source repo to the target
repo. The default is False.
+
+ Subversion Destination
+ ######################
+
+ Commit dates being converted to subversion destination are kept
+ monotonically increasing by default.
+
+ :convert.svn.allowdecreasingdates: convert commit dates as is allowing svn
+ commit dates to decrease. This may break some subversion functionality
+ when using the resulting repository (e.g. filtering revisions by using
+ date ranges with ``svn log``).
"""
return convcmd.convert(ui, src, dest, revmapfile, **opts)
To: nslsrv, #hg-reviewers
Cc: mercurial-patches, mercurial-devel
More information about the Mercurial-devel
mailing list