[PATCH 1 of 4] hgmerge: add new hgmerge package under mercurial

Matt Mackall mpm at selenic.com
Tue Jan 8 11:49:20 CST 2008


On Mon, 2008-01-07 at 15:20 -0600, Steve Borho wrote:
> # HG changeset patch
> # User Steve Borho <steve at borho.org>
> # Date 1199739435 21600
> # Node ID 1dabe5c4867c4f1d855494ecd0f76d6436882c6e
> # Parent  3ef279074c77c3cf3f6b35f0f73dee2fdba5aa41
> hgmerge: add new hgmerge package under mercurial
> 
> diff --git a/mercurial/hgmerge/README.txt b/mercurial/hgmerge/README.txt
> new file mode 100644
> --- /dev/null
> +++ b/mercurial/hgmerge/README.txt
> @@ -0,0 +1,96 @@
> +Cross-platform merging for Mercurial.
> +
> +The purpose of hgmerge is to provide a file revision merging interface, with
> +good default behavior and user configurability.  It is the default merge
> +behavior for Mercurial when HGMERGE is not set in your environmant and ui.merge
> +is not set in your hgrc file(s).
> +
> +When unconfigured, hgmerge will attempt to perform a 3-way merge using an
> +included simplemerge script that runs without user interaction.  If no conflicts
> +are found, the merge is successful.  When conflicts are found, hgmerge will
> +search for interactive 3-way merge tools on your computer and use the first one
> +it finds.  If no tools are detected (or if requested tool is not found), the
> +partially merged file with conflict markers is left in the working directory to
> +be resolved manually.  Note that Mercurial does not track 'conflict' file
> +status, so users have to be diligent to not check in partially merged files.
> +
> +The 'hg debuginstall' command will report the list of plug-ins that are detected
> +on your machine.
> +
> +By adding entries in their hgrc files, users can:
> +* completely override the search by specifying a default plug-in
> +* specify plugins to use for specific file extensions
> +* modify the built-in plug-ins (override characteristics)
> +* define search precedence for plug-ins
> +* define entirely new plug-ins.
> +
> +Hgmerge defines two new hgrc sections.  [hgmerge] is used to define default and
> +file extension based plug-ins.  [hgmerge-plugins] is used to configure built-in
> +plugins and to define entirely new plugins.
> +
> +Example hgmerge section:
> +[hgmerge]
> +default = kdiff3
> +ext.png = mypngmerge
> +ext.lib = takemine
> +
> +When a file extension plug-in is specified (e.g., .png), hgmerge will bypass the
> +initial simplemerge step and directly call the specified plug-in.  This is
> +useful for e.g. binary formats that cannot be merged as text.  There are two
> +special plug-ins intended for file extension use: 'takemine' and 'takeother'
> +(with predictable behaviors).  These two will not show up in the list of
> +installed plug-ins but are always available.
> +
> +Note that unless the plug-in was selected by a file extension match, hgmerge
> +will specially handle file types which are unmergeable by most merge tools
> +(symlinks, binary files, etc).  Unmergeable files bypass the entire simplemerge
> +and plugin architecture and instead the user will be asked to chose between the
> +'local' and 'other' versions of the file.
> +
> +Plug-In Configuration
> +=====================
> +Merge plug-ins can be configured through Mercurial's configuration system
> +(hgrc). One may modify existing plug-ins or define new ones. Plug-in
> +configurations exist in the section [hgmerge-plugins]. 
> +
> +Plug-ins can be of one of two types: tool and custom. The default type is tool.
> +
> +Tool Plug-Ins
> +-------------
> +A tool definition represents an external program and parameters for running
> +that, such as its arguments. The argument line can contain variables, the
> +following are supported: $base, $local, $other, $output.
> +
> +The following options can be set for a tool:
> +	executable: Either just the name of the executable or its pathname. Per
> +	default the same as the plug-in's name.
> +	arguments: The arguments to pass to the tool (default: $base $local $other
> +	$output)
> +	priority: The priority in which to evaluate this plug-in.
> +	stdout: Should the tool's standard output be used as the merge result?
> +	check_conflicts: Check whether there are conflicts even though the tool
> +	reported none?
> +	win.regpath_installdir: Specify a pathname in the Windows registry defining
> +	the tool's installation directory. The format of this option is like this:
> +	<key name>\<value name>. If the key itself actually holds the value, end
> +	the pathname with a backslash, so it's clear there is no value name
> +	component.
> +	win.regpath_installpath: Like the former, except that the registry value
> +	is taken to specify the installation path of the tool's executable.
> +	
> +Example tool configuration:
> +[hgmerge-plugins]
> +gvimdiff.type = tool
> +gvimdiff.arguments = --nofork -d -g -O $output $other $base
> +gvimdiff.priority = 1
> +gvimdiff.win.regpath_installpath = Software\Vim\GVim\path
> +kdiff3.executable = ~/bin/kdiff3   # override built in plug-in value
> +
> +Note that the plugin type defaults to tool and can be left unspecified, and the
> +priority defaults to 0 (higher priority tools are detected first).
> +
> +Custom Plug-Ins
> +---------------
> +A "custom" plug-in is defined by a Python class. TODO ...
> +
> +# vim: textwidth=80
> diff --git a/mercurial/hgmerge/TODO.txt b/mercurial/hgmerge/TODO.txt
> new file mode 100644
> --- /dev/null
> +++ b/mercurial/hgmerge/TODO.txt
> @@ -0,0 +1,5 @@
> +* Allow user to turn off automatic invocation of merge tool
> +* Port tests to standard Mercurial system
> +
> +MacOS         - needs wrappers for more OSX tools
> +              - needs testing

