Merge with mpm
authorBrendan Cully <brendan@kublai.com>
Wed, 06 Dec 2006 13:51:54 -0800
changeset 3819 6099cfa7c4aa
parent 3818 bcdab0b2a6f5 (current diff)
parent 3813 fc5ba0ab7f45 (diff)
child 3820 4f056896c093
Merge with mpm
--- a/mercurial/commands.py	Wed Dec 06 13:27:39 2006 -0800
+++ b/mercurial/commands.py	Wed Dec 06 13:51:54 2006 -0800
@@ -788,11 +788,17 @@
     except KeyError:
         raise util.Abort(_('invalid revision identifier %s') % rev)
 
-def debugdate(ui, date):
+def debugdate(ui, date, range=None, **opts):
     """parse and display a date"""
-    d = util.parsedate(date)
+    if opts["extended"]:
+        d = util.parsedate(date, util.extendeddateformats)
+    else:
+        d = util.parsedate(date)
     ui.write("internal: %s %s\n" % d)
     ui.write("standard: %s\n" % util.datestr(d))
+    if range:
+        m = util.matchdate(range)
+        ui.write("match: %s\n" % m(d[0]))
 
 def debugindex(ui, file_):
     """dump the contents of an index file"""
@@ -1521,6 +1527,11 @@
             return ncache[fn].get(dcache[1][fn])
         return None
 
+    df = False
+    if opts["date"]:
+        df = util.matchdate(opts["date"])
+
+
     displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
     for st, rev, fns in changeiter:
         if st == 'add':
@@ -1532,6 +1543,11 @@
             if opts['only_merges'] and len(parents) != 2:
                 continue
 
+            if df:
+                changes = get(rev)
+                if not df(changes[2][0]):
+                    continue
+
             if opts['keyword']:
                 changes = get(rev)
                 miss = 0
@@ -2483,7 +2499,9 @@
     "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
     "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
     "debugstate": (debugstate, [], _('debugstate')),
-    "debugdate": (debugdate, [], _('debugdata DATE')),
+    "debugdate": (debugdate,
+                  [('e','extended', None, _('try extended date formats'))],
+                  _('debugdata [-e] DATE [RANGE]')),
     "debugdata": (debugdata, [], _('debugdata FILE REV')),
     "debugindex": (debugindex, [], _('debugindex FILE')),
     "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
@@ -2578,6 +2596,7 @@
            _('follow changeset history, or file history across copies and renames')),
           ('', 'follow-first', None,
            _('only follow the first parent of merge changesets')),
+          ('d', 'date', '', _('show revs matching date spec')),
           ('C', 'copies', None, _('show copied files')),
           ('k', 'keyword', [], _('search for a keyword')),
           ('l', 'limit', '', _('limit number of changes displayed')),
--- a/mercurial/util.py	Wed Dec 06 13:27:39 2006 -0800
+++ b/mercurial/util.py	Wed Dec 06 13:51:54 2006 -0800
@@ -85,6 +85,8 @@
     '%a %b %d %H:%M:%S %Y',
     '%a %b %d %I:%M:%S%p %Y',
     '%b %d %H:%M:%S %Y',
+    '%b %d %I:%M:%S%p %Y',
+    '%b %d %H:%M:%S',
     '%b %d %I:%M:%S%p',
     '%b %d %H:%M',
     '%b %d %I:%M%p',
@@ -96,6 +98,13 @@
     '%I:%M%p',
 )
 
+extendeddateformats = defaultdateformats + (
+    "%Y",
+    "%Y-%m",
+    "%b",
+    "%b %Y",
+    )
+
 class SignalInterrupt(Exception):
     """Exception raised on SIGTERM and SIGHUP."""
 
@@ -1058,7 +1067,7 @@
         s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
     return s
 
-def strdate(string, format='%a %b %d %H:%M:%S %Y'):
+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):
@@ -1076,16 +1085,12 @@
     if offset != None:
         date = " ".join(string.split()[:-1])
 
-    # add missing elements
-    if '%y' not in format.lower():
-        date += "@" + datestr(makedate(), "%Y", False)
-        format += "@%Y"
-    if '%m' not in format and '%b' not in format:
-        date += "@" + datestr(makedate(), "%m", False)
-        format += "@%m"
-    if '%d' not in format:
-        date += "@" + datestr(makedate(), "%d", False)
-        format += "@%d"
+    # add missing elements from defaults
+    for part in defaults:
+        found = [True for p in part if ("%"+p) in format]
+        if not found:
+            date += "@" + defaults[part]
+            format += "@%" + part[0]
 
     timetuple = time.strptime(date, format)
     localunixtime = int(calendar.timegm(timetuple))
@@ -1097,7 +1102,7 @@
         unixtime = localunixtime + offset
     return unixtime, offset
 
-def parsedate(string, formats=None):
+def parsedate(string, formats=None, defaults=None):
     """parse a localized time string and return a (unixtime, offset) tuple.
     The date may be a "unixtime offset" string or in one of the specified
     formats."""
@@ -1109,9 +1114,22 @@
     try:
         when, offset = map(int, string.split(' '))
     except ValueError:
+        # fill out defaults
+        if not defaults:
+            defaults = {}
+        now = makedate()
+        for part in "d mb yY HI M S".split():
+            if part not in defaults:
+                if part[0] in "HMS":
+                    defaults[part] = "00"
+                elif part[0] in "dm":
+                    defaults[part] = "1"
+                else:
+                    defaults[part] = datestr(now, "%" + part[0], False)
+
         for format in formats:
             try:
-                when, offset = strdate(string, format)
+                when, offset = strdate(string, format, defaults)
             except ValueError:
                 pass
             else:
@@ -1128,6 +1146,54 @@
         raise Abort(_('impossible time zone offset: %d') % offset)
     return when, offset
 
+def matchdate(date):
+    """Return a function that matches a given date match specifier
+
+    Formats include:
+
+    '{date}' match a given date to the accuracy provided
+
+    '<{date}' on or before a given date
+
+    '>{date}' on or after a given date
+
+    """
+
+    def lower(date):
+        return parsedate(date, extendeddateformats)[0]
+
+    def upper(date):
+        d = dict(mb="12", HI="23", M="59", S="59")
+        for days in "31 30 29".split():
+            try:
+                d["d"] = days
+                return parsedate(date, extendeddateformats, d)[0]
+            except:
+                pass
+        d["d"] = "28"
+        return parsedate(date, extendeddateformats, d)[0]
+
+    if date[0] == "<":
+        when = upper(date[1:])
+        return lambda x: x <= when
+    elif date[0] == ">":
+        when = lower(date[1:])
+        return lambda x: x >= when
+    elif date[0] == "-":
+        try:
+            days = int(date[1:])
+        except ValueError:
+            raise Abort(_("invalid day spec: %s") % date[1:])
+        when = makedate()[0] - days * 3600 * 24
+        return lambda x: x >= when
+    elif " to " in date:
+        a, b = date.split(" to ")
+        start, stop = lower(a), upper(b)
+        return lambda x: x >= start and x <= stop
+    else:
+        start, stop = lower(date), upper(date)
+        return lambda x: x >= start and x <= stop
+
 def shortuser(user):
     """Return a short representation of a user name or email address."""
     f = user.find('@')