Package: mercurial_path_pattern
Don’t repeat yourself defining[paths]over many repositories,
specify the general rule once in~/.hgrc.Path Pattern is aMercurialextension used to define default
remote path aliases. You may find it helpful if you maintain
consistently layed out repository trees on a few machines.1Using path patterns1.1Simple example1.2Overriding repository-level paths1.3Reusing the same alias2Clone-supporting commands2.1Usingcloneto2.2Instead ofclonefrom3Testing pattern configuration4Pattern syntax4.1Introduction4.2Pattern definition4.3Resolution example4.4Legacy syntax5Pattern priority6Tips and tricks6.1defaultas path pattern6.2Special treatment of specific repositories6.3Keeping non-standard remote paths as patterns6.4Separating (and sharing) pattern configuration7Installation7.1Linux/Unix (from PyPI)7.2Linux/Unix (from source)7.3Windows8Related extensions9History10Repository, bug reports, enhancement suggestions11Additional notesPath Pattern mostly works behind the courtains, making standard
commands likehg pull,hg push, andhg incomingaware of
extra paths. Still, it implements some commands, in particularhg cloneto«path-alias»(clone to remote address specified by short
name).1Using path patternsInstall the extension as described below.1.1Simple exampleWrite in your~/.hgrc:[extensions]
mercurial_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/draftsand~/devel/public/pymods/acmeare 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-acmeThis works in spite of the fact, that those repos lack.hg/hgrc.For two repositories that’s not very useful, but once you have hundred
of them, managing individual.hg/hgrcbecomes a hassle (imagine
changinglagrange.mekk.nettolagrange.mekk.comeverywhere, or
maybe adding second remote alias for the new development machine).NoteOn Windows extension tries to handle (in.localspecifications)
both native paths (C:\repos\sth) and portable ones
(C:/repos/sth), but it is recommended to use the
latter. Whichever syntax is used, extracted{fragments}contain/(so they can be easily used in remote urls).1.2Overriding repository-level pathsBy default path patterns have lower priority than per-repository
paths, so in case you definelagrangepath on repository level, it
won’t be overwritten by the pattern. You can augment it by adding.enforce:[path_pattern]
lagrange.local = ~/devel/{repo}
lagrange.remote =  ssh://johny@lagrange.mekk.net/sources/{repo}
lagrange.enforce = trueWith such config pattern wins against any path from.hg/hgrc(usually it is not recommended but can be handy if you have some
broken path scattered around repositories).1.3Reusing the same aliasTo (re)use the same alias in a few different locations, useALIAS.XTRA.localandALIAS.XTRA.remotekeys, whereXTRAis something unique. For example:[path_pattern]
production.main.local = ~/devel/{repo}
production.main.remote = ssh://www-owner@www.acme.org/public/{repo}
production.beta.local = ~/experiments/{repo}
production.beta.remote = ssh://www-owner@beta.acme.org/public/{repo}would let youhg push productionnot only in~/devel/website/blogbut also in~/experiments/website/qagame(pushing towww.acme.orgin the former, and tobeta.acme.orgin the
latter case). Whether this is a good idea, is up to you.2Clone-supporting commands2.1UsingclonetoTheclonetocommand makes it easier to clone repository to remote url:hg cloneto lagrange
# Equivalent to
#   hg clone . ssh://johny@lagrange.mekk.net/sources/pymodules/acme
# but noticeably shorterwhich 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 sources/libs/xyz on johny@lagrange.mekk.netNoteWhileclonetois particularly useful with patterns, it works
for usual paths as well. You can write (new) path to repository-level.hg/hgrc, thenhg cloneto«new-name».2.2Instead ofclonefromThere is noclonefromcommand (at least for now), but it is not
really needed. The following works (imaginelibs/zzzexists onlagrange.mekk.net, but is not yet clonedhere):cd ~/devel/libs
hg init zzz
cd zzz
hg pull lagrange3Testing pattern configurationThe standard:hg pathscommand lists paths defined for current repository, after pattern
expansion. Use it (in a few different repositories) to verify whether
your patterns generate proper paths.The:hg list_path_patternscommand prints all patterns found in configuration. Use it to detect
typos causing some patterns to be ignored and to check the final
result of configuration processing.4Pattern syntax4.1IntroductionPatterns are defined in[path_pattern]section of mercurial
configuration file (typically~/.hgrc).  You may have as many
patterns as you like. Example illustrating various syntax elements:[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.dotcfg.local = ~/.config/{repo}
cfg.dotcfg.remote = ssh://hgrepos@central.com/configs/riemann-config/{repo}
cfg.dotshr.local = ~/.local/share/{repo}
cfg.dotshr.remote = ssh://hgrepos@central.com/configs/riemann-local/{repo}
official.hgstable.local = ~/tracked/mercurial/hg-stable
official.hgstable.remote = http://selenic.com/repo/hg-stable
official.thg.local = ~/tracked/mercurial/tortoisehg-stable
official.thg.remote = https://bitbucket.org/tortoisehg/thg
official.evolve.local = ~/tracked/mercurial/mutable-history
official.evolve.remote = https://bitbucket.org/marmoute/mutable-history4.2Pattern definitionEvery pattern is defined by the pair of keys -«alias».localand«alias».remote- or, in case the same alias is to be used in a few
places, by«alias».«sth».localand«alias».«sth».remote(where«sth»is anything making the key unique).While processing patterns, the extension matches current repository
root path againstlocalpattern, and if it matches, calculates
remote path by filling markers present there, and defines the path alias.The.localpart should specify absolute repository path (~and~userare allowed). Some part(s) of the path may be replaced with{brace}or(paren)markers:{brace}matches everything aggressively (to the very end, unless
some fixed text follows it),(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 remote path being defined.NoteTypically there will be single{marker}on the end, but more
obscure patterns are possible (asuglyabove
illustrates).Markers are optional, if no marker is used (seeofficialabove),
rule applies to exactly one repository. This may make sense (over
defining path in given repo.hg/hgrc) if you prefer to centralize
your remote paths list (or if you frequently drop those repos to re-clone
them again later).The.remotepart defines appropriate remote address. This is typical
Mercurial remote path, but{marker}’s can be used to refer to
values extracted from local path:{sth}is replaced with whatever
matched{sth}or(sth)present in local path.Simple modifications are supported –{sth:x=y}meanstake whatever
was extracted assthand replace anyxwithy. This is
mostly used to replace/with some other character (in particular{below:/=-}handles BitBucket convention, replacing slashes with minuses).
Replacements can be multi-letter, for example{sth:lib=library}.Replacements can be chained if necessary –{sth:x=y:v=z}meanstake whatever was extracted assth,replace anyxwithy,then replace anyvwithz,then use the final
result.NoteIn case multiple patterns of the same name match, extension tries
to findbestone.  SeePattern prioritychapter below.4.3Resolution exampleWith definitions quoted above, if you happen to work
inside the~/devel/python/libs/webbyrepository, the extension will:Find thatlagrange.localmatches and that{repo}ispython/libs/webby.   Fillinglagrange.remotewith
that value generatesssh://johny@lagrange.mekk.net/sources/python/libs/webby, so
the following path alias is created:lagrange=ssh://johny@lagrange.mekk.net/sources/python/libs/webbyDiscover thateuler.localalso matches, and{repo}is againpython/libs/webby. After replacing/-s with.-s,
that brings aliaseuler=ssh://johny@euler.mekk.net/devel/python.libs.webby/hgIgnore remaining patterns as they do not match.Or, in~/tracked/mercurial/tortoisehg-stable, the extension will:Note thatofficial.thg.localmatches (at this time without
defining anything), extract matching path fromofficial.thg.remote, and finally generate for this repository
pathofficial =https://bitbucket.org/tortoisehg/thg(sohg pull officialworks there).  Note that the path alias is justofficial, the.thg.part was used only to group appropriate
config items.Ignore remaining patterns which do not match.4.4Legacy syntaxFor compatibility reasons, there exist alternative way
to reuse the same path alias. For example, instead of
(currently recommended):[path_pattern]
production.web.local = ~/devel/web/{repo}
production.web.remote = ssh://product@acme.org/www/{repo}
production.db.local = ~/devel/database/{repo}
production.db.remote = ssh://product@backend.acme.org/db/{repo}
production.monit.local = ~/devel/monitoring/{repo}
production.monit.remote = ssh://product@monit.acme.org/{repo}one can use.alias:[path_pattern]
production.local = ~/devel/web/{repo}
production.remote = ssh://product@acme.org/www/{repo}
dbproduction.db.local = ~/devel/database/{repo}
dbproduction.db.remote = ssh://product@backend.acme.org/db/{repo}
dbproduction.alias = production
monproduction.local = ~/devel/monitoring/{repo}
monproduction.remote = ssh://product@monit.acme.org/{repo}
monproduction.alias = productionBoth those syntaxes give meaning tohg push productionin all matching
repositories.NoteI keep supporting.aliassyntax for backward compatibility (it
was the initial syntax provided for the task) but it is more
elaborate and less readable, so I don’t recommend it anymore.5Pattern priorityIt is possible to write patterns so theyconflict(more than one
definition of some path exists). While not frequent, such approach has
sometimes it’s uses.Path aliases have the following priority:enforced patterns (patterns with.enforceset),per repo aliases (standard[paths]defined in.hg/hgrc),non-enforced patterns.So, for example, with:[path_pattern]
acme.local = ~/devel/{repo}
acme.remote =  ssh://johny@apps.mekk.net/code/{repo}
acme.enforce = true
acme.alt.local = ~/devel/libs/{repo}
acme.alt.remote =  ssh://johny@libs.mekk.net/{repo}(both patterns define the same aliasacme) executinghg push acmein~/devel/libs/calcwill push tossh://johny@apps.mekk.net/code/libs/calcas enforced pattern wins
over non-enforced one. The same will happen even ifacmeis
defined in per-repository.hg/hgrc(among standard[paths]).If more than one pattern of the same strength matches, extension tries
it’s best to pick one with more specific local path, for example if we
dropacme.enforcefrom the example above (or if we addacme.alt.enforce), executinghg push acmein~/devel/libs/calcwill push tossh://johny@libs.mekk.net/calcas more specific pattern wins.NoteIt’s not always obvious which pattern is more specific (compare~/(klass)/libs/basewith~/src/{repo}). Current
implementation looks for the length of non-varying prefix (so the
latter will win over the former as~/src/is longer than~/). If those are of equal length, pattern with more non-var characters wins,
and finally, the one which happened last in the config file.Some details may change in the future, useenforcewhen in
doubt (or let me know if numeric priority would be useful).6Tips and tricks6.1defaultas path patternYou can definedefaultvia path pattern if you wish:[path_pattern]
default.hobby.local = ~/hobby/{repo}
default.hobby.remote =  ssh://hg@bitbucket.org/Johny/{below:/=-}
default.wrk.local = ~/work/{what}
default.wrk.remote =  https://tim@devel-department.local/{what}(here in~/hobbyI push to bitbucket by default, but in~/workto department server).NoteMercurial will sooner or later definedefaultpath in
per-repository.hg/hgrcfiles.  Enforce your patterns
(default.hobby.enforce = true) if you need to defeat those
settings. Or don’t, if you want those patterns for defaults only.6.2Special treatment of specific repositoriesIt happens that some repository (or a few)does not matchthe
general rule. In such a case, one can simply overwrite given alias
on repository level, or use pattern priority.My real example isKeyring Extensionrepository. While I generally
use dash (-) as path separator (so Path Pattern is located at/Mekk/mercurial-path_patternandDynamic Usernameat/Mekk/mercurial-dynamic_username), keyring repo predates this
convention and is named/Mekk/mercurial_keyring. So I solve this
by:[path_pattern]
# By default bitbucket mirrors my dir structure replacing / with -
bbssh.local = ~/devel/{below}
bbssh.remote = ssh://hg@bitbucket.org/Mekk/{below:/=-}
# … but there are overrides
bbssh.keyring.local = ~/devel/mercurial/keyring
bbssh.keyring.remote = ssh://hg@bitbucket.org/Mekk/mercurial_keyringOf course I could achieve the same by definingbbsshamong[paths]in~/devel/mercurial/keyring/.hg/hgrcfile, but pattern
technique have some advantages:as I share and sync snippet of my~/.hgrcbetween machines,
this definition automatically propagates everywhere, and I don’t need
to remember about adding path to the new clone,it leaves all paths in one place where I can review them together,it can be expanded to whole subtree if necessary.6.3Keeping non-standard remote paths as patternsThe same trick can be used for maintaining list of remotes.
For example here is my way to havehg pull officialhandy
in various tracked repositories:[path_pattern]
official.hgstable.local = ~/tracked/hg-stable
official.hgstable.remote = http://selenic.com/repo/hg-stable
official.thg.local = ~/tracked/tortoise-hg
official.thg.remote = https://bitbucket.org/tortoisehg/thg/
# …Of course I could enter those paths directly inside.hg/hgrc, but
those definitions can be synced between machines, and survive
in case I discard the repo in charge for some time.6.4Separating (and sharing) pattern configurationIn case the pattern list grows bigger, I recommend moving patterns
into the separate config file. For example, write in~/.hgrc:%include ~/configs/mercurial/path_pattern.hgrcand then store all patterns inpath_pattern.hgrc:[path_pattern]
…Extra benefit of such approach is that it makes sharing the file
easier (in my case~/configs/mercurialis by itself Mercurial
repository which I share over my various development machines, and
which contains all non-machine specific snippets of my Mercurial
configuration).7Installation7.1Linux/Unix (from PyPI)If you have workingpiporeasy_install:pip install --user mercurial_path_patternor maybe:sudo pip install mercurial_path_pattern(or useeasy_installinstead ofpip). Then activate by:[extensions]
mercurial_path_pattern =To upgrade, repeat the same command with--upgradeoption, for
example:pip install --user --upgrade mercurial_path_pattern7.2Linux/Unix (from source)If you don’t havepip, or wish to follow development more closely:clone both this repository andmercurial_extension_utilsand put
them in the same directory, for example:cd ~/sources
hg clone https://foss.heptapod.net/mercurial/mercurial-extension_utils/
hg clone https://foss.heptapod.net/mercurial/mercurial-path_pattern/update to newest tags,activate by:[extensions]
mercurial_path_pattern = ~/sources/mercurial-path_pattern/mercurial_path_pattern.pyTo upgrade, pull and update.Note that directory names matter. Seemercurial_extension_utilsfor
longer description of this kind of installation.7.3WindowsIf you have any Python installed, you may install withpip:pip install mercurial_path_patternStill, as Mercurial (whether taken fromTortoiseHg, or own package)
uses it’s own bundled Python, you must activate by specifying the path:[extensions]
mercurial_path_pattern = C:/Python27/Lib/site-packages/mercurial_path_pattern.py
;; Or wherever pip installed itTo upgrade to new version:pip --upgrade mercurial_path_patternIf you don’t have any Python, clone repositories:cd c:\hgplugins
hg clone https://foss.heptapod.net/mercurial/mercurial-extension_utils/
hg clone https://foss.heptapod.net/mercurial/mercurial-path_pattern/update to tagged versions and activate by path:[extensions]
mercurial_path_pattern = C:/hgplugins/mercurial-path_pattern/mercurial_path_pattern.py
;; Or wherever you clonedSeemercurial_extension_utilsdocumentation for more details on
Windows installation.NoteDirectory names matter. Ifmercurial_path_pattern.pycan’t findmercurial_extension_utils.pyin system path, it looks for it in
its own directory, in../mercurial_extension_utils, and in../extension_utils.8Related extensionsSchemes Extension, distributed together with Mercurial, makes it
possible to simplify repository URLs. For example, you can write:hg clone bb://Mekk/mercurial-path_pattern(bbis schemes alias expanding to BitBucket url).While both Path Pattern and Schemes are related to path management,
they target different habits. Schemes is particularly useful
for people making frequent ad-hoc clones, Path Pattern is about
keeping consistent synchronized repository hierarchies. With Schemes,
urls you type are shorter and less error-prone, with Path Pattern
you don’t type them at all as Mercurial guesses them for you.Both can cooperate, schemes aliases can be used in pattern definitions:[path_pattern]
bitb.local = ~/sources/{below}
bitb.remote = bb://Mekk/{below:/=-}will work (as long as schemes extension is enabled).9HistorySeeHISTORY.rst10Repository, bug reports, enhancement suggestionsDevelopment is tracked on HeptaPod, seehttps://foss.heptapod.net/mercurial/mercurial-path_pattern/Use issue tracker there for bug reports and enhancement
suggestions.Thanks toOctobusandClever Cloudfor hosting this service.11Additional notesInformation about this extension is also available
on Mercurial Wiki:http://mercurial.selenic.com/wiki/PathPatternExtensionCheck alsoother Mercurial extensions I wrote.