[PATCH V2 1/2] diff: add the --output option

Ahmed S. Darwish darwish.07 at gmail.com
Mon Jul 1 11:25:59 CDT 2013


# HG changeset patch
# User Ahmed S. Darwish <a.darwish at vireton.com>
# Date 1372695210 -7200
# Node ID c1aa2fdfc7b7a8fff58b192259dcdf4f74f7ada7
# Parent  648d1974b3f328947ee6cf2d00c66815a33cd208
diff: add the --output option

For all shells which cannot save a command standard output correctly,
this option is now introduced.

The most common example is Microsoft PowerShell, where the piped
output gets corrupted if saved using the standard, unix-like, stdout
rediction, '>' operator. By transforming the piped output to a
different encoding, PowerShell saves 'hg diff' patch output to a
format __not understandable__ by GNU patch and 'hg patch' commands.

Windows PowerShell is installed by default on all Windows 7+
machines (Windows 7, 8, Server 2008, and Server 2012). An easily
invokable 'hg diff > temp.patch' command should thus be available
on these systems.

For a similar real-world scenario, please check:

http://www.webcitation.org/6Hiiqf425 - Archived from the original
post at http://nbevans.wordpress.com/2011/02/22/lightweight-shelving-of-your-work-in-progress-with-mercurial/

diff -r 648d1974b3f3 -r c1aa2fdfc7b7 mercurial/cmdutil.py
--- a/mercurial/cmdutil.py	Sun Jun 30 15:19:39 2013 -0500
+++ b/mercurial/cmdutil.py	Mon Jul 01 18:13:30 2013 +0200
@@ -7,6 +7,7 @@
 
 from node import hex, nullid, nullrev, short
 from i18n import _
+from datetime import datetime
 import os, sys, errno, re, tempfile
 import util, scmutil, templater, patch, error, templatekw, revlog, copies
 import match as matchmod
@@ -123,6 +124,16 @@
         limit = None
     return limit
 
+def fsfriendly(user):
+    """return committer's username in a short and filesystem-friendly
+    manner.  This basically implies removing email info, white spaces,
+    and other problematic characters for common filesystems.
+    reference: MSDN - Naming Files, Paths, and Namespaces.
+    """
+    user = re.sub('\<[^<]*@[^>]*\>', '', user)
+    user = re.sub("[\W]", '', user)
+    return user.lower()
+
 def makefilename(repo, pat, node, desc=None,
                   total=None, seqno=None, revwidth=None, pathname=None):
     node_expander = {
@@ -134,6 +145,8 @@
     expander = {
         '%': lambda: '%',
         'b': lambda: os.path.basename(repo.root),
+        'u': lambda: fsfriendly(repo.ui.username()),
+        'd': lambda: datetime.now().strftime("%Y_%m_%d-%H_%M_%S")
         }
 
     try:
diff -r 648d1974b3f3 -r c1aa2fdfc7b7 mercurial/commands.py
--- a/mercurial/commands.py	Sun Jun 30 15:19:39 2013 -0500
+++ b/mercurial/commands.py	Mon Jul 01 18:13:30 2013 +0200
@@ -2676,7 +2676,9 @@
         ui.warn("%s\n" % res2)
 
 @command('^diff',
-    [('r', 'rev', [], _('revision'), _('REV')),
+    [('o', 'output', '',
+     _('print output to file with formatted name'), _('FORMAT')),
+    ('r', 'rev', [], _('revision'), _('REV')),
     ('c', 'change', '', _('change made by revision'), _('REV'))
     ] + diffopts + diffopts2 + walkopts + subrepoopts,
     _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
@@ -2692,6 +2694,21 @@
        default to comparing against the working directory's first
        parent changeset if no revisions are specified.
 
+    Output may be to a file, in which case the name of the file is
+    given using a format string. The formatting rules are as follows:
+
+    :``%%``: literal "%" character
+    :``%b``: basename of the exporting repository
+    :``%u``: committer username, in a filesystem-friendly manner
+    :``%d``: current local date and time
+
+    .. note::
+       Do not save diff output using Windows PowerShell (R) pipeline
+       `|` or standard output redirection `>` facilities. They change
+       the resulting diffs encoding, making them unappliable by
+       :hg:`patch` or GNU patch afterwards. Use the
+       :hg:`diff --output` option instead.
+
     When two revision arguments are given, then changes are shown
     between those revisions. If only one revision is specified then
     that revision is compared to the working directory, and, when no
@@ -2737,6 +2754,7 @@
     Returns 0 on success.
     """
 
+    fname = opts.get('output')
     revs = opts.get('rev')
     change = opts.get('change')
     stat = opts.get('stat')
@@ -2754,10 +2772,14 @@
     if reverse:
         node1, node2 = node2, node1
 
+    fp = None
+    if fname:
+        fp = cmdutil.makefileobj(repo, fname)
+
     diffopts = patch.diffopts(ui, opts)
     m = scmutil.match(repo[node2], pats, opts)
     cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
-                           listsubrepos=opts.get('subrepos'))
+                           fp=fp, listsubrepos=opts.get('subrepos'))
 
 @command('^export',
     [('o', 'output', '',


More information about the Mercurial-devel mailing list