Internal Vrs External Path to Sub-repository - mercurial

I have a repository for an application A which is controlled by mercurial and a library B which is also controlled by mercurial. In the application A's repository it has the sub-repository mapped to library B's repository using the path central repository path ssh://user#1.2.3.4/B. This works well enough for our internal development, but we need access externally, but we can't use the domain name as our router bulks. Is it possible to have the sub-repository defined as something like:
[internal]
B = ssh://user#1.2.3.4/B
[external]
B = ssh://user#domain/B

The only method that I was able to find, which sort of works, is to have each developer set the path for the repository. So for the example above, the path for an internal developer would remain unchanged, but the external developers would change their sub-paths to:
ssh://user#1.2.3.4/B = ssh://user#domain/B

Related

How to preserve Mercurial subrepo remappings across clone/pull?

I'm trying to set up subrepo remapping in Mercurial (2.1.1) to account for subrepo paths that may change in the future. I've been able to get the [subpaths] key to be read and processed properly when it is specified in the .hgrc file. However, when I clone or pull from that repository, the .hgrc file is not copied and thus the subrepo remaps are not brought over to the destination repository.
My first thought after looking at the SubrepoRemappingPlan was to put the [subpaths] in a .hg/subpaths file, which is supposed to be copied on clones/pulls. However, it turns out this functionality has been obsoleted, and the subpaths file has been replaced with a more general configuration-sharing mechanism via the Projrc extension.
The problems with the Projrc solution, though, are:
it's a separate extension that all team members need to have installed and enabled
additional configuration needs to be done to tell Projrc where it is allowed to pull from (and what it is allowed to pull), for security reasons
So, my question is, is there any built-in mechanism in Mercurial for implementing subrepo mapping that is preserved across clones/pulls?
Generally, the best method is to use relative paths for subrepos (see http://mercurial.aragost.com/kick-start/en/subrepositories/) so they never have to be remapped at all.
Example:
+ main repo
+ subrepo
+ .hgsub
.hgsub:
subrepo = subrepo
Adding the subpaths mapping to your .hgsub file should do the trick (as described in the mercurial wiki).

Mercurial hg serve multiple repositories

I am setting up a central mercurial server, and want to host multiple repositories. Every web page I look at about this says to set up a config file that looks like this:
[collections]
repos/ = repos/
Where /repos is the folder and /repos is the path to use in the URL.
My question is which /repos is which??? I may want to use a name that is not the same as the path, as in:
[collections]
A/ = B/
Is A the physical path or the url path? Such a simple question you would think would have been answered, but I could not find any nontrivial examples.
Ok, I got it. This is on Windows, and here is everything that I need in the hg.conf file:
[paths]
foo = C:\Data\repositories-hg/foo-hg
bar = C:\Data\repositories-hg/bar-hg
This lets met access the repo at the location C:\Data\repositories-hg/foo-hg as:
http://server:8000/foo
Therefore A is the url alias and B is the physical path. There's of course more to set up, but this accomplishes what need for now.

How do I use the [subpaths] section in .hgsub to remap a local subrepo for use in bitbucket

NOTE: Since I'm new they won't let me post links, which means all the config files will have improperly formatted URLs. This is simply to get around stackoverflow's limitations, I have used the correct URL in practice.
I tried to setup a subrepo, let's call it A/B. So that cloning works properly, I wanted a normal relative path to put it inside the repository, so logically I had .hgsub:
A/B = A/B
However when trying to push this into bitbucket I get the usual 404 (NOT FOUND) error because on bitbucket B cannot be local, and is actually another project (http s://username#bitbucket.org/username/B)
So then I said, OK just to make bitbucket work I can put .hgsub:
A/B = https://username#bitbucket.org/username/B
However, I recently found out that supposedly there was a workaround here: https://www.mercurial-scm.org/wiki/Subrepository where you use the [subpaths] section so that cloning locally works normal, but bitbucket will request the special path for the project.
So I tried copying their instructions. .hgsub:
A/B = A/B
[subpaths]
https://username#bitbucket.org/username/project/A/B = https://username#bitbucket.org/username/B
But I get the same 404 error. Supposedly whenever it sees https://username#bitbucket.org/username/project/A/B, it will instead remap to the latter https://username#bitbucket.org/username/B which will work. However, this doesn't appear to be the case. I have also tried without putting the username# at the beginning.
Any help would be much appreciated. :)
Turns out I think I was testing at a different repo so it wasn't grabbing the match. Here's the working config for all those interested:
.hgsub:
A/B = A/B
[subpaths]
bitbucket\.org/username/projectname/A/B = bitbucket.org/username/B
It looks like your subpaths config is incorrect. The string on the left side must be a pattern that matches an entry in your .hgsub. I think you want something like:
[subpaths]
A/B = https://username#bitbucket.org/username/B
More info may be found in:
SubrepoRemappingPlan
The subpaths section of hg help hgrc:
Here is an excerpt from the hgrc help:
Defines subrepositories source locations rewriting rules of the form:
<pattern> = <replacement>
Where "pattern" is a regular expression matching the source and
"replacement" is the replacement string used to rewrite it. Groups can be
matched in "pattern" and referenced in "replacements". For instance:
http://server/(.*)-hg/ = http://hg.server/\1/
rewrites "http://server/foo-hg/" into "http://hg.server/foo/".

How do I set up a hook in HG / Mercurial that gets dictated by the repository?

I have a need for a hook to run after update (this will build the solution they have updated) and I don't want to have to add that hook manually for each person that clones my central repository.
When someone first clones my central repository, is it possible to include hooks into that clone? It seems that the .hgrc file doesn't get cloned automatically.
I did read about site-wide hooks, but as far as I understand it, they work on each created repository, where I only want to have the hooks on some repos.
As Rudi already said, this is (thankfully) not possible for security reasons.
However, you can reduce the per-clone workload to set up hooks manually: Ship the hook scripts as part of your repository, e.g. in a directory .hghooks, and additionally include a script in your repo which sets up these hooks in a clone's hgrc. Each coworker now only needs to call the setup script once per clone.
This is not possible, since that hooks do not propagate to clones is a security measure. If this were possible, one could set up a rouge repository, which runs arbitrary commands on any machine where the repo is cloned.
See http://hgbook.red-bean.com/read/handling-repository-events-with-hooks.html#id402330 for more details.
This will allow for centralised per-repo hooks, with a single setup step per user. It will however cause problems for users who are disconnected from the network. An alternative if you tend to have disconnected developers (or ones over high-latency/low bandwidth links) would be to have a repo containing the hooks, and set up each user's global hgrc to point into that repo (and require regular pulls from a central hook repo).
Note that I treat the ID of the first commit as the "repo ID" - this assumes that the first commit in each repository is unique in some way - contents or commit message. If this is not the case you could do the same thing but applying it over the first N commits - but you would then have to account for repos that have fewer than N commits - can't just take repo[:5] for example as newer commits would then change the repo ID. I'd personally suggest that the first commit should probably be a standard .ignore file with a commit message unique to that repo.
Have a central shared_hgrc file, accessible from a network share (or in a hook repo).
Each user's global hgrc has:
%include /path/to/shared_hgrc
Create a shared repository of python hook modules. The hooks must be written in python.
Create your hook functions. In each function, check which repo the hook has been called on by checking the ID of the first commit:
# hooktest.py
import mercurial.util
FOOBAR_REPO = 'b88c69276866d73310be679b6a4b40d875e26d84'
ALLOW_PRECOMMIT_REPOS = set((
FOOBAR_REPO,
))
def precommit_deny_if_wrong_repo(ui, repo, **kwargs):
"""Aborts if the repo is not allowed to do this.
The repo ID is the ID of the first commit to the repo."""
repo_id = repo[0].hex().lower()
if repo_id not in ALLOW_PRECOMMIT_REPOS:
raise mercurial.util.Abort('Repository denied: %s' % (repo_id,))
ui.status('Repository allowed: %s\n' % (repo_id,))
def precommit_skip_if_wrong_repo(ui, repo, **kwargs):
"""Skips the hook if the repo is not allowed to do this.
The repo ID is the ID of the first commit to the repo."""
repo_id = repo[0].hex().lower()
if repo_id not in ALLOW_PRECOMMIT_REPOS:
ui.debug('Repository hook skipped: %s\n' % (repo_id,))
return
ui.status('Repository hook allowed: %s\n' % (repo_id,))
In the shared_hgrc file, set up the hooks you need (make sure you qualify the hook names to prevent conflicts):
[hooks]
pre-commit.00_skip = python:/path/to/hooktest.py:precommit_skip_if_wrong_repo
pre-commit.01_deny = python:/path/to/hooktest.py:precommit_deny_if_wrong_repo
As #Rudi said first, it can't be done for security reasons.
With some prior setup you can make it so that hooks are run on clone, but putting a hook with a repo-relative path in /etc/mercurial or in each user's ~/.hgrc, which in a corporate setting can be done via your system management tools or by building a custom Mercurial installer. In a non-corporate setting follow #Oben's advice and provide the scripts and a readme.

Mercurial workflow with subrepositories and offline clones?

I'm offline a lot.
So normally, I use one local clone as a "hub" for features, bugs, etc.
hg clone local-hub bug-123
Works offline. Cool.
Can I use a similar workflow if that project contains remote subrepositories?
Because, if .hgsub says
sub/shared = http://server/hg/shared
hg clone says
abort: error: getaddrinfo failed
Note that once the clone is created (while connected), push and pull will use the path in the subrepo's hgrc (instead of the location in .hgsub). So I can point this to a local clone and everything is cool.
But clone looks at .hgsub (as it's supposed to). So if the "blessed" subrepo is on a server, I can't create new clones offline, even though the files I need are right there.
This is a problem, right?
Ideally whomever set up the project uses relative URLs in their .hgsub file like this:
sub/shared = ../shared
and then, of course, actually makes shared a sibling of the main repo. Then as long as you have cloned down the main repo and the subs (as siblings) then everything will work out.
If they've used absolute URLs in their .hgsub file you can work around it using the subpaths section in your .hgrc like this:
[subpaths]
http://server/hg/shared = ../shared
which provides a translation layer in your client.
The canonical way to use subrepositories is to have X = X paths in the .hgsub file:
sub/shared = sub/shared
That way a clone will structurally look just like the original -- and so you can use the clone to make further (local!) clones.
However, this is not always possible, for example, Bitbucket wont let you create the nested repositories on their server. In that case, the ../X style paths in the .hgsub file is better, and you can use the subpaths configuration section to translate these paths into paths you can use locally.