Skip to content
Snippets Groups Projects
Marcin Kasperski's avatar
Marcin Kasperski authored
90e9262b
History
.. -*- mode: rst -*-

==========================================
Mercurial Path Pattern
==========================================

Don't repeat yourself defining ``[paths]`` over many repositories,
specify the general rule once in ``~/.hgrc``.

``path_pattern`` is a Mercurial_ extension used to define default
remote path aliases. You may find it helpful if you maintain
consistently layed out repository trees on a few machines.

It also provides shortcut ``hg cloneto «path-alias»`` (clone to
address to which given path alias resolves).

Using path patterns
=====================

Install the extension (``sudo pip install mercurial_path_pattern`` or
manually in the way described below).

Write in your ``~/.hgrc``::

    [extensions]
    path_pattern =

    [path_pattern]
    lagrange.local = ~/devel/{repo}
    lagrange.remote =  ssh://johny@lagrange.mekk.net/sources/{repo}
    bbssh.local = ~/devel/public/{below}
    bbssh.remote = ssh://hg@bitbucket.org/Johny/{below:/=-}

Imagine ``~/devel/personal/blog/drafts`` and ``~/devel/public/pymods/acme``
are both some mercurial repositories. Then::

    cd ~/devel/personal/blog/drafts
    hg push lagrange
    # Works, pushes to ssh://johny@lagrange.mekk.net/sources/personal/blog/drafts

    cd ~/devel/public/pymods/acme
    hg pull lagrange
    # Works, pulls from ssh://johny@lagrange.mekk.net/sources/public/pymods/acme
    hg pull bbssh
    # Works too, pulls from ssh://hg@bitbucket.org/Johny/pymods-acme

Note: paths ``lagrange`` and ``bbssh`` need not be defined in any of those
repositories (those repos may even lack ``.hg/hgrc`` at all).

For two repositories that's not very useful, but once you have hundred
of them, managing individual ``.hg/hgrc`` becomes a hassle (imagine
changing ``lagrange.mekk.net`` to ``lagrange.mekk.com`` everywhere, or
maybe adding second remote alias for the new development machine).

By default path patterns have lower priority than per-repository
paths, so in case you define ``lagrange`` path on repository level, it
won't be overwritten. You can augment it by adding ``.enforce``::

    [path_pattern]
    lagrange.local = ~/devel/{repo}
    lagrange.remote =  ssh://johny@lagrange.mekk.net/sources/{repo}
    lagrange.enforce = true

With such config pattern wins against any path from ``.hg/hgrc``
(usually it is not recommended but can be handy if you have some
broken paths scattered around repositories).


Using cloneto
======================

There is also::

    hg cloneto lagrange
    # Equivalent to 
    #   hg clone . ssh://johny@lagrange.mekk.net/sources/pymodules/acme
    # but noticeably shorter

which works both for normal paths and paths derived from patterns, but
is especially handy with patterns. In particular, it makes
it possible to push newly created repository, for example::

    cd ~/devel/libs
    hg init xyz
    cd xyz
    hg cloneto lagrange
    # Works, creates soures/libs/xyz on johny@lagrange.mekk.net


Commands
=====================

Extension mostly works behind the courtains, making standard commands
like ``hg pull``, ``hg push``, and ``hg incoming`` aware of extra
paths. In particular, ``hg paths`` includes generated paths and can be
used to check whether they are correct.

You may also use::

    hg list_path_patterns

to check which patterns you configured.

The::

    hg cloneto «alias»

command looks up alias among paths (both pattern-based, and normal)
and issues clone to this path. It is equivalent to ``hg clone . «alias
expansion»``). In case alias is not defined, it fails.



Pattern syntax
=====================

Patterns are defined in ``[path_pattern]`` section of mercurial
configuration file (typically they are kept in ``~/.hgrc``, but feel
free to define them system-wide).

