3 Commits
v1.0.2 ... test

Author SHA1 Message Date
Felipe Contreras
e71a8963af test: fix hg version check
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-06-02 18:38:59 -05:00
Felipe Contreras
f20dbc33c3 Add extra verbosity
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-06-02 18:29:14 -05:00
Felipe Contreras
e4aeae6d4b test: skip tests with broken hg-git compatibility
https://bitbucket.org/durin42/hg-git/issue/115/

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
2014-06-02 18:16:49 -05:00
19 changed files with 581 additions and 4512 deletions

View File

@@ -1,20 +1,26 @@
dist: xenial
language: minimal
language: python
cache:
directories:
- $HOME/.cache/git-remote-hg
install:
- if [ "$HG_VERSION" != "dev" ];
then pip install -q Mercurial${HG_VERSION+==$HG_VERSION};
else pip install -q http://selenic.com/repo/hg/archive/tip.tar.gz;
fi
- pip install -q dulwich hg-git || true
before_script:
- hg --version || true
- pip show hg-git dulwich
script:
- ./tools/check-versions hg:$HG_VERSION
- export TEST_OPTS='-v'
- make test
matrix:
include:
- env:
- env: HG_VERSION=@
- env: HG_VERSION=5.0
- env: HG_VERSION=4.9
- env: HG_VERSION=4.8
- env: HG_VERSION=4.7
- env: HG_VERSION=4.6
- env: HG_VERSION=4.5
- env: HG_VERSION=2.9.1
- env: HG_VERSION=2.8.2
- env: HG_VERSION=2.7.2
- env: HG_VERSION=3.0
- env: HG_VERSION=dev
- python: 2.7
- python: 2.6

View File