Let's not have a TODO file. I'd prefer not to have a separate directory
too, but let's see..

> diff --git a/mercurial/hgmerge/__init__.py b/mercurial/hgmerge/__init__.py
> new file mode 100644
> --- /dev/null
> +++ b/mercurial/hgmerge/__init__.py
> @@ -0,0 +1,544 @@
> +# -*- coding: utf-8 -*-
> +""" Logic for merging changes in two versions of a file.
> + at var stockplugins: Sequence of stock plug-in representations.
> +"""
> +import shutil
> +import StringIO
> +import filecmp
> +import random
> +import traceback
> +    
> +from mercurial.hgmerge._common import *
> +import mercurial.util as hgutil
> +import _simplemerge
> +import _plugins as hgmergeplugs
> +import _pluginapi as hgpluginapi
> +
> +stockplugins = hgmergeplugs.plugins
> +
> +# Initially not defined
> +plugins = None
> +
> +class filedesc(object):
> +    ''' Describe properties of a file.
> +    @ivar name: The file's name.
> +    @ivar islink: Is the file a symlink?
> +    '''

I detect design overkill.

> +class _pluginopts(object):
> +    ''' Plug-in options handler baseclass.
> +    '''
> +    def __init__(self, ui, sectname, name):
> +        self.attrs = {}
> +        self.__ui, self.__sect, self.__name = ui, sectname, name
> +        self._set_int('priority', default=0)
> +        
> +    def _set_string(self, prop, **kwds):
> +        self._set_opt(prop, self.__ui.config, **kwds)
> +        
> +    def _set_bool(self, prop, **kwds):
> +        self._set_opt(prop, self.__ui.configbool, **kwds)

Yes, looks like someone's a Java fan.

This code is about 5 times as long as it needs to be. Needs a few rounds
of simplifying.

> +def _is_mergeable(base, local, other):
> +    ''' Are the files mergeable?
> +    @return: Success?
> +    '''
> +    mergetypes = ('dos', 'unix', 'mac')
> +
> +    for eoltp in (local.eoltype, other.eoltype, base.eoltype):
> +        if eoltp not in mergetypes:
> +            return False

Hmmm. Don't really like this. Does it apply to user-defined tools?

> +def _readfile(fname):
> +    f = file(fname, 'rb')
> +    try: data = f.read()
> +    finally: f.close()
> +    return data

This function should be taken out and shot.

> +
> +def _ask_unmergeable(ui, local, other, output):
> +    ''' File is not mergeable, ask user which version to keep.
> +    @return: Success?
> +    '''
> +    def _describe(fdesc):
> +        '''Describe a file to the user'''
> +        if not fdesc.islink:
> +            eoltp = fdesc.eoltype
> +            if eoltp in ('dos', 'unix', 'mac'):
> +                return 'is a %s style text file browsable here\n%s' % (

Browsable?

> +def eoltype(name):
> +    ''' Get the EOL type for a file.
> +    '''

util.py

> +def lookup_reg(path):
> +    ''' Look up a path in the Windows registry.
> +    @return: The value for the path if found, else None.
> +    '''

util_win32.py

> +# -*- coding: utf-8 -*-s

No thanks.

> \ No newline at end of file

Oops.

> diff --git a/contrib/simplemerge b/mercurial/hgmerge/_simplemerge.py
> old mode 100755
> new mode 100644
> copy from contrib/simplemerge
> copy to mercurial/hgmerge/_simplemerge.py

I think we have tests that want to use this.

> --- /dev/null
> +++ b/mercurial/hgmerge/design.txt
> @@ -0,0 +1,26 @@
> +Hgmerge's design explained

Put this in a file docstring.

> +# vim: textwidth=80

No thanks.

-- 
Mathematics is the supreme nostalgia of our time.



More information about the Mercurial-devel mailing list