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

Arve Knudsen arve.knudsen at gmail.com
Tue Jan 8 12:28:11 CST 2008


On Jan 8, 2008 6:49 PM, Matt Mackall <mpm at selenic.com> wrote:

>
> 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..


True, it's for initial development.

> 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.


How? It's a direct subset of Mercurial file contexts. If necessary it may
grow to share more attributes with the latter. Don't recall off the top of
my head why we didn't pass in file contexts directly.

>
> > +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.
>

I don't write Java. I don't have anything against it for that matter either
.. This is more typical generic programming, which I  _am_ a fan of. My
design typically turns out the way it does based on (unit) testability.


> 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?


Not sure what you mean by that. It is not consulted if a tool is specified
for this kind of file at least.

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

This function should be taken out and shot.
>

I don't see why, but what do I know.

> \ No newline at end of file
>
> Oops.
>

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.
>

Sure, it was written merely to hash out initial ideas anyway.

Arve
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://selenic.com/pipermail/mercurial-devel/attachments/20080108/5ba665f5/attachment.htm 


More information about the Mercurial-devel mailing list