You may have as many patterns as you like. Example::

    [path_pattern]
    lagrange.local = ~/devel/{repo}
    lagrange.remote =  ssh://johny@lagrange.mekk.net/sources/{repo}
    euler.local = ~/devel/{repo}
    euler.remote =  ssh://johny@euler.mekk.net/devel/{repo:/=.}/hg
    wrk.local = ~/work/{what}
    wrk.remote =  https://tim@devel-department.local/{what:/=__:\=__}
    ugly.local = ~/(topic)/sources/{subpath}/repo
    ugly.remote = ssh://hg{topic}@devel.local/{topic}/{subpath}
    cfg.local = ~/.config/upstart
    cfg.remote = ssh://hgrepos@central.com/configs/riemann/upstart

Every pattern is defined by the pair of keys - ``«alias».local`` and
``«alias».remote``. 

While processing patterns, the extension matches current repository
root path against ``local`` pattern, and if it matches, extracts parts
marked with markers and fills remote part with them to calculate
proper path to use.

Local part specifies the format some repository path must have to
match the rule. It should be absolute, but ``~`` and ``~user`` are
allowed. Some part(s) of the path may be replaced with ``{brace}`` or
``(paren)`` markers (both serve the same purpose, but ``{brace}``
matches everything aggressively while ``(paren)`` is limited to single
path item and does not cross ``/`` or ``\\`` characters). Those parts
will be extracted from local repository path and available for use in
alias being defined. Typically there will be single ``{marker}`` on
the end, but more obscure patterns are possible (as ``ugly`` above
illustrates). Markers are optional, if not used, rule applies to
exactly one repository (see ``cfg`` above).

Remote part defines appropriate remote address. This is typical
Mercurial remote path, where ``{marker}``'s can be used to refer to
values extracted from local path (``{sth}`` is replaced with whatever
matched ``{sth}`` or ``(sth)`` used in local path). Simple substitutions are allowed –
``{sth:x=y}`` means *take whatever was extracted as* ``sth`` *and
replace any* ``x`` *with* ``y`` – *and can be chained if necessary* –
``{sth:x=y,v=z}`` means *take whatever was extracted as* ``sth``,
*replace any* ``x`` *with* ``y``, *then replace any* ``v`` *with* ``z``, *then
use the final result*.

For example, with definitions above, if you happen to issue ``hg paths``
in repository ``~/devel/python/libs/webby``, the extension will:

1. Find that ``lagrange.local`` matches and that ``{repo}`` is
   ``python/libs/webby``.   Filling ``lagrange.remote`` with
   that value generates
   ``ssh://johny@lagrange.mekk.net/sources/python/libs/webby``, so
   finally it will create path alias
   ``lagrange=ssh://johny@lagrange.mekk.net/sources/python/libs/webby``;

2. Discover that ``euler.local`` also matches, and ``{repo}`` is again
   ``python/libs/webby``. After replacing ``/``-s with ``.``-s,
   that brings alias 
   ``euler=ssh://johny@euler.mekk.net/devel/python.libs.webby/hg``;

3. Ignore remaining patterns as they do not match.


Installation
=================================================

Recommended way::

    pip install mercurial_path_pattern

(prepend with ``sudo`` if necessary).

Manual way:

- install `mercurial_extension_utils`_

- download ``path_pattern.py`` from this repository and save it somewhere

- activate extension by::

       path_pattern = /path/to/path_pattern.py


History
==================================================

See `HISTORY.txt`_


Development, bug reports, enhancement suggestions
===================================================

Development is tracked on BitBucket, see 
http://bitbucket.org/Mekk/mercurial-path_pattern/

Use BitBucket issue tracker for bug reports and enhancement
suggestions.

Additional notes
================

Information about this extension is also available
on Mercurial Wiki: http://mercurial.selenic.com/wiki/PathPatternExtension

.. _Mercurial: http://mercurial.selenic.com
.. _HISTORY.txt: http://bitbucket.org/Mekk/mercurial-path_pattern/src/tip/HISTORY.txt
.. _mercurial_extension_utils: https://bitbucket.org/Mekk/mercurial-extension_utils/