[PATCH 1 of 1] Option to enforce using UTC for commit dates

arne_bab at web.de arne_bab at web.de
Mon Dec 17 19:24:53 CST 2012


 mercurial/cmdutil.py      |   4 ++-
 mercurial/commands.py     |   5 +++-
 mercurial/help/config.txt |   4 +++
 mercurial/util.py         |  51 ++++++++++++++++++++++++++++++++++++----------
 tests/test-commit.t       |  10 ++++++++-
 5 Dateien verändert, 60 Zeilen hinzugefügt(+), 14 Zeilen entfernt(-)


# HG changeset patch
# User Arne Babenhauserheide <bab at draketo.de>
# Date 1355793798 -3600
# Node ID c4e74e535082cee18b73f09cf5b0c6b5ffbcd19d
# Parent  7aa7380691b8815200dda268aa1af19fd56aa741
Option to enforce using UTC for commit dates.

The timezone entries in commit messages give away location information
of the commiter, which can be dangerous when Mercurial is used
anonymously.

To mitigate that danger, this commit adds an rc-option to use UTC
dates, except when the timezone is requested explicitely via a date
string or by amending a commit without changing the date and time.

To switch to UTC times, add

    [ui]
    datetimeutc = True

to your ~/.hgrc or a .hg/hgrc.

Extensions like infocalypse can also set this option when doing the
initial clone from an anonymous source to ensure that the default
behaviour of Mercurial is safe.

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1586,7 +1586,9 @@ def commit(ui, repo, commitfunc, pats, o
     '''commit the specified files or all outstanding changes'''
     date = opts.get('date')
     if date:
-        opts['date'] = util.parsedate(date)
+        opts['date'] = util.timezoneprivacy(ui.configbool('ui', 'datetimeutc'),
+                                            date)
+
     message = logmessage(ui, opts)
 
     # extract addremove carefully -- this function can be called from a command
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1304,9 +1304,12 @@ def commit(ui, repo, *pats, **opts):
             if not message:
                 message = old.description()
                 editor = cmdutil.commitforceeditor
+            date = util.timezoneprivacy(ui.configbool('ui', 'datetimeutc'),
+                                        opts.get('date'),
+                                        old.date())
             return repo.commit(message,
                                opts.get('user') or old.user(),
-                               opts.get('date') or old.date(),
+                               date,
                                match,
                                editor=editor,
                                extra=extra)
diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -1128,6 +1128,10 @@ User interface controls.
     changes, abort the commit.
     Default is False.
 
+``datetimeutc``
+    Whether to always use Universal Time Coordinated (UTC) for date
+    entries when committing.
+
 ``debug``
     Print debugging information. True or False. Default is False.
 
diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -980,20 +980,20 @@ def shortdate(date=None):
     """turn (timestamp, tzoff) tuple into iso 8631 date."""
     return datestr(date, format='%Y-%m-%d')
 
+def timezone(string):
+    tz = string.split()[-1]
+    if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
+        sign = (tz[0] == "+") and 1 or -1
+        hours = int(tz[1:3])
+        minutes = int(tz[3:5])
+        return -sign * (hours * 60 + minutes) * 60
+    if tz == "GMT" or tz == "UTC":
+        return 0
+    return None
+
 def strdate(string, format, defaults=[]):
     """parse a localized time string and return a (unixtime, offset) tuple.
     if the string cannot be parsed, ValueError is raised."""
-    def timezone(string):
-        tz = string.split()[-1]
-        if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
-            sign = (tz[0] == "+") and 1 or -1
-            hours = int(tz[1:3])
-            minutes = int(tz[3:5])
-            return -sign * (hours * 60 + minutes) * 60
-        if tz == "GMT" or tz == "UTC":
-            return 0
-        return None
-
     # NOTE: unixtime = localunixtime + offset
     offset, date = timezone(string), string
     if offset is not None:
@@ -1151,6 +1151,35 @@ def matchdate(date):
         start, stop = lower(date), upper(date)
         return lambda x: x >= start and x <= stop
 
+def timezoneprivacy(privacy, datestring=None, date=None):
+    """Switch to UTC if the timezone could be a risk to
+    privacy and the timezone was not requested explicitly.
+
+    >>> withtz = parsedate("2012-12-23 10:04:23 +0300")
+    >>> localtz = makedate()[1]
+    >>> notz = timezoneprivacy(True, "2012-12-23 07:04:23")
+    >>> notz[1] == 0
+    True
+    >>> notz[0] - localtz == withtz[0]
+    True
+    >>> (notz[0], localtz) == timezoneprivacy(False, "2012-12-23 07:04:23")
+    True
+    >>> (withtz[0], -3600) == timezoneprivacy(True, "2012-12-23 08:04:23 +0100")
+    True
+    >>> (withtz[0], 18000) == timezoneprivacy(True, "2012-12-23 02:04:23 -0500")
+    True
+    """
+    when = parsedate(datestring or date or makedate())
+    if not privacy:
+        return when
+    hastimezone = timezone(datestring) is not None
+    if datestring and not hastimezone:
+        return when[0], 0
+    if datestring or date:
+        return when
+    # no explicit datestring or date: use current UTC
+    return when[0], 0
+
 def shortuser(user):
     """Return a short representation of a user name or email address."""
     f = user.find('@')
diff --git a/tests/test-commit.t b/tests/test-commit.t
--- a/tests/test-commit.t
+++ b/tests/test-commit.t
@@ -90,12 +90,20 @@ commit added file that has been deleted
   dir/file
   committed changeset 4:49176991390e
 
-An empty date was interpreted as epoch origin
+date argument parsing
 
   $ echo foo >> foo
   $ hg commit -d '' -m commit-no-date
   $ hg tip --template '{date|isodate}\n' | grep '1970'
   [1]
+  $ echo foo >> foo
+  $ hg --config ui.datetimeutc=True commit -d '1982-04-23 14:23' -m commit-utc
+  $ hg tip --template '{date|isodate}\n'
+  1982-04-23 14:23 +0000
+  $ echo foo >> foo
+  $ hg --config ui.datetimeutc=True commit -d '1982-04-23 14:23 +0100' -m commit-utc
+  $ hg tip --template '{date|isodate}\n'
+  1982-04-23 14:23 +0100
 
 Make sure we do not obscure unknown requires file entries (issue2649)
 


More information about the Mercurial-devel mailing list