@@ -26,16 +26,4 @@ install-doc: doc
install -d -m 755 $(D)$(mandir)/
install -m 644 doc/git-remote-hg.1 $(D)$(mandir)/git-remote-hg.1
pypi:
version=`git describe --tags ${REV}` && \
sed -i "s/version = .*/version = '$$version'[1:]/" setup.py
-rm -rf dist build
python setup.py sdist bdist_wheel
pypi-upload:
twine upload dist/*
pypi-test:
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
.PHONY: all test install install-doc clean pypy pypy-upload
.PHONY: all test install install-doc clean

View File

@@ -9,38 +9,12 @@ git clone "hg::http://selenic.com/repo/hello"
To enable this, simply add the 'git-remote-hg' script anywhere in your `$PATH`:
--------------------------------------
wget https://raw.github.com/mnauw/git-remote-hg/master/git-remote-hg -O ~/bin/git-remote-hg
wget https://raw.github.com/felipec/git-remote-hg/master/git-remote-hg -O ~/bin/git-remote-hg
chmod +x ~/bin/git-remote-hg
--------------------------------------
In Windows, you also need to put and an NTFS symbolic link named `python2.exe` somewhere
on your `$PATH` pointing to your Python 2 executable:
--------------------------------------
mklink <path to link> <path to python.exe>
--------------------------------------
That's it :)
Obviously you will need Mercurial installed.
****
At present, this "working copy"/fork <<add-features, adds the following features>>
(and I would prefer it is indeed rather a "working copy"
to be appropriately merged upstream):
* eliminates a number of <<limitations, limitations>> as mentioned below
* properly annotates copy/rename when pushing new commits to Mercurial
* adds a 'git-hg-helper' script than can aid in the git-hg interaction workflow
* provides enhanced bidirectional git-hg safety
* avoids clutter of `refs/hg/...` by keeping these implementation details really private
* more robust and efficient fetching, especially so when fetching or cloning from multiple
Mercurial clones which will only process changesets not yet fetched from elsewhere
(as opposed to processing everything all over again)
See sections below or sidemarked notes for more details.
****
== Configuration ==
If you want to see Mercurial revisions as Git commit notes:
@@ -115,23 +89,6 @@ However, some of these features require very new versions of 'git-remote-hg',
so you might have better luck simply specifying the username and password in
the URL.
=== Submodules ===
Hg repositories can be used as git submodule, but this requires to allow the hg procotol to be used by git submodule commands:
--------------------------------------
git config protocol.hg.allow always
--------------------------------------
Or adding manually the following to your git configuration file:
--------------------------------------
[protocol "hg"]
allow = always
--------------------------------------
This can be done per-repository, every time after a clone, or globally in the global .gitconfig (using the --global command-line option).
=== Caveats ===
The only major incompatibility is that Git octopus merges (a merge with more
@@ -148,31 +105,17 @@ Closed branches are not supported; they are not shown and you can't close or
reopen. Additionally in certain rare situations a synchronization issue can
occur (https://github.com/felipec/git/issues/65[Bug #65]).
[[limitations]]
Limitations of the remote-helpers' framework apply. In particular, these
commands don't work:
* `git push origin :branch-to-delete`
****
Another limitation is that if `git log` reports a rename, this will not survive
the push and Mercurial will not be aware of a rename (and similarly so for copy).
Though Mercurial would know about it if you *manually* ran `git-format-patch`
followed by a `hg apply -s`, which is not the nice way to go obviously.
Actually, scratch the limitations above ascribed to the remote-helpers framework.
They are not limitations of the framework, but are due to how the original
implementation of 'git-remote-hg' interacts with it.
Using the remote-helpers framework in only a slightly different way has none
of the above limitations. See the <<no-limitations, relevant section>>
below for more details.
****
* `git push origin old:new` (it will push 'old') (patches available)
* `git push --dry-run origin branch` (it will push) (patches available)
== Other projects ==
There are other 'git-remote-hg' projects out there, do not confuse this one,
this is the one distributed officially by the Git project
(_though actually no longer so nowadays_):
this is the one distributed officially by the Git project:
* https://github.com/msysgit/msysgit/wiki/Guide-to-git-remote-hg[msysgit's git-remote-hg]
* https://github.com/rfk/git-remote-hg[rfk's git-remote-hg]
@@ -180,240 +123,7 @@ this is the one distributed officially by the Git project
For a comparison between these and other projects go
https://github.com/felipec/git/wiki/Comparison-of-git-remote-hg-alternatives[here].
[[no-limitations]]
== Limitations (or not) ==
If interested in some of technical details behind this explanation, then also
see the relevant section in 'git-remote-hg' manpage. Otherwise, the general
idea is presented here.
More precisely and simply, the <<limitations, mentioned limitations>> are indeed
limitations of the `export` capability of
https://www.kernel.org/pub/software/scm/git/docs/gitremote-helpers.html[gitremote-helpers(1)]
framework. However, the framework also supports a `push` capability and when this
is used appropriately in the remote helper the aforementioned limitations do not apply.
In the case of `export` capability, git-core will internally invoke `git-fast-export`
and the helper will process this data and hand over generated changesets to Mercurial.
In the case of `push` capability, git informs the helper what (refs) should go where,
and the helper is free to ponder about this and take the required action, such as
to invoke `git-fast-export` itself (with suitable options) and process its output
the same way as before (and over to Mercurial).
And so;
* `git push origin :branch-to-delete` will delete the bookmark `branch-to-delete` on remote
* `git push --dry-run origin branch` will not touch the remote
(or any local state, except for local helper proxy repo)
* `git push origin old:new` will push `old` onto `new` in the remote
* `git push origin <history-with-copy/rename>` will push copy/rename aware Mercurial revisions
To tweak how 'git-remote-hg' decides on a copy/rename, use e.g:
--------------------------------------
% git config --global remote-hg.fast-export-options '-M -C -C'
--------------------------------------
[[add-features]]
== Additional Features ==
=== Miscellaneous Tweaks ===
Other than <<no-limitations, removing the limitations>> as mentioned above,
a number of issues (either so reported in
https://github.com/felipec/git-remote-hg/issues[issue tracking] or not) have been
addressed here, e.g. notes handling, `fetch --prune` support, correctly fetching
after a `strip` on remote repo, tracking remote changes to import (if any) in a
safe, robust and efficient way, etc. Some of these have been highlighted above.
For example, the `refs/hg/...` refs are really an implementation detail
that need not clutter up the (visible) ref space. So, in as much as they
are still relevant, these are now kept elsewhere out of sight.
If somehow your workflow relies on having these in the old place:
--------------------------------------
% git config --global remote-hg.show-private-refs true
--------------------------------------
More importantly, a significantly more efficient workflow is achieved using
one set of shared marks files for all remotes (which also forces a local repo
to use an internal proxy clone).
The practical consequence is that fetching from a newly added remote hg repo
does not require another (lengthy) complete import
(as the original clone) but will only fetch additional changesets (if any).
The same goes for subsequent fetching from any hg remote; what was fetched
and imported from some remote need not be imported again from another.
Operating in this shared mode also has the added advantage
of correctly pushing after a `strip` on a remote.
This shared-marks-files behaviour is the default on a fresh repo clone. It can
also be enabled on an existing one by the following setting.
--------------------------------------
% git config --global remote-hg.shared-marks true
--------------------------------------
Note, however, that one should then perform a fetch from each relevant remote
to fully complete the conversion (prior to subsequent pushing).
Some Mercurial names (of branches, bookmarks, tags) may not be a valid git
refname. See e.g. `man git-check-ref-format` for a rather involved set of rules.
Moreover, while a slash `/` is allowed, it is not supported to have both a `parent`
and `parent/child` branch (though only the latter is allowed). Even though
it is not quite (bidirectionally) safe, a (percentage) URL encoding
(with some additional twist) is performed to obtain sane git refnames, at least
so for most cases. If some nasty cases still slip through, then likely only
a few instances (out of a whole Mercurial repo) are
problematic. This could be handled by a single-branch clone and/or configuring
a suitable refspec. However, it might be more convenient to simply filter out a
few unimportant pesky cases, which can be done by configuring a regural
expression in following setting:
--------------------------------------
% git config remote-hg.ignore-name nasty/nested/name
--------------------------------------
Recall also that a config setting can be provided at clone time
(command line using `--config` option).
--------------------------------------
% git config --global remote-hg.remove-username-quotes false
--------------------------------------
By default, for backwards compatibility with earlier versions,
git-remote-hg removes quotation marks from git usernames
(e.g. 'Raffaello "Raphael" Sanzio da Urbino <raphael@example.com>'
would become 'Raffaello Raphael Sanzio da Urbino
<raphael@example.com>'). This breaks round-trip compatibility; a git
commit by an author with quotes would become an hg commit without,
and if re-imported into git, would get a different SHA1.
To restore round-trip compatibility (at the cost of backwards
compatibility with commits converted by older versions of
git-remote-hg), turn 'remote-hg.remove-username-quotes' off.
=== Helper Commands ===
Beyond that, a 'git-hg-helper' script has been added that can aid in the git-hg
interaction workflow with a number of subcommands that are not in the purview of
a remote helper. This is similar to e.g. 'git-svn' being a separate program
altogether. These subcommands
* provide conversion from a hg changeset id to a git commit hash, or vice versa
* provide consistency and cleanup maintenance on internal `git-remote-hg` metadata marks
* provide optimization of git marks of a fetch-only remote
See the helper script commands' help description for further details.
It should simply be installed (`$PATH` accessible) next to 'git-remote-hg'.
Following git alias is probably also convenient as it allows invoking the helper
as `git hg`:
--------------------------------------
% git config --global alias.hg '!git-hg-helper'
--------------------------------------
With that in place, running `git hg gc <remote>` after initial fetch from (large)
<remote> will save quite some space in the git marks file. Not to mention some time
each time it is loaded and saved again (upon fetch). If the remote is ever pushed
to, the marks file will similarly be squashed, but for a fetch-only <remote>
the aforementioned command will do. It may also be needed to run aforementioned
command after a `git gc` has been performed. You will notice the need
when `git-fast-import` or `git-fast-export` complain about not finding objects ;-)
In addition, the helper also provides support routines for `git-remote-hg` that
provide for increased (or at least safer) git-hg bidirectionality.
Before explaining how it helps, let's first elaborate on what is really
meant by the above _bidirectionality_ since it can be regarded in 2 directions.
From the git repo point of view, one can push to a hg repo and then fetch (or
clone) back to git. Or one could have fetched a changeset from some hg repo and
then push this back to (another) hg clone. So what happens in either case? In the
former case, from git to hg and then back, things work out ok whether or not in
hg-git compatibility mode. In the latter case, it is very likely (but
ultimately not guaranteed) that it works out in hg-git compatibility mode, and far
less likely otherwise.
Most approaches on bidirectionality try to go for the "mapping" way.
That is, find a way to map all Mercurial (meta)data somewhere into git;
in the commit message, or in non-standard ways in extra headers in commit objects
(e.g. the latest hg-git approach). The upside of this is that such a git repo can be
cloned to another git repo, and then one can push back into hg which will/should
turn out ok. The downside is setting up such a mapping in the first place,
avoiding the slightest error in translating authors, timestamps etc,
and maintaining all that whenever there is some Mercurial API/ABI breakage.
The approach here is to consider a typical git-hg interaction workflow and to
ensure simple/safe bidirectionality in such a setting. That is, you are (obviously)
in a situation having to deal with some Mercurial repo and quite probably
with various clones as well. The objective is to fetch from these repos/clones,
work in git and then push back. And in the latter case, one needs to make sure
that hg changesets from one hg clone end up *exactly* that way in another hg
clone (or the git-hg bridge usage might not be so appreciated). Such pushes are
probably not recommended workflow practice, but no accidents or issues should
arise from any push in these circumstances. There is less interest in this setting,
however, for (git-wise) cloning around the derived git repo.
Now, depending on your workflow and to ensure the above behaves well,
following setting can be enabled as preferred:
--------------------------------------
% git config --global remote-hg.check-hg-commits fail
% git config --global remote-hg.check-hg-commits push
--------------------------------------
If not set, the behaviour is as before; pushing a commit based on hg changeset
will again transform the latter into a new hg changeset which may or may not
match the original (as described above).
If set to `fail`, it will reject and abort the push.
If set to `push`, it will re-use the original changeset in a Mercurial native
way (rather than creating a new one). The latter guarantees the changeset ends
up elsewhere as expected (regardless of conversion mapping or ABI).
Note that identifying and re-using the hg changeset relies on metadata
(`refs/notes/hg` and marks files) that is not managed or maintained by any
git-to-git fetch (or clone).
As such (and as said), this approach aims for plain-and-simple safety, but only
within a local scope (git repo).
=== Mercurial Subrepository Support ===
Both Git and Mercurial support a submodule/subrepo system.
In case of Git, URLs are managed in `.gitmodules`, submodule state is tracked
in tree objects and only Git submodules are supported.
Mercurial manages URLs in `.hgsub`, records subrepo state in `.hgsubstate` and
supports Git, Mercurial and Subversion subrepos (at time of writing).
Merely the latter diversity in subrepo types shows that somehow mapping Mercurial
"natively" to git submodules is not quite evident. Moreover, while one might
conceivably devise such a mapping restricted to git and hg subrepos, any such would
seem error-prone and fraught with all sorts of tricky cases and inconvenient
workflow handling (innovative robust suggestions are welcome though ...)
So, rather than overtaking the plumbing and ending up with stuffed drain further on,
the approach here is (again) to keep it plain-and-simple. That is, provide some
git-ish look-and-feel helper script commands for setting up and manipulating
subrepos. And so (if the alias mentioned above has been defined), `git hg sub`
provides commands similar to `git submodule` that accomplish what is otherwise
taken care of by the Mercurial subrepo support.
The latter is obviously extended to be git-aware in that e.g. a Mercurial subrepo
is cloned as a git-hg subrepo and translation back-and-forth between hg changeset id
and git commit hash is also performed where needed. There is no support though
for Subversion subrepos.
As with the other commands, see the help description for the proper details,
but the following example session may clarify the principle:
--------------------------------------
% git clone hg::hgparentrepo
# bring in subrepos in proper location:
% git hg sub update
# do some work
% git pull --rebase origin
# update subrepo state:
% git hg sub update
# do work in subrepo and push
% ( cd subrepo && git push origin HEAD:master )
# fetch to update refs/notes/hg (or enable remote-hg.push-updates-notes)
% ( cd subrepo && git fetch origin )
# update .hgsubstate to subrepo HEAD:
% git hg sub upstate
% git add .hgsubstate
# add more, commit and push as intended
--------------------------------------
Note that the refspec `HEAD:master` is needed if working with detached `HEAD`
in subrepo, and that pushing such refspec is actually supported now in a git-hg subrepo
as explained <<no-limitations, earlier>>.
== Contributing ==
Please file an issue with some patches or a pull-request.
Send your patches to the mailing list git-fc@googlegroups.com (no need to
subscribe).

View File

@@ -58,50 +58,6 @@ If you want 'git-remote-hg' to be compatible with 'hg-git', and generate exactly
% git config --global remote-hg.hg-git-compat true
--------------------------------------
If you would like (why?) the old behaviour (export capability)
where various limitations apply:
--------------------------------------
% git config --global remote-hg.capability-push false
--------------------------------------
In the new behaviour, performing a git push will make git search for and detect
file rename and copy and turn this into Mercurial commit metadata. To tweak how this
detection happens, e.g. have it search even more:
--------------------------------------
% git config --global remote-hg.fast-export-options '-M -C -C'
--------------------------------------
The default otherwise is simply `-M -C`. See also e.g.
https://www.kernel.org/pub/software/scm/git/docs/git-log.html[git-log(1) manpage]
for more details on the options used to tweak this.
As the old refs/hg/... are actually an implementation detail, they are now
maintained not so visibly. If that, however, would be preferred:
--------------------------------------
% git config --global remote-hg.show-private-refs true
--------------------------------------
Use of shared marks files is the default in a new repo, but can also be enabled
for an existing repo:
--------------------------------------
% git config --global remote-hg.shared-marks true
--------------------------------------
Note that one should perform a fetch from each remote to properly complete the
conversion to shared marks files.
Mercurial name(s) (of a branch or bookmark) that are not a valid git refname,
can be ignored by configuring a suitable regular expression, e.g. avoiding
the invalid '~'
--------------------------------------
% git config --global remote-hg.ignore-name ~
--------------------------------------
NOTES
-----
@@ -163,49 +119,3 @@ would only see the latest head.
Closed branches are not supported; they are not shown and you can't close or
reopen. Additionally in certain rare situations a synchronization issue can
occur (https://github.com/felipec/git/issues/65[Bug #65]).
TECHNICAL DISCUSSION
--------------------
As `git-remote-hg` is a developer tool after all, it might be interesting to know a
bit about what is going on behind the scenes, without necessarily going into all the
details.
So let's first have a look in the `.git/hg` directory, which typically
contains a subdirectory for each remote Mercurial repo alias, as well as a `.hg`
subdirectory. If the Mercurial repo is a local one, it will (again typically)
only contain a `marks-git` and a `marks-hg` file. If the repo is a remote one,
then the `clone` contains, well, a local clone of the remote. However, all
these clones share storage through the `.hg` directory mentioned previously (so
they do not add up separately). During a fetch/push, the local (proxy) repo is
used as an intermediate stage. If you would also prefer such an intermediate
stage for local repos, then setting the environment variable
`GIT_REMOTE_HG_TEST_REMOTE` will also use a proxy repo clone for a local repo.
As for the marks files, `marks-git` is created and used by `git-fast-export`
and `git-fast-import` and contains a mapping from mark to commit hash, where a
mark is essentially a plain number. `marks-hg` similarly contains a (JSON) based
mapping between such mark and hg revision hash. Together they provide for a
(consistent) view of the synchronization state of things.
When operating with shared-marks files, the `marks-git` and `marks-hg` files
are shared among all repos. As such, they are then found in the `.git/hg`
directory (rather than a repo subdirectory).
As there is really only one hg repository
(the shared storage "union bag" in `.git/hg/.hg`), only 1 set of marks files
should track the mapping between commit hash and revision hash.
Each individual remote then only adds some metadata (e.g regarding heads).
Upon a fetch, the helper uses the `marks-hg` file to decide what is already present
and what not. The required parts are then retrieved from Mercurial and turned
into a `git-fast-import` stream as expected by `import` capability of
https://www.kernel.org/pub/software/scm/git/docs/gitremote-helpers.html[gitremote-helpers(1)].
Upon a push, the helper has specified the `push` capability in the new approach, and
so git will provide a list of refspecs indicating what should go where.
If the refspecs indicates a remote delete, it is performed appropriately the Mercurial way.
If it is a regular push, then git-fast-export is invoked (using the existing `marks-git`)
and the stream is processed and turned into Mercurial commits (along with bookmarks, etc).
If the refspec specifies a `src:dest` rename, then the requested remote refname is tracked
accordingly. If a dry-run is requested, no remote is touched and no (marks) state of
the run is retained.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +0,0 @@
# git-remote-hg setuptools script
import setuptools
import subprocess
import sys
import os
# strip leading v
version = 'v1.0.2'[1:]
# check for released version
assert (len(version) > 0)
assert (version.find('-') < 0)
long_description = \
"""
'git-remote-hg' is a gitremote protocol helper for Mercurial.
It allows you to clone, fetch and push to and from Mercurial repositories as if
they were Git ones using a hg::some-url URL.
See the homepage for much more explanation.
"""
CLASSIFIERS = [
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"License :: OSI Approved",
"License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
]
setuptools.setup(name="git-remote-hg",
version=version,
author="Mark Nauwelaerts",
author_email="mnauw@users.sourceforge.net",
url="http://github.com/mnauw/git-remote-hg",
description="access hg repositories as git remotes",
long_description=long_description,
license="GPLv2",
keywords="git hg mercurial",
scripts=["git-remote-hg", "git-hg-helper"],
classifiers=CLASSIFIERS
)

View File

@@ -1,6 +1,6 @@
RM ?= rm -f
T = main.t main-push.t bidi.t helper.t
T = $(wildcard *.t)
TEST_DIRECTORY := $(CURDIR)
export TEST_DIRECTORY

View File

@@ -17,7 +17,7 @@ then
test_done
fi
if ! python -c 'import mercurial' > /dev/null 2>&1
if ! python2 -c 'import mercurial' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
@@ -51,7 +51,7 @@ hg_push () {
}
hg_log () {
hg -R $1 log --debug
hg -R $1 log --graph --debug
}
setup () {
@@ -204,9 +204,8 @@ test_expect_success 'hg branch' '
: Back to the common revision &&
(cd hgrepo && hg checkout default) &&
# fetch does not affect phase, but pushing now does
hg_log hgrepo | grep -v phase > expected &&
hg_log hgrepo2 | grep -v phase > actual &&
hg_log hgrepo > expected &&
hg_log hgrepo2 > actual &&
test_cmp expected actual
'
@@ -233,47 +232,7 @@ test_expect_success 'hg tags' '
) &&
hg_push hgrepo gitrepo &&
# pushing a fetched tag is a problem ...
{ hg_clone gitrepo hgrepo2 || true ; } &&
# fetch does not affect phase, but pushing now does
hg_log hgrepo | grep -v phase > expected &&
hg_log hgrepo2 | grep -v phase > actual &&
test_cmp expected actual
'
test_expect_success 'test timezones' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
git init -q gitrepo &&
cd gitrepo &&
echo alpha > alpha &&
git add alpha &&
git commit -m "add alpha" --date="2007-01-01 00:00:00 +0000" &&
echo beta > beta &&
git add beta &&
git commit -m "add beta" --date="2007-01-01 00:00:00 +0100" &&
echo gamma > gamma &&
git add gamma &&
git commit -m "add gamma" --date="2007-01-01 00:00:00 -0100" &&
echo delta > delta &&
git add delta &&
git commit -m "add delta" --date="2007-01-01 00:00:00 +0130" &&
echo epsilon > epsilon &&
git add epsilon &&
git commit -m "add epsilon" --date="2007-01-01 00:00:00 -0130"
) &&
hg_clone gitrepo hgrepo &&
git_clone hgrepo gitrepo2 &&
hg_clone gitrepo2 hgrepo2 &&
hg_clone gitrepo hgrepo2 &&
hg_log hgrepo > expected &&
hg_log hgrepo2 > actual &&

View File

@@ -1,547 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2016 Mark Nauwelaerts
#
# Base commands from hg-git tests:
# https://bitbucket.org/durin42/hg-git/src
#
test_description='Test git-hg-helper'
test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
. "$TEST_DIRECTORY"/test-lib.sh
if ! test_have_prereq PYTHON
then
skip_all='skipping remote-hg tests; python not available'
test_done
fi
if ! python -c 'import mercurial' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
setup () {
cat > "$HOME"/.hgrc <<-EOF &&
[ui]
username = H G Wells <wells@example.com>
[extensions]
mq =
strip =
[subrepos]
git:allowed = true
EOF
GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" &&
GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" &&
export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
}
setup
setup_repos () {
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero
) &&
git clone hg::hgrepo gitrepo
}
test_expect_success 'subcommand help' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repos &&
(
cd gitrepo &&
test_expect_code 2 git-hg-helper help 2> ../help
)
# remotes should be in help output
grep origin help
'
git config --global remote-hg.shared-marks false
test_expect_success 'subcommand repo - no local proxy' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repos &&
(
cd hgrepo &&
pwd >../expected
) &&
(
cd gitrepo &&
git-hg-helper repo origin > ../actual
) &&
test_cmp expected actual
'
git config --global --unset remote-hg.shared-marks
GIT_REMOTE_HG_TEST_REMOTE=1 &&
export GIT_REMOTE_HG_TEST_REMOTE
test_expect_success 'subcommand repo - with local proxy' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repos &&
(
cd gitrepo &&
export gitdir=`git rev-parse --git-dir`
# trick to normalize path
( cd $gitdir/hg/origin/clone && pwd ) >../expected &&
( cd `git-hg-helper repo origin` && pwd ) > ../actual
) &&
test_cmp expected actual
'
test_expect_success 'subcommands hg-rev and git-rev' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repos &&
(
cd gitrepo &&
git rev-parse HEAD > rev-HEAD &&
test -s rev-HEAD &&
git-hg-helper hg-rev `cat rev-HEAD` > hg-HEAD &&
git-hg-helper git-rev `cat hg-HEAD` > git-HEAD &&
test_cmp rev-HEAD git-HEAD
)
'
test_expect_success 'subcommand gc' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero
echo one > content &&
hg commit -m one &&
echo two > content &&
hg commit -m two &&
echo three > content &&
hg commit -m three
) &&
git clone hg::hgrepo gitrepo &&
(
cd hgrepo &&
hg strip -r 1 &&
echo four > content &&
hg commit -m four
) &&
(
cd gitrepo &&
git fetch origin &&
git reset --hard origin/master &&
git gc &&
git-hg-helper gc --check-hg origin > output &&
cat output &&
grep "hg marks" output &&
grep "git marks" output
)
'
test_expect_success 'subcommand [some-repo]' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repos &&
(
cd hgrepo &&
echo one > content &&
hg commit -m one
) &&
(
cd gitrepo &&
git fetch origin
) &&
hg log -R hgrepo > expected &&
# not inside gitrepo; test shared path handling
GIT_DIR=gitrepo/.git git-hg-helper origin log > actual
test_cmp expected actual
'
setup_repo () {
kind=$1 &&
repo=$2 &&
$kind init $repo &&
(
cd $repo &&
echo zero > content_$repo &&
$kind add content_$repo &&
$kind commit -m zero_$repo
)
}
check () {
echo $3 > expected &&
git --git-dir=$1/.git log --format='%s' -1 $2 > actual &&
test_cmp expected actual
}
check_branch () {
if test -n "$3"
then
echo $3 > expected &&
hg -R $1 log -r $2 --template '{desc}\n' > actual &&
test_cmp expected actual
else
hg -R $1 branches > out &&
! grep $2 out
fi
}
test_expect_success 'subcommand sub initial update (hg and git subrepos)' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repo hg hgrepo &&
(
cd hgrepo &&
setup_repo hg sub_hg_a &&
setup_repo hg sub_hg_b &&
setup_repo git sub_git &&
echo "sub_hg_a = sub_hg_a" > .hgsub &&
echo "sub_hg_b = sub_hg_b" >> .hgsub &&
echo "sub_git = [git]sub_git" >> .hgsub &&
hg add .hgsub &&
hg commit -m substate
)
git clone hg::hgrepo gitrepo &&
(
cd gitrepo &&
git-hg-helper sub update --force &&
test -f content_hgrepo &&
test -f sub_hg_a/content_sub_hg_a &&
test -f sub_hg_b/content_sub_hg_b &&
test -f sub_git/content_sub_git
) &&
check gitrepo HEAD substate &&
check gitrepo/sub_hg_a HEAD zero_sub_hg_a &&
check gitrepo/sub_hg_b HEAD zero_sub_hg_b &&
check gitrepo/sub_git HEAD zero_sub_git
'
setup_subrepos () {
setup_repo hg hgrepo &&
(
cd hgrepo &&
setup_repo hg sub_hg_a &&
(
cd sub_hg_a &&
setup_repo hg sub_hg_a_x &&
echo "sub_hg_a_x = sub_hg_a_x" > .hgsub &&
hg add .hgsub &&
hg commit -m substate_hg_a
) &&
setup_repo hg sub_hg_b &&
(
cd sub_hg_b &&
setup_repo git sub_git &&
echo "sub_git = [git]sub_git" > .hgsub &&
hg add .hgsub &&
hg commit -m substate_hg_b
) &&
echo "sub_hg_a = sub_hg_a" > .hgsub &&
echo "sub_hg_b = sub_hg_b" >> .hgsub &&
hg add .hgsub &&
hg commit -m substate
)
}
test_expect_success 'subcommand sub initial recursive update' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_subrepos &&
git clone hg::hgrepo gitrepo &&
(
cd gitrepo &&
git-hg-helper sub --recursive update --force &&
test -f content_hgrepo &&
test -f sub_hg_a/content_sub_hg_a &&
test -f sub_hg_a/sub_hg_a_x/content_sub_hg_a_x &&
test -f sub_hg_b/content_sub_hg_b &&
test -f sub_hg_b/sub_git/content_sub_git
) &&
check gitrepo HEAD substate &&
check gitrepo/sub_hg_a HEAD substate_hg_a &&
check gitrepo/sub_hg_b HEAD substate_hg_b &&
check gitrepo/sub_hg_a/sub_hg_a_x HEAD zero_sub_hg_a_x &&
check gitrepo/sub_hg_b/sub_git HEAD zero_sub_git
'
test_sub_update () {
export option=$1
setup_subrepos &&
git clone hg::hgrepo gitrepo &&
(
cd gitrepo &&
git-hg-helper sub --recursive update --force
) &&
(
cd hgrepo &&
(
cd sub_hg_a &&
(
cd sub_hg_a_x &&
echo one > content_sub_hg_a_x &&
hg commit -m one_sub_hg_a_x
) &&
hg commit -m substate_updated_hg_a
) &&
hg commit -m substate_updated
) &&
(
cd gitrepo &&
git fetch origin &&
git merge origin/master &&
git-hg-helper sub --recursive update --force $option &&
test -f content_hgrepo &&
test -f sub_hg_a/content_sub_hg_a &&
test -f sub_hg_a/sub_hg_a_x/content_sub_hg_a_x &&
test -f sub_hg_b/content_sub_hg_b &&
test -f sub_hg_b/sub_git/content_sub_git
) &&
check gitrepo HEAD substate_updated &&
check gitrepo/sub_hg_a HEAD substate_updated_hg_a &&
check gitrepo/sub_hg_b HEAD substate_hg_b &&
check gitrepo/sub_hg_a/sub_hg_a_x HEAD one_sub_hg_a_x &&
check gitrepo/sub_hg_b/sub_git HEAD zero_sub_git
}
test_expect_success 'subcommand sub subsequent recursive update' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_sub_update
'
test_expect_success 'subcommand sub subsequent recursive update -- rebase' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_sub_update --rebase
'
test_expect_success 'subcommand sub subsequent recursive update -- merge' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_sub_update --merge
'
check_foreach_vars () {
cat $1 | while read kind sha1 rev path remainder
do
ok=0
if test "$kind" = "hg" ; then
if test "$sha1" != "$rev" ; then
ok=1
fi
else
if test "$sha1" = "$rev" ; then
ok=1
fi
fi
test $ok -eq 1 || echo "invalid $kind $sha1 $rev $path"
test $ok -eq 1 || return 1
done &&
return 0
}
test_sub_foreach () {
setup_subrepos &&
git clone hg::hgrepo gitrepo &&
(
cd gitrepo &&
git-hg-helper sub --recursive update --force &&
git-hg-helper sub --recursive --quiet foreach 'echo $kind $sha1 $rev $path $toplevel' > output &&
cat output &&
echo 1 > expected_git &&
grep -c ^git output > actual_git &&
test_cmp expected_git actual_git &&
echo 3 > expected_hg &&
grep -c ^hg output > actual_hg &&
test_cmp expected_hg actual_hg &&
grep '\(hg\|git\) [0-9a-f]* [0-9a-f]* sub[^ ]* /.*' output > actual &&
test_cmp output actual &&
check_foreach_vars output
)
}
test_expect_success 'subcommand sub foreach' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
test_sub_foreach
'
test_expect_success 'subcommand sub sync' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repo hg hgrepo &&
(
cd hgrepo &&
setup_repo hg sub_hg &&
echo "sub_hg = sub_hg" > .hgsub &&
hg add .hgsub &&
hg commit -m substate
)
git clone hg::hgrepo gitrepo &&
(
cd gitrepo &&
git-hg-helper sub update --force &&
(
cd sub_hg &&
grep url .git/config > ../expected &&
git config remote.origin.url foobar &&
grep foobar .git/config
) &&
git-hg-helper sub sync &&
grep url sub_hg/.git/config > actual &&
test_cmp expected actual
)
'
test_expect_success 'subcommand sub addstate' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repo hg hgrepo &&
(
cd hgrepo &&
setup_repo hg sub_hg &&
setup_repo git sub_git &&
echo "sub_hg = sub_hg" > .hgsub &&
echo "sub_git = [git]sub_git" >> .hgsub &&
hg add .hgsub &&
hg commit -m substate
)
git clone hg::hgrepo gitrepo &&
(
cd gitrepo &&
git-hg-helper sub update --force &&
(
cd sub_hg &&
echo one > content_sub_hg &&
git add content_sub_hg &&
git commit -m one_sub_hg &&
# detached HEAD
git push origin HEAD:master &&
# also fetch to ensure notes are updated
git fetch origin
) &&
(
cd sub_git &&
echo one > content_sub_git &&
git add content_sub_git &&
git commit -m one_sub_git &&
# detached HEAD; push revision to other side ... anywhere
git push origin HEAD:refs/heads/new
)
) &&
(
cd gitrepo &&
git-hg-helper sub upstate &&
git diff &&
git status --porcelain | grep .hgsubstate &&
git add .hgsubstate &&
git commit -m update_sub &&
git push origin master
) &&
hg clone hgrepo hgclone &&
(
cd hgclone &&
hg update
) &&
check_branch hgclone default update_sub &&
check_branch hgclone/sub_hg default one_sub_hg &&
check hgclone/sub_git HEAD one_sub_git
'
test_expect_success 'subcommand sub status' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_repo hg hgrepo &&
(
cd hgrepo &&
setup_repo hg sub_hg_a &&
setup_repo hg sub_hg_b &&
setup_repo git sub_git &&
echo "sub_hg_a = sub_hg_a" > .hgsub &&
echo "sub_hg_b = sub_hg_b" >> .hgsub &&
echo "sub_git = [git]sub_git" >> .hgsub &&
hg add .hgsub &&
hg commit -m substate
)
git clone hg::hgrepo gitrepo &&
(
cd gitrepo &&
git-hg-helper sub update --force sub_hg_a &&
git-hg-helper sub update --force sub_git &&
(
# advance and add a tag to the git repo
cd sub_git &&
echo one > content_sub_git &&
git add content_sub_git &&
git commit -m one_sub_git &&
git tag feature-a
) &&
git-hg-helper sub status --cached > output &&
cat output &&
grep "^ .*sub_hg_a (.*master.*)$" output &&
grep "^-.*sub_hg_b$" output &&
grep "^+.*sub_git (feature-a~1)$" output &&
git-hg-helper sub status sub_git > output &&
cat output &&
grep "^+.*sub_git (feature-a)$" output > actual &&
test_cmp output actual
)
'
test_done

View File

@@ -17,16 +17,16 @@ then
test_done
fi
if ! python -c 'import mercurial' > /dev/null 2>&1
if ! python2 -c 'import mercurial' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
fi
if python -c 'import hggit' > /dev/null 2>&1
if python2 -c 'import hggit' > /dev/null 2>&1
then
hggit=hggit
elif python -c 'import hgext.git' > /dev/null 2>&1
elif python2 -c 'import hgext.git' > /dev/null 2>&1
then
hggit=hgext.git
else
@@ -34,6 +34,17 @@ else
test_done
fi
hg_version=$(python2 -c 'from mercurial import util; print util.version()')
echo "hg_version: $hg_version"
case $hg_version in
3.0*+*)
skip_all='skipping remote-hg tests; unsuported version of hg by hg-git'
test_done
;;
esac
# clone to a git repo with git
git_clone_git () {
git clone -q "hg::$1" $2 &&
@@ -106,15 +117,13 @@ setup () {
debugrawcommit = -d "0 0"
tag = -d "0 0"
[extensions]
hgext.bookmarks =
$hggit =
graphlog =
[git]
debugextrainmessage = 1
EOF
git config --global receive.denycurrentbranch warn
git config --global remote-hg.hg-git-compat true
git config --global remote-hg.track-branches false
git config --global remote-hg.shared-marks false
HGEDITOR=true
HGMERGE=true
@@ -126,31 +135,6 @@ setup () {
setup
test_expect_success 'rename' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
(
hg init hgrepo1 &&
cd hgrepo1 &&
echo alpha > alpha &&
hg add alpha &&
hg commit -m "add alpha" &&
hg mv alpha beta &&
hg commit -m "rename alpha to beta"
) &&
for x in hg git
do
git_clone_$x hgrepo1 gitrepo-$x &&
hg_clone_$x gitrepo-$x hgrepo2-$x &&
hg_log hgrepo2-$x > "hg-log-$x" &&
git_log gitrepo-$x > "git-log-$x"
done &&
test_cmp hg-log-hg hg-log-git &&
test_cmp git-log-hg git-log-git
'
test_expect_success 'executable bit' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&

View File

@@ -1,314 +0,0 @@
CAPABILITY_PUSH=t
test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
. "$TEST_DIRECTORY"/main.t
# .. and some push mode only specific tests
test_expect_success 'remote delete bookmark' '
test_when_finished "rm -rf hgrepo* gitrepo*" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero
hg bookmark feature-a
) &&
git clone "hg::hgrepo" gitrepo &&
check_bookmark hgrepo feature-a zero &&
(
cd gitrepo &&
git push --quiet origin :feature-a
) &&
check_bookmark hgrepo feature-a ''
'
test_expect_success 'source:dest bookmark' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd gitrepo &&
echo one > content &&
git commit -a -m one &&
git push --quiet origin master:feature-b &&
git push --quiet origin master^:refs/heads/feature-a
) &&
check_bookmark hgrepo feature-a zero &&
check_bookmark hgrepo feature-b one &&
(
cd gitrepo &&
git push --quiet origin master:feature-a
) &&
check_bookmark hgrepo feature-a one
'
setup_check_hg_commits_repo () {
(
rm -rf hgrepo* &&
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
hg clone hgrepo hgrepo.second &&
(
cd gitrepo &&
git remote add second hg::../hgrepo.second &&
git fetch second
) &&
(
cd hgrepo &&
echo one > content &&
hg commit -m one &&
echo two > content &&
hg commit -m two &&
echo three > content &&
hg commit -m three &&
hg move content content-move &&
hg commit -m moved &&
hg move content-move content &&
hg commit -m restored
)
}
# a shared bag would make all of the following pretty trivial
git config --global remote-hg.shared-marks false
git config --global remote-hg.check-hg-commits fail
test_expect_success 'check-hg-commits with fail mode' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_check_hg_commits_repo &&
(
cd gitrepo &&
git fetch origin &&
git reset --hard origin/master &&
! git push second master 2>../error
)
cat error &&
grep rejected error | grep hg
'
git config --global remote-hg.check-hg-commits push
# codepath for push is slightly different depending on shared proxy involved
# so tweak to test both
check_hg_commits_push () {
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_check_hg_commits_repo &&
(
cd gitrepo &&
git fetch origin &&
git reset --hard origin/master &&
git push second master 2> ../error
) &&
cat error &&
grep "hg changeset" error &&
hg log -R hgrepo > expected &&
hg log -R hgrepo.second | grep -v bookmark > actual &&
test_cmp expected actual
}
unset GIT_REMOTE_HG_TEST_REMOTE
test_expect_success 'check-hg-commits with push mode - no local proxy' '
check_hg_commits_push
'
GIT_REMOTE_HG_TEST_REMOTE=1 &&
export GIT_REMOTE_HG_TEST_REMOTE
test_expect_success 'check-hg-commits with push mode - with local proxy' '
check_hg_commits_push
'
setup_check_shared_marks_repo () {
(
rm -rf hgrepo* &&
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd gitrepo &&
git remote add second hg::../hgrepo &&
git fetch second
)
}
check_marks () {
dir=$1
ls -al $dir &&
if test "$2" = "y"
then
test -f $dir/marks-git && test -f $dir/marks-hg
else
test ! -f $dir/marks-git && test ! -f $dir/marks-hg
fi
}
# cleanup setting
git config --global --unset remote-hg.shared-marks
test_expect_success 'shared-marks unset' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
setup_check_shared_marks_repo &&
(
cd gitrepo &&
check_marks .git/hg y &&
check_marks .git/hg/origin n &&
check_marks .git/hg/second n
)
'
test_expect_success 'shared-marks set to unset' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
git config --global remote-hg.shared-marks true &&
setup_check_shared_marks_repo &&
(
cd gitrepo &&
check_marks .git/hg y &&
check_marks .git/hg/origin n &&
check_marks .git/hg/second n
) &&
git config --global remote-hg.shared-marks false &&
(
cd gitrepo &&
git fetch origin &&
check_marks .git/hg n &&
check_marks .git/hg/origin y &&
check_marks .git/hg/second y
)
'
test_expect_success 'shared-marks unset to set' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
git config --global remote-hg.shared-marks false &&
setup_check_shared_marks_repo &&
(
cd gitrepo &&
check_marks .git/hg n &&
check_marks .git/hg/origin y &&
check_marks .git/hg/second y
) &&
git config --global --unset remote-hg.shared-marks &&
(
cd gitrepo &&
git fetch origin &&
check_marks .git/hg n &&
check_marks .git/hg/origin y &&
check_marks .git/hg/second y
) &&
git config --global remote-hg.shared-marks true &&
(
cd gitrepo &&
git fetch origin &&
check_marks .git/hg y &&
check_marks .git/hg/origin n &&
check_marks .git/hg/second n
)
'
test_expect_success 'push with renamed executable preserves executable bit' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
hg init hgrepo &&
(
git init gitrepo &&
cd gitrepo &&
git remote add origin "hg::../hgrepo" &&
echo one > content &&
chmod a+x content &&
git add content &&
git commit -a -m one &&
git mv content content2 &&
git commit -a -m two &&
git push origin master
) &&
(
cd hgrepo &&
hg update &&
stat content2 >expected &&
# umask mileage might vary
grep -- -r.xr.xr.x expected
)
'
test_expect_success 'push with submodule' '
test_when_finished "rm -rf sub hgrepo gitrepo*" &&
hg init hgrepo &&
(
git init sub &&
cd sub &&
: >empty &&
git add empty &&
git commit -m init
) &&
(
git init gitrepo &&
cd gitrepo &&
git submodule add ../sub sub &&
git remote add origin "hg::../hgrepo" &&
git commit -a -m sub &&
git push origin master
) &&
(
cd hgrepo &&
hg update &&
expected="[git-remote-hg: skipped import of submodule at $(git -C ../sub rev-parse HEAD)]"
test "$expected" = "$(cat sub)"
)
'
# cleanup setting
git config --global --unset remote-hg.shared-marks
test_done

View File

@@ -11,22 +11,13 @@ test_description='Test remote-hg'
test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
. "$TEST_DIRECTORY"/test-lib.sh
if test "$CAPABILITY_PUSH" = "t"
then
git config --global remote-hg.capability-push true
git config --global remote-hg.push-updates-notes true
git config --global remote-hg.fast-export-options '-C -C -M'
else
git config --global remote-hg.capability-push false
fi
if ! test_have_prereq PYTHON
then
skip_all='skipping remote-hg tests; python not available'
test_done
fi
if ! python -c 'import mercurial' > /dev/null 2>&1
if ! python2 -c 'import mercurial' > /dev/null 2>&1
then
skip_all='skipping remote-hg tests; mercurial not available'
test_done
@@ -90,20 +81,23 @@ check_push () {
'non-fast-forward')
grep "^ ! \[rejected\] *${branch} -> ${branch} (non-fast-forward)$" error || ref_ret=1
;;
'fetch-first')
grep "^ ! \[rejected\] *${branch} -> ${branch} (fetch first)$" error || ref_ret=1
;;
'forced-update')
grep "^ + [a-f0-9]*\.\.\.[a-f0-9]* *${branch} -> ${branch} (forced update)$" error || ref_ret=1
;;
'')
grep "^ [a-f0-9]*\.\.[a-f0-9]* *${branch} -> ${branch}$" error || ref_ret=1
;;
*)
echo "BUG: wrong kind '$kind'" && return 3
;;
esac
test $ref_ret -ne 0 && echo "match for '$branch' failed" && return 2
test $ref_ret -ne 0 && echo "match for '$branch' failed" && break
done
test $expected_ret -ne $ret && return 1
if test $expected_ret -ne $ret || test $ref_ret -ne 0
then
return 1
fi
return 0
}
@@ -182,7 +176,7 @@ test_expect_success 'update bookmark' '
git checkout --quiet devel &&
echo devel > content &&
git commit -a -m devel &&
git push --quiet origin devel
git push --quiet
) &&
check_bookmark hgrepo devel devel
@@ -448,7 +442,7 @@ test_expect_success 'remote update bookmark diverge' '
echo diverge > content &&
git commit -a -m diverge &&
check_push 1 <<-\EOF
diverge:non-fast-forward
diverge:fetch-first
EOF
) &&
@@ -473,56 +467,10 @@ test_expect_success 'remote new bookmark multiple branch head' '
# cleanup previous stuff
rm -rf hgrepo
testcopyrenamedesc='push commits with copy and rename'
testcopyrename='
test_when_finished "rm -rf gitrepo hgrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd gitrepo &&
cp content content-copy &&
# recent git-fast-export is (too) picky in recognizing copies
# although git-log is not as picky;
# since https://github.com/git/git/commit/8096e1d385660c159d9d47e69b2be63cf22e4f31
# a copy is only marked if source filed not modified as well
# (though destination file can be modified)
echo one >> content-copy &&
git add content content-copy &&
git commit -m copy &&
git mv content-copy content-moved
git commit -m moved &&
git push origin master
) &&
(
hg -R hgrepo update &&
test_cmp gitrepo/content hgrepo/content
test_cmp gitrepo/content-moved hgrepo/content-moved
cd hgrepo &&
test `hg log -f content-moved | grep -c changeset` -eq 3
)
'
if test "$CAPABILITY_PUSH" = "t"
then
test_expect_success "$testcopyrenamedesc" "$testcopyrename"
else
test_expect_failure "$testcopyrenamedesc" "$testcopyrename"
fi
test_expect_success 'fetch special filenames' '
test_when_finished "rm -rf hgrepo gitrepo && LC_ALL=C" &&
LC_ALL=en_US.UTF-8
LC_ALL=C.UTF-8
export LC_ALL
(
@@ -555,7 +503,7 @@ test_expect_success 'push special filenames' '
mkdir -p tmp && cd tmp &&
LC_ALL=en_US.UTF-8
LC_ALL=C.UTF-8
export LC_ALL
(
@@ -670,31 +618,17 @@ test_expect_success 'remote big push' '
EOF
) &&
if test "$CAPABILITY_PUSH" = "t"
then
# cap push handles refs one by one
# so it will push all requested it can
check_branch hgrepo default six &&
check_branch hgrepo good_branch eight &&
check_branch hgrepo bad_branch "bad branch" &&
check_branch hgrepo new_branch ten &&
check_bookmark hgrepo good_bmark three &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark six
else
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
check_branch hgrepo bad_branch "bad branch" &&
check_branch hgrepo new_branch &&
check_bookmark hgrepo good_bmark one &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark
fi
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
check_branch hgrepo bad_branch "bad branch" &&
check_branch hgrepo new_branch '' &&
check_bookmark hgrepo good_bmark one &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark ''
'
test_expect_success 'remote big push non fast forward' '
test_expect_success 'remote big push fetch first' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
(
@@ -743,33 +677,22 @@ test_expect_success 'remote big push non fast forward' '
check_push 1 --all <<-\EOF &&
master
good_bmark
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
bad_bmark:fetch-first
branches/bad_branch:festch-first
EOF
git fetch &&
if test "$CAPABILITY_PUSH" = "t"
then
# cap push handles refs one by one
# so it will already have pushed some above previously
# (and master is a fake one that jumps around a bit)
check_push 1 --all <<-\EOF
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
else
check_push 1 --all <<-\EOF
master
good_bmark
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
fi
check_push 1 --all <<-\EOF
master
good_bmark
bad_bmark:non-fast-forward
branches/bad_branch:non-fast-forward
EOF
)
'
test_expect_success 'remote big push force' '
test_expect_failure 'remote big push force' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
@@ -777,30 +700,16 @@ test_expect_success 'remote big push force' '
(
cd gitrepo &&
if test "$CAPABILITY_PUSH" = "t"
then
check_push 0 --force --all <<-\EOF
master:forced-update
good_bmark:forced-update
branches/good_branch:forced-update
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
else
check_push 0 --force --all <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
fi
check_push 0 --force --all <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
) &&
check_branch hgrepo default six &&
@@ -813,7 +722,7 @@ test_expect_success 'remote big push force' '
check_bookmark hgrepo new_bmark six
'
test_expect_success 'remote big push dry-run' '
test_expect_failure 'remote big push dry-run' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
@@ -844,55 +753,11 @@ test_expect_success 'remote big push dry-run' '
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
check_branch hgrepo bad_branch "bad branch" &&
check_branch hgrepo new_branch &&
check_branch hgrepo new_branch '' &&
check_bookmark hgrepo good_bmark one &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark
'
test_expect_success 'remote big push force dry-run' '
test_when_finished "rm -rf hgrepo gitrepo*" &&
setup_big_push
(
cd gitrepo &&
if test "$CAPABILITY_PUSH" = "t"
then
check_push 0 --force --dry-run --all <<-\EOF
master:forced-update
good_bmark:forced-update
branches/good_branch:forced-update
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
else
check_push 0 --force --dry-run --all <<-\EOF
master
good_bmark
branches/good_branch
new_bmark:new
branches/new_branch:new
bad_bmark1:forced-update
bad_bmark2:forced-update
branches/bad_branch:forced-update
EOF
fi
) &&
check_branch hgrepo default one &&
check_branch hgrepo good_branch "good branch" &&
check_branch hgrepo bad_branch "bad branch" &&
check_branch hgrepo new_branch &&
check_bookmark hgrepo good_bmark one &&
check_bookmark hgrepo bad_bmark1 one &&
check_bookmark hgrepo bad_bmark2 one &&
check_bookmark hgrepo new_bmark
check_bookmark hgrepo new_bmark ''
'
test_expect_success 'remote double failed push' '
@@ -918,78 +783,6 @@ test_expect_success 'remote double failed push' '
test_expect_code 1 git push
)
'
test_expect_success 'fetch prune' '
test_when_finished "rm -rf gitrepo hgrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero &&
echo feature-a > content &&
hg commit -m feature-a
hg bookmark feature-a
) &&
git clone "hg::hgrepo" gitrepo &&
check gitrepo origin/feature-a feature-a &&
(
cd hgrepo &&
hg bookmark -d feature-a
) &&
(
cd gitrepo &&
git fetch --prune origin
git branch -a > out &&
! grep feature-a out
)
'
test_expect_success 'fetch multiple independent histories' '
test_when_finished "rm -rf gitrepo hgrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo zero > content &&
hg add content &&
hg commit -m zero &&
hg up -r null &&
echo another > ocontent &&
hg add ocontent &&
hg commit -m one
) &&
# -r 1 acts as master
(
git init --bare gitrepo && cd gitrepo &&
git remote add origin hg::../hgrepo &&
git fetch origin refs/heads/*:refs/heads/*
) &&
(
cd hgrepo &&
hg up 0 &&
echo two > content &&
hg commit -m two
) &&
# now master already exists
# -r 2 becomes master head which has rev 0 as ancestor
# so when importing (parentless) rev 0, a reset is needed
# (to ensure rev 0 is not given a parent commit)
(
cd gitrepo &&
git fetch origin &&
git log --format="%s" origin/master > ../actual
) &&
hg -R hgrepo log -r . -f --template "{desc}\n" > expected &&
test_cmp actual expected
'
test_expect_success 'clone remote with null bookmark, then push' '
test_when_finished "rm -rf gitrepo* hgrepo*" &&
@@ -1035,8 +828,7 @@ test_expect_success 'notes' '
test_cmp expected actual
'
testpushupdatesnotesdesc='push updates notes'
testpushupdatesnotes='
test_expect_failure 'push updates notes' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
@@ -1052,7 +844,7 @@ testpushupdatesnotes='
(
cd gitrepo &&
echo two > content &&
git commit -a -m two &&
git commit -a -m two
git push
) &&
@@ -1061,39 +853,7 @@ testpushupdatesnotes='
test_cmp expected actual
'
if test "$CAPABILITY_PUSH" = "t"
then
test_expect_success "$testpushupdatesnotesdesc" "$testpushupdatesnotes"
else
test_expect_failure "$testpushupdatesnotesdesc" "$testpushupdatesnotes"
fi
test_expect_success 'push bookmark without changesets' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo one > content &&
hg add content &&
hg commit -m one
) &&
git clone "hg::hgrepo" gitrepo &&
(
cd gitrepo &&
echo two > content &&
git commit -a -m two &&
git push origin master &&
git branch feature-a &&
git push origin feature-a
) &&
check_bookmark hgrepo feature-a two
'
test_expect_unstable 'pull tags' '
test_expect_success 'pull tags' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
@@ -1138,7 +898,7 @@ test_expect_success 'push merged named branch' '
git push
) &&
cat > expected <<-EOF &&
cat > expected <<-EOF
Merge
three
two
@@ -1179,7 +939,7 @@ test_expect_success 'push tag different branch' '
cd hgrepo &&
echo one > content &&
hg add content &&
hg commit -m one &&
hg commit -m one
hg branch feature &&
echo two > content &&
hg commit -m two
@@ -1264,78 +1024,4 @@ test_expect_success 'clone replace directory with a file' '
check_files gitrepo "dir_or_file"
'
test_expect_success 'clone can ignore invalid refnames' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
touch test.txt &&
hg add test.txt &&
hg commit -m master &&
hg branch parent &&
echo test >test.txt &&
hg commit -m test &&
hg branch parent/child &&
echo test1 >test.txt &&
hg commit -m test1
) &&
git clone -c remote-hg.ignore-name=child "hg::hgrepo" gitrepo &&
check_files gitrepo "test.txt"
'
test_expect_success 'push annotated tag' '
test_when_finished "rm -rf hgrepo gitrepo" &&
(
hg init hgrepo &&
cd hgrepo &&
echo one > content &&
hg add content &&
hg commit -m one
) &&
(
git clone "hg::hgrepo" gitrepo &&
cd gitrepo &&
git tag -m "Version 1.0" v1.0 &&
git push --tags
) &&
cat > expected <<-\EOF &&
tip:Version 1.0:C O Mitter <committer@example.com>
v1.0:one:H G Wells <wells@example.com>
EOF
hg -R hgrepo log --template "{tags}:{desc}:{author}\n" > actual &&
test_cmp expected actual
'
test_expect_success 'timezone issues with negative offsets' '
test_when_finished "rm -rf hgrepo gitrepo1 gitrepo2" &&
hg init hgrepo &&
(
git clone "hg::hgrepo" gitrepo1 &&
cd gitrepo1 &&
echo two >> content &&
git add content &&
git commit -m two --date="2016-09-26 00:00:00 -0230" &&
git push
) &&
git clone "hg::hgrepo" gitrepo2 &&
git --git-dir=gitrepo1/.git log -1 --format="%ai" > expected &&
git --git-dir=gitrepo2/.git log -1 --format="%ai" > actual &&
test_cmp expected actual
'
if test "$CAPABILITY_PUSH" != "t"
then
test_done
fi

View File

@@ -18,80 +18,33 @@
# along with this program. If not, see http://www.gnu.org/licenses/ .
# Public: Current version of Sharness.
SHARNESS_VERSION="1.1.0"
SHARNESS_VERSION="0.3.0"
export SHARNESS_VERSION
# Public: The file extension for tests. By default, it is set to "t".
: "${SHARNESS_TEST_EXTENSION:=t}"
: ${SHARNESS_TEST_EXTENSION:=t}
export SHARNESS_TEST_EXTENSION
# Public: Root directory containing tests. Tests can override this variable,
# e.g. for testing Sharness itself.
if test -z "$SHARNESS_TEST_DIRECTORY"
then
SHARNESS_TEST_DIRECTORY=$(pwd)
else
# ensure that SHARNESS_TEST_DIRECTORY is an absolute path so that it
# is valid even if the current working directory is changed
SHARNESS_TEST_DIRECTORY=$(cd "$SHARNESS_TEST_DIRECTORY" && pwd) || exit 1
fi
export SHARNESS_TEST_DIRECTORY
if test -z "$SHARNESS_TEST_OUTPUT_DIRECTORY"
then
# Similarly, override this to store the test-results subdir
# elsewhere
SHARNESS_TEST_OUTPUT_DIRECTORY=$SHARNESS_TEST_DIRECTORY
fi
# Reset TERM to original terminal if found, otherwise save original TERM
[ "x" = "x$SHARNESS_ORIG_TERM" ] &&
SHARNESS_ORIG_TERM="$TERM" ||
TERM="$SHARNESS_ORIG_TERM"
# Public: The unsanitized TERM under which sharness is originally run
export SHARNESS_ORIG_TERM
# Export SHELL_PATH
: "${SHELL_PATH:=$SHELL}"
export SHELL_PATH
# if --tee was passed, write the output not only to the terminal, but
# additionally to the file test-results/$BASENAME.out, too.
case "$SHARNESS_TEST_TEE_STARTED, $* " in
done,*)
# do not redirect again
;;
*' --tee '*|*' --verbose-log '*)
mkdir -p "$SHARNESS_TEST_OUTPUT_DIRECTORY/test-results"
BASE="$SHARNESS_TEST_OUTPUT_DIRECTORY/test-results/$(basename "$0" ".$SHARNESS_TEST_EXTENSION")"
# Make this filename available to the sub-process in case it is using
# --verbose-log.
SHARNESS_TEST_TEE_OUTPUT_FILE="$BASE.out"
export SHARNESS_TEST_TEE_OUTPUT_FILE
# Truncate before calling "tee -a" to get rid of the results
# from any previous runs.
: >"$SHARNESS_TEST_TEE_OUTPUT_FILE"
(SHARNESS_TEST_TEE_STARTED="done" ${SHELL_PATH} "$0" "$@" 2>&1;
echo $? >"$BASE.exit") | tee -a "$SHARNESS_TEST_TEE_OUTPUT_FILE"
test "$(cat "$BASE.exit")" = 0
exit
;;
esac
# Keep the original TERM for say_color
ORIGINAL_TERM=$TERM
# For repeatability, reset the environment to a known state.
# TERM is sanitized below, after saving color control sequences.
LANG=C
LC_ALL=C
PAGER="cat"
PAGER=cat
TZ=UTC
TERM=dumb
EDITOR=:
export LANG LC_ALL PAGER TZ EDITOR
export LANG LC_ALL PAGER TZ TERM EDITOR
unset VISUAL CDPATH GREP_OPTIONS
[ "x$TERM" != "xdumb" ] && (
# Line feed
LF='
'
[ "x$ORIGINAL_TERM" != "xdumb" ] && (
TERM=$ORIGINAL_TERM &&
export TERM &&
[ -t 1 ] &&
tput bold >/dev/null 2>&1 &&
tput setaf 1 >/dev/null 2>&1 &&
@@ -107,8 +60,6 @@ while test "$#" -ne 0; do
immediate=t; shift ;;
-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
TEST_LONG=t; export TEST_LONG; shift ;;
--in|--int|--inte|--inter|--intera|--interac|--interact|--interacti|--interactiv|--interactive|--interactive-|--interactive-t|--interactive-te|--interactive-tes|--interactive-test|--interactive-tests):
TEST_INTERACTIVE=t; export TEST_INTERACTIVE; verbose=t; shift ;;
-h|--h|--he|--hel|--help)
help=t; shift ;;
-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
@@ -117,69 +68,49 @@ while test "$#" -ne 0; do
# Ignore --quiet under a TAP::Harness. Saying how many tests
# passed without the ok/not ok details is always an error.
test -z "$HARNESS_ACTIVE" && quiet=t; shift ;;
--chain-lint)
chain_lint=t; shift ;;
--no-chain-lint)
chain_lint=; shift ;;
--no-color)
color=; shift ;;
--tee)
shift ;; # was handled already
--root=*)
root=$(expr "z$1" : 'z[^=]*=\(.*\)')
shift ;;
--verbose-log)
verbose_log=t
shift ;;
*)
echo "error: unknown test option '$1'" >&2; exit 1 ;;
esac
done
if test -n "$color"; then
# Save the color control sequences now rather than run tput
# each time say_color() is called. This is done for two
# reasons:
# * TERM will be changed to dumb
# * HOME will be changed to a temporary directory and tput
# might need to read ~/.terminfo from the original HOME
# directory to get the control sequences
# Note: This approach assumes the control sequences don't end
# in a newline for any terminal of interest (command
# substitutions strip trailing newlines). Given that most
# (all?) terminals in common use are related to ECMA-48, this
# shouldn't be a problem.
say_color_error=$(tput bold; tput setaf 1) # bold red
say_color_skip=$(tput setaf 4) # blue
say_color_warn=$(tput setaf 3) # brown/yellow
say_color_pass=$(tput setaf 2) # green
say_color_info=$(tput setaf 6) # cyan
say_color_reset=$(tput sgr0)
say_color_raw="" # no formatting for normal text
say_color() {
test -z "$1" && test -n "$quiet" && return
(
TERM=$ORIGINAL_TERM
export TERM
case "$1" in
error) say_color_color=$say_color_error ;;
skip) say_color_color=$say_color_skip ;;
warn) say_color_color=$say_color_warn ;;
pass) say_color_color=$say_color_pass ;;
info) say_color_color=$say_color_info ;;
*) say_color_color=$say_color_raw ;;
error)
tput bold; tput setaf 1;; # bold red
skip)
tput setaf 4;; # blue
warn)
tput setaf 3;; # brown/yellow
pass)
tput setaf 2;; # green
info)
tput setaf 6;; # cyan
*)
test -n "$quiet" && return;;
esac
shift
printf '%s%s%s\n' "$say_color_color" "$*" "$say_color_reset"
printf "%s" "$*"
tput sgr0
echo
)
}
else
say_color() {
test -z "$1" && test -n "$quiet" && return
shift
printf '%s\n' "$*"
printf "%s\n" "$*"
}
fi
TERM=dumb
export TERM
error() {
say_color error "error: $*"
EXIT_OK=t
@@ -190,7 +121,7 @@ say() {
say_color info "$*"
}
test -n "${test_description:-}" || error "Test script did not set test_description."
test -n "$test_description" || error "Test script did not set test_description."
if test "$help" = "t"; then
echo "$test_description"
@@ -199,11 +130,7 @@ fi
exec 5>&1
exec 6<&0
if test "$verbose_log" = "t"
then
exec 3>>"$SHARNESS_TEST_TEE_OUTPUT_FILE" 4>&3
elif test "$verbose" = "t"
then
if test "$verbose" = "t"; then
exec 4>&2 3>&1
else
exec 4>/dev/null 3>/dev/null
@@ -234,7 +161,7 @@ trap 'die' EXIT
# implicitly by specifying the prerequisite name in calls to test_expect_success
# or test_expect_failure.
#
# $1 - Name of prerequisite (a simple word, in all capital letters by convention)
# $1 - Name of prerequiste (a simple word, in all capital letters by convention)
#
# Examples
#
@@ -271,7 +198,7 @@ test_have_prereq() {
# prerequisites can be concatenated with ','
save_IFS=$IFS
IFS=,
set -- $@
set -- $*
IFS=$save_IFS
total_prereq=0
@@ -288,7 +215,7 @@ test_have_prereq() {
negative_prereq=
esac
total_prereq=$((total_prereq + 1))
total_prereq=$(($total_prereq + 1))
case "$satisfied_prereq" in
*" $prerequisite "*)
satisfied_this_prereq=t
@@ -299,7 +226,7 @@ test_have_prereq() {
case "$satisfied_this_prereq,$negative_prereq" in
t,|,t)
ok_prereq=$((ok_prereq + 1))
ok_prereq=$(($ok_prereq + 1))
;;
*)
# Keep a list of missing prerequisites; restore
@@ -320,12 +247,12 @@ test_have_prereq() {
# the text_expect_* functions instead.
test_ok_() {
test_success=$((test_success + 1))
say_color "" "ok $test_count - $*"
test_success=$(($test_success + 1))
say_color "" "ok $test_count - $@"
}
test_failure_() {
test_failure=$((test_failure + 1))
test_failure=$(($test_failure + 1))
say_color error "not ok $test_count - $1"
shift
echo "$@" | sed -e 's/^/# /'
@@ -333,13 +260,13 @@ test_failure_() {
}
test_known_broken_ok_() {
test_fixed=$((test_fixed + 1))
say_color error "ok $test_count - $* # TODO known breakage vanished"
test_fixed=$(($test_fixed + 1))
say_color error "ok $test_count - $@ # TODO known breakage vanished"
}
test_known_broken_failure_() {
test_broken=$((test_broken + 1))
say_color warn "not ok $test_count - $* # TODO known breakage"
test_broken=$(($test_broken + 1))
say_color warn "not ok $test_count - $@ # TODO known breakage"
}
# Public: Execute commands in debug mode.
@@ -360,29 +287,10 @@ test_debug() {
test "$debug" = "" || eval "$1"
}
# Public: Stop execution and start a shell.
#
# This is useful for debugging tests and only makes sense together with "-v".
# Be sure to remove all invocations of this command before submitting.
test_pause() {
if test "$verbose" = t; then
"$SHELL_PATH" <&6 >&3 2>&4
else
error >&5 "test_pause requires --verbose"
fi
}
test_eval_() {
# This is a separate function because some tests use
# "return" to end a test_expect_success block early.
case ",$test_prereq," in
*,INTERACTIVE,*)
eval "$*"
;;
*)
eval </dev/null >&3 2>&4 "$*"
;;
esac
eval </dev/null >&3 2>&4 "$*"
}
test_run_() {
@@ -391,13 +299,6 @@ test_run_() {
test_eval_ "$1"
eval_ret=$?
if test "$chain_lint" = "t"; then
test_eval_ "(exit 117) && $1"
if test "$?" != 117; then
error "bug in the test script: broken &&-chain: $1"
fi
fi
if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"; then
test_eval_ "$test_cleanup"
fi
@@ -408,7 +309,7 @@ test_run_() {
}
test_skip_() {
test_count=$((test_count + 1))
test_count=$(($test_count + 1))
to_skip=
for skp in $SKIP_TESTS; do
case $this_test.$test_count in
@@ -427,7 +328,7 @@ test_skip_() {
of_prereq=" of $test_prereq"
fi
say_color skip >&3 "skipping test: $*"
say_color skip >&3 "skipping test: $@"
say_color skip "ok $test_count # skip $1 (missing $missing_prereq${of_prereq})"
: true
;;
@@ -525,44 +426,6 @@ test_expect_failure() {
echo >&3 ""
}
# Public: Run test commands and expect anything from them. Used when a
# test is not stable or not finished for some reason.
#
# When the test passed, an "ok" message is printed, but the number of
# fixed tests is not incremented.
#
# When it failed, a "not ok ... # TODO known breakage" message is
# printed, and the number of tests still broken is incremented.
#
# Failures from these tests won't cause --immediate to stop.
#
# Usually takes two arguments:
# $1 - Test description
# $2 - Commands to be executed.
#
# With three arguments, the first will be taken to be a prerequisite:
# $1 - Comma-separated list of test prerequisites. The test will be skipped if
# not all of the given prerequisites are set. To negate a prerequisite,
# put a "!" in front of it.
# $2 - Test description
# $3 - Commands to be executed.
#
# Returns nothing.
test_expect_unstable() {
test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_unstable"
export test_prereq
if ! test_skip_ "$@"; then
say >&3 "checking unstable test: $2"
if test_run_ "$2" unstable; then
test_ok_ "$1"
else
test_known_broken_failure_ "$1"
fi
fi
echo >&3 ""
}
# Public: Run command and ensure that it fails in a controlled way.
#
# Use it instead of "! <command>". For example, when <command> dies due to a
@@ -655,7 +518,7 @@ test_expect_code() {
shift
"$@"
exit_code=$?
if test "$exit_code" = "$want_code"; then
if test $exit_code = $want_code; then
return 0
fi
@@ -665,7 +528,7 @@ test_expect_code() {
# Public: Compare two files to see if expected output matches actual output.
#
# The TEST_CMP variable defines the command used for the comparison; it
# The TEST_CMP variable defines the command used for the comparision; it
# defaults to "diff -u". Only when the test script was started with --verbose,
# will the command's output, the diff, be printed to the standard output.
#
@@ -688,79 +551,6 @@ test_cmp() {
${TEST_CMP:-diff -u} "$@"
}
# Public: portably print a sequence of numbers.
#
# seq is not in POSIX and GNU seq might not be available everywhere,
# so it is nice to have a seq implementation, even a very simple one.
#
# $1 - Starting number.
# $2 - Ending number.
#
# Examples
#
# test_expect_success 'foo works 10 times' '
# for i in $(test_seq 1 10)
# do
# foo || return
# done
# '
#
# Returns 0 if all the specified numbers can be displayed.
test_seq() {
i="$1"
j="$2"
while test "$i" -le "$j"
do
echo "$i" || return
i=$(("$i" + 1))
done
}
# Public: Check if the file expected to be empty is indeed empty, and barfs
# otherwise.
#
# $1 - File to check for emptiness.
#
# Returns 0 if file is empty, 1 otherwise.
test_must_be_empty() {
if test -s "$1"
then
echo "'$1' is not empty, it contains:"
cat "$1"
return 1
fi
}
# debugging-friendly alternatives to "test [-f|-d|-e]"
# The commands test the existence or non-existence of $1. $2 can be
# given to provide a more precise diagnosis.
test_path_is_file () {
if ! test -f "$1"
then
echo "File $1 doesn't exist. $2"
false
fi
}
test_path_is_dir () {
if ! test -d "$1"
then
echo "Directory $1 doesn't exist. $2"
false
fi
}
# Check if the directory exists and is empty as expected, barf otherwise.
test_dir_is_empty () {
test_path_is_dir "$1" &&
if test -n "$(find "$1" -mindepth 1 -maxdepth 1)"
then
echo "Directory '$1' is not empty, it contains:"
ls -la "$1"
return 1
fi
}
# Public: Schedule cleanup commands to be run unconditionally at the end of a
# test.
#
@@ -786,23 +576,6 @@ test_when_finished() {
} && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
}
# Public: Schedule cleanup commands to be run unconditionally when all tests
# have run.
#
# This can be used to clean up things like test databases. It is not needed to
# clean up temporary files, as test_done already does that.
#
# Examples:
#
# cleanup mysql -e "DROP DATABASE mytest"
#
# Returns the exit code of the last cleanup command executed.
final_cleanup=
cleanup() {
final_cleanup="{ $*
} && (exit \"\$eval_ret\"); eval_ret=\$?; $final_cleanup"
}
# Public: Summarize test results and exit with an appropriate error code.
#
# Must be called at the end of each test script.
@@ -827,9 +600,9 @@ test_done() {
EXIT_OK=t
if test -z "$HARNESS_ACTIVE"; then
test_results_dir="$SHARNESS_TEST_OUTPUT_DIRECTORY/test-results"
test_results_dir="$SHARNESS_TEST_DIRECTORY/test-results"
mkdir -p "$test_results_dir"
test_results_path="$test_results_dir/$this_test.$$.counts"
test_results_path="$test_results_dir/${SHARNESS_TEST_FILE%.$SHARNESS_TEST_EXTENSION}.$$.counts"
cat >>"$test_results_path" <<-EOF
total $test_count
@@ -848,7 +621,7 @@ test_done() {
say_color warn "# still have $test_broken known breakage(s)"
fi
if test "$test_broken" != 0 || test "$test_fixed" != 0; then
test_remaining=$((test_count - test_broken - test_fixed))
test_remaining=$(( $test_count - $test_broken - $test_fixed ))
msg="remaining $test_remaining test(s)"
else
test_remaining=$test_count
@@ -868,8 +641,6 @@ test_done() {
fi
say "1..$test_count$skip_all"
test_eval_ "$final_cleanup"
test -d "$remove_trash" &&
cd "$(dirname "$remove_trash")" &&
rm -rf "$(basename "$remove_trash")"
@@ -885,15 +656,14 @@ test_done() {
esac
}
# Public: Source directory of test code and sharness library.
# This directory may be different from the directory in which tests are
# being run.
: "${SHARNESS_TEST_SRCDIR:=$(cd "$(dirname "$0")" && pwd)}"
export SHARNESS_TEST_SRCDIR
# Public: Root directory containing tests. Tests can override this variable,
# e.g. for testing Sharness itself.
: ${SHARNESS_TEST_DIRECTORY:=$(pwd)}
export SHARNESS_TEST_DIRECTORY
# Public: Build directory that will be added to PATH. By default, it is set to
# the parent directory of SHARNESS_TEST_DIRECTORY.
: "${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}"
: ${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}
PATH="$SHARNESS_BUILD_DIRECTORY:$PATH"
export PATH SHARNESS_BUILD_DIRECTORY
@@ -902,43 +672,19 @@ SHARNESS_TEST_FILE="$0"
export SHARNESS_TEST_FILE
# Prepare test area.
SHARNESS_TRASH_DIRECTORY="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")"
test -n "$root" && SHARNESS_TRASH_DIRECTORY="$root/$SHARNESS_TRASH_DIRECTORY"
case "$SHARNESS_TRASH_DIRECTORY" in
/*) ;; # absolute path is good
*) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_OUTPUT_DIRECTORY/$SHARNESS_TRASH_DIRECTORY" ;;
test_dir="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")"
test -n "$root" && test_dir="$root/$test_dir"
case "$test_dir" in
/*) SHARNESS_TRASH_DIRECTORY="$test_dir" ;;
*) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_DIRECTORY/$test_dir" ;;
esac
test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY"
rm -rf "$SHARNESS_TRASH_DIRECTORY" || {
rm -rf "$test_dir" || {
EXIT_OK=t
echo >&5 "FATAL: Cannot prepare test area"
exit 1
}
#
# Load any extensions in $srcdir/sharness.d/*.sh
#
if test -d "${SHARNESS_TEST_SRCDIR}/sharness.d"
then
for file in "${SHARNESS_TEST_SRCDIR}"/sharness.d/*.sh
do
# Ensure glob was not an empty match:
test -e "${file}" || break
if test -n "$debug"
then
echo >&5 "sharness: loading extensions from ${file}"
fi
. "${file}"
if test $? != 0
then
echo >&5 "sharness: Error loading ${file}. Aborting."
exit 1
fi
done
fi
# Public: Empty trash directory, the test area, provided for each test. The HOME
# variable is set to that directory too.
export SHARNESS_TRASH_DIRECTORY
@@ -946,10 +692,10 @@ export SHARNESS_TRASH_DIRECTORY
HOME="$SHARNESS_TRASH_DIRECTORY"
export HOME
mkdir -p "$SHARNESS_TRASH_DIRECTORY" || exit 1
mkdir -p "$test_dir" || exit 1
# Use -P to resolve symlinks in our working directory so that the cwd
# in subprocesses like git equals our $PWD (for pathname comparisons).
cd -P "$SHARNESS_TRASH_DIRECTORY" || exit 1
cd -P "$test_dir" || exit 1
this_test=${SHARNESS_TEST_FILE##*/}
this_test=${this_test%.$SHARNESS_TEST_EXTENSION}
@@ -962,10 +708,4 @@ for skp in $SKIP_TESTS; do
esac
done
test -n "$TEST_LONG" && test_set_prereq EXPENSIVE
test -n "$TEST_INTERACTIVE" && test_set_prereq INTERACTIVE
# Make sure this script ends with code 0
:
# vi: set ts=4 sw=4 noet :

1
tools/.gitignore vendored
View File

@@ -1 +0,0 @@
results.txt

View File

@@ -1,297 +0,0 @@
#!/usr/bin/env ruby
#
# Copyright (c) 2019 Felipe Contreras
#
# This script runs the tests for all versions of the components:
# hg, hggit and dulwich
#
# You can run it without arguments, in which case it reads the file
# 'versions.txt' and executes all those checks.
#
# Or you can pass the versions to check manually, like:
#
# ./check-versions hg:4.7 hggit:0.8.12 dulwich:0.19.7
#
# Or you can pass just the hg version, the other versions are fetched from
# 'versions.txt':
#
# ./check-versions hg:5.0
#
require 'fileutils'
$tests = %w[main.t bidi.t hg-git.t]
$workdir = "#{Dir.home}/.cache/git-remote-hg"
$builddir = "/tmp/git-remote-hg-build"
$testoutdir = "/tmp/git-remote-hg-tests"
QUIET, LOW, HIGH = (1..3).to_a
$verbosity = LOW
# Util {{{1
def section(text)
puts [nil, text, '=' * text.size]
end
def title(text)
puts [nil, text, '-' * text.size] unless $verbosity < HIGH
end
def run_cmd(cmd, fatal: true)
puts cmd.join(' ') unless $verbosity < HIGH
result = system(*cmd)
unless result or not fatal
STDERR.puts "Failed to run command '%s'" % cmd.join(' ')
exit -1
end
result
end
def check_version(a, b)
return true if a == '@'
a = a.split('.').map(&:to_i)
b = b.split('.').map(&:to_i)
(a <=> b) >= 0
end
# Component {{{1
class Component
attr_reader :id
def initialize(id, url, kind: nil, **args)
@id = id
@url = url
@kind = kind || (url.start_with?('git') ? :git : :hg)
@tool = @kind.to_s
@checkout_fix = args[:checkout_fix]
@version_format = args[:version_format]
end
def dir
"#{$workdir}/#{@id}"
end
def get_version(version)
return @kind == :hg ? 'tip' : '@' if version == '@'
@version_format ? @version_format % version : version
end
def clone
run_cmd [@tool, 'clone', '-q', @url, dir]
end
def checkout(version)
Dir.chdir(dir) do
case @kind
when :hg
cmd = %w[update --clean]
when :git
cmd = %w[reset --hard]
else
cmd = %w[checkout]
end
run_cmd [@tool] + cmd + ['-q', get_version(version)]
@checkout_fix.call(version) if @checkout_fix
end
end
def build
Dir.chdir(dir) do
targets = %w[build_py build_ext].map { |e| [e, '--build-lib', "#{$builddir}/python"] }
run_cmd %w[python setup.py --quiet] + targets.flatten
end
end
end
# Functions {{{1
def setup
dirs = %w[bin python]
FileUtils.mkdir_p(dirs.map { |e| "#{$builddir}/#{e}" })
FileUtils.mkdir_p($workdir)
$components.each do |id, component|
next if File.exists?(component.dir)
if $verbosity < HIGH
puts "Cloning #{component.id}"
else
title "Cloning #{component.id}"
end
component.clone
end
end
def test_env(paths: nil)
old = ENV.to_h
paths.each do |id, path|
name = id.to_s
ENV[name] = "#{path}:#{ENV[name]}"
end
r = yield
ENV.replace(old)
return r
end
def run_tests(tests)
title "Running tests"
Dir.chdir("#{__dir__}/../test") do
case $verbosity
when QUIET
tests_opt = tests.join(' ')
cmd = "prove -q #{tests_opt} :: -i"
when LOW
tests_opt = "T='%s'" % tests.join(' ')
cmd = "make -j1 #{tests_opt}"
else
tests_opt = "T='%s'" % tests.join(' ')
cmd = "TEST_OPTS='-v -i' make -j1 #{tests_opt}"
end
system(cmd)
end
end
def versions_to_s(versions)
versions.map { |k,v| "#{k}:#{v}" }.join(' ')
end
def versions_from_args(args)
args.map { |e| k, v = e.split(':'); [k.to_sym, v] }.to_h
end
def versions_from_s(str)
versions_from_args(str.split(' '))
end
def check(versions)
section versions_to_s(versions)
versions.each do |id, version|
component = $components[id]
next unless component
title "Checking out #{component.id} #{version}"
component.checkout(version)
title "Building #{component.id}"
component.build
end
paths = {
PATH: "#{$builddir}/bin",
PYTHONPATH: "#{$builddir}/python",
}
test_env(paths: paths) do
ENV['SHARNESS_TEST_OUTPUT_DIRECTORY'] = $testoutdir
run_tests($tests)
end
end
# Add components {{{1
$components = {}
def add_component(id, url, **args)
$components[id] = Component.new(id, url, **args)
end
hg_checkout_fix = lambda do |version|
FileUtils.cp('hg', "#{$builddir}/bin/")
return if check_version(version, '4.3')
if run_cmd %W[hg import -q --no-commit #{__dir__}/hg_setup_hack_2.4.patch], fatal: false
File.write('.hg_force_version', "%s\n" % version)
else
File.write('mercurial/__version__.py', "version = \"%s\"\n" % version)
end
end
add_component(:hg, 'https://www.mercurial-scm.org/repo/hg', checkout_fix: hg_checkout_fix)
hggit_checkout_fix = lambda do |version|
return unless check_version(version, '0.8.0')
run_cmd %W[hg import -q --no-commit #{__dir__}/hggit_rename_fix_0.8.0.patch], fatal: false
end
add_component(:hggit, 'https://bitbucket.org/durin42/hg-git', checkout_fix: hggit_checkout_fix)
add_component(:dulwich, 'https://github.com/dulwich/dulwich.git', version_format: 'dulwich-%s', kind: :git)
def load_checks(file)
file.each do |e|
e.chomp!
next if e.empty? or e.start_with?('#')
content, comment = e.split(' # ')
versions = versions_from_s(content)
$checks << versions
end
end
def store_results(file)
$results.each do |versions, result|
content = versions_to_s(versions)
comment = result ? 'OK' : 'FAIL'
file.puts '%s # %s' % [content, comment]
end
end
# Main {{{1
setup
$checks = []
$results = []
$versions = versions_from_args(ARGV)
File.open("#{__dir__}/versions.txt") do |f|
load_checks(f)
end
if $versions.size == 1 and $versions.key?(:hg)
# mode 1
$verbosity = LOW
if ['@', nil].include?($versions[:hg])
versions = $checks.last
versions[:hg] = $versions[:hg] if $versions[:hg]
else
versions = $checks.find { |e| e[:hg] == $versions[:hg] }
exit 1 unless versions
end
exit check(versions) ? 0 : 1
elsif not $versions.empty?
# mode 2
$verbosity = HIGH
exit check(versions) ? 0 : 1
else
# mode 3
$verbosity = QUIET
at_exit do
File.open("#{__dir__}/results.txt", 'w') do |f|
store_results(f)
end
end
failures = 0
$checks.each do |versions|
result = check(versions)
failures += 1 unless result
$results << [versions, result]
end
exit 1 unless failures == 0
end

View File

@@ -1,15 +0,0 @@
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -181,7 +181,10 @@
# error 0xc0150004. See: http://bugs.python.org/issue3440
env['SystemRoot'] = os.environ['SystemRoot']
-if os.path.isdir('.hg'):
+if os.path.exists('.hg_force_version'):
+ with open('.hg_force_version') as f:
+ version = f.read().rstrip('\n')
+elif os.path.isdir('.hg'):
cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()

View File

@@ -1,22 +0,0 @@
diff --git a/hggit/git_handler.py b/hggit/git_handler.py
--- a/hggit/git_handler.py
+++ b/hggit/git_handler.py
@@ -693,6 +693,8 @@
def import_git_commit(self, commit):
self.ui.debug(_("importing: %s\n") % commit.id)
+ extra_in_message = self.ui.configbool('git', 'debugextrainmessage', False)
+
detect_renames = False
(strip_message, hg_renames,
hg_branch, extra) = git2hg.extract_hg_metadata(
@@ -703,7 +705,8 @@
# renames detected from Git. This is because we export an extra
# 'HG:rename-source' Git parameter when this isn't set, which will
# break bidirectionality.
- extra['hg-git-rename-source'] = 'git'
+ if not extra_in_message:
+ extra['hg-git-rename-source'] = 'git'
else:
renames = hg_renames

View File

@@ -1,33 +0,0 @@
# vi: ft=ruby
hg:2.4 hggit:0.4.0 dulwich:0.9.0 # 2013_02
hg:2.5 hggit:0.4.0 dulwich:0.9.0 # 2013_02
hg:2.6 hggit:0.4.0 dulwich:0.9.0 # 2013_02
hg:2.7 hggit:0.4.0 dulwich:0.9.0 # 2013_02
hg:2.8 hggit:0.4.0 dulwich:0.9.0 # 2013_02
hg:2.9 hggit:0.4.0 dulwich:0.9.0 # 2013_02
hg:3.0 hggit:0.7.0 dulwich:0.10.0 # 2014_11
hg:3.1 hggit:0.7.0 dulwich:0.10.0 # 2014_11
hg:3.2 hggit:0.7.0 dulwich:0.10.0 # 2014_11
hg:3.3 hggit:0.8.4 dulwich:0.13.0 # 2016_01
hg:3.4 hggit:0.8.4 dulwich:0.13.0 # 2016_01
hg:3.5 hggit:0.8.4 dulwich:0.13.0 # 2016_01
hg:3.6 hggit:0.8.4 dulwich:0.13.0 # 2016_01
hg:3.7 hggit:0.8.4 dulwich:0.13.0 # 2016_01
hg:3.8 hggit:0.8.4 dulwich:0.13.0 # 2016_01
hg:3.9 hggit:0.8.4 dulwich:0.13.0 # 2016_01
hg:4.0 hggit:0.8.10 dulwich:0.18.0 # 2017_11
hg:4.1 hggit:0.8.10 dulwich:0.18.0 # 2017_11
hg:4.2 hggit:0.8.10 dulwich:0.18.0 # 2017_11
hg:4.3 hggit:0.8.10 dulwich:0.18.0 # 2017_11
hg:4.4 hggit:0.8.10 dulwich:0.18.0 # 2017_11
hg:4.5 hggit:0.8.11 dulwich:0.18.0 # 2018_02
hg:4.6 hggit:0.8.12 dulwich:0.19.7 # 2018_10
hg:4.7 hggit:0.8.12 dulwich:0.19.7 # 2018_10
hg:4.8 hggit:@ dulwich:0.19.11
hg:4.9 hggit:@ dulwich:0.19.11
hg:5.0 hggit:@ dulwich:0.19.11