mirror of
				https://github.com/mnauw/git-remote-hg.git
				synced 2025-11-03 10:05:48 +01:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			v1.0.3
			...
			topic_note
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8f9d2797fd | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +0,0 @@
 | 
			
		||||
/build/
 | 
			
		||||
/dist/
 | 
			
		||||
/git_remote_hg.egg-info/
 | 
			
		||||
							
								
								
									
										36
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -1,20 +1,28 @@
 | 
			
		||||
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==0.6.1 || true
 | 
			
		||||
 | 
			
		||||
before_script:
 | 
			
		||||
  - hg --version || true
 | 
			
		||||
  - pip show hg-git dulwich
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - ./tools/check-versions hg:$HG_VERSION
 | 
			
		||||
  - 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=3.5.2
 | 
			
		||||
    - env: HG_VERSION=3.6.3
 | 
			
		||||
    - env: HG_VERSION=3.7
 | 
			
		||||
    - env: HG_VERSION=dev
 | 
			
		||||
    - python: 2.7
 | 
			
		||||
    - python: 2.6
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								Makefile
									
									
									
									
									
								
							@@ -3,28 +3,7 @@ prefix := $(HOME)
 | 
			
		||||
bindir := $(prefix)/bin
 | 
			
		||||
mandir := $(prefix)/share/man/man1
 | 
			
		||||
 | 
			
		||||
all: build doc
 | 
			
		||||
 | 
			
		||||
build:
 | 
			
		||||
	if [ -n "$$PYTHON" ] && "$$PYTHON" -c 'import mercurial' 2> /dev/null ; then \
 | 
			
		||||
		: Use chosen Python version ; \
 | 
			
		||||
	elif python3 -c 'import mercurial' 2> /dev/null ; then \
 | 
			
		||||
		PYTHON=python3 ; \
 | 
			
		||||
	elif python2 -c 'import mercurial' 2> /dev/null ; then \
 | 
			
		||||
		PYTHON=python2 ; \
 | 
			
		||||
	elif python -c 'import mercurial' 2> /dev/null ; then \
 | 
			
		||||
		PYTHON=python ; \
 | 
			
		||||
	fi ; \
 | 
			
		||||
	if [ -n "$$PYTHON" ] ; then \
 | 
			
		||||
		PYTHON=python ; \
 | 
			
		||||
	fi ; \
 | 
			
		||||
	mkdir -p bin ; \
 | 
			
		||||
	for s in git-remote-hg git-hg-helper ; do \
 | 
			
		||||
		printf "%s\n" "#!/usr/bin/env $$PYTHON" > "bin/$$s" ; \
 | 
			
		||||
		tail -n +2 "./$$s" >> "bin/$$s" ; \
 | 
			
		||||
		chmod 755 "bin/$$s" ; \
 | 
			
		||||
		touch -r "./$$s" "bin/$$s" ; \
 | 
			
		||||
	done
 | 
			
		||||
all: doc
 | 
			
		||||
 | 
			
		||||
doc: doc/git-remote-hg.1
 | 
			
		||||
 | 
			
		||||
@@ -36,29 +15,15 @@ doc/git-remote-hg.1: doc/git-remote-hg.txt
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	$(RM) doc/git-remote-hg.1
 | 
			
		||||
	$(RM) -r bin/
 | 
			
		||||
 | 
			
		||||
D = $(DESTDIR)
 | 
			
		||||
 | 
			
		||||
install: build
 | 
			
		||||
install:
 | 
			
		||||
	install -d -m 755 $(D)$(bindir)/
 | 
			
		||||
	install -m 755 bin/git-remote-hg $(D)$(bindir)/git-remote-hg
 | 
			
		||||
	install -m 755 bin/git-hg-helper $(D)$(bindir)/git-hg-helper
 | 
			
		||||
	install -m 755 git-remote-hg $(D)$(bindir)/git-remote-hg
 | 
			
		||||
 | 
			
		||||
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 build test install install-doc clean pypy pypy-upload
 | 
			
		||||
.PHONY: all test install install-doc clean
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										300
									
								
								README.asciidoc
									
									
									
									
									
								
							
							
						
						
									
										300
									
								
								README.asciidoc
									
									
									
									
									
								
							@@ -9,38 +9,14 @@ 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 +91,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 +107,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 +125,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).
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1020
									
								
								git-hg-helper
									
									
									
									
									
								
							
							
						
						
									
										1020
									
								
								git-hg-helper
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1444
									
								
								git-remote-hg
									
									
									
									
									
								
							
							
						
						
									
										1444
									
								
								git-remote-hg
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										45
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								setup.py
									
									
									
									
									
								
							@@ -1,45 +0,0 @@
 | 
			
		||||
# git-remote-hg setuptools script
 | 
			
		||||
 | 
			
		||||
import setuptools
 | 
			
		||||
 | 
			
		||||
# strip leading v
 | 
			
		||||
version = 'v1.0.3'[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",
 | 
			
		||||
    "Programming Language :: Python :: 3",
 | 
			
		||||
    "Programming Language :: Python :: 3.6",
 | 
			
		||||
    "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
 | 
			
		||||
     )
 | 
			
		||||
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
RM ?= rm -f
 | 
			
		||||
 | 
			
		||||
T = main.t main-push.t bidi.t helper.t
 | 
			
		||||
T = main.t bidi.t
 | 
			
		||||
TEST_DIRECTORY := $(CURDIR)
 | 
			
		||||
 | 
			
		||||
export TEST_DIRECTORY
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								test/bidi.t
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								test/bidi.t
									
									
									
									
									
								
							@@ -13,7 +13,13 @@ test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
 | 
			
		||||
 | 
			
		||||
if ! test_have_prereq PYTHON
 | 
			
		||||
then
 | 
			
		||||
	skip_all='skipping remote-hg tests; python with mercurial not available'
 | 
			
		||||
	skip_all='skipping remote-hg tests; python not available'
 | 
			
		||||
	test_done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if ! python2 -c 'import mercurial' > /dev/null 2>&1
 | 
			
		||||
then
 | 
			
		||||
	skip_all='skipping remote-hg tests; mercurial not available'
 | 
			
		||||
	test_done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
@@ -45,7 +51,7 @@ hg_push () {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
hg_log () {
 | 
			
		||||
	hg -R $1 log --debug
 | 
			
		||||
	hg -R $1 log --graph --debug
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
setup () {
 | 
			
		||||
@@ -198,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
 | 
			
		||||
'
 | 
			
		||||
@@ -227,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 &&
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										541
									
								
								test/helper.t
									
									
									
									
									
								
							
							
						
						
									
										541
									
								
								test/helper.t
									
									
									
									
									
								
							@@ -1,541 +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 with 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
 | 
			
		||||
@@ -13,14 +13,20 @@ test -n "$TEST_DIRECTORY" || TEST_DIRECTORY=$(dirname $0)/
 | 
			
		||||
 | 
			
		||||
if ! test_have_prereq PYTHON
 | 
			
		||||
then
 | 
			
		||||
	skip_all='skipping remote-hg tests; python with mercurial not available'
 | 
			
		||||
	skip_all='skipping remote-hg tests; python not available'
 | 
			
		||||
	test_done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if "$PYTHON" -c 'import hggit' > /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 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
 | 
			
		||||
@@ -28,6 +34,15 @@ else
 | 
			
		||||
	test_done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
hg_version=$(python2 -c 'from mercurial import util; print util.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 &&
 | 
			
		||||
@@ -102,13 +117,10 @@ setup () {
 | 
			
		||||
	[extensions]
 | 
			
		||||
	$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
 | 
			
		||||
@@ -120,31 +132,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*" &&
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										314
									
								
								test/main-push.t
									
									
									
									
									
								
							
							
						
						
									
										314
									
								
								test/main-push.t
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
	) &&
 | 
			
		||||
 | 
			
		||||
	(
 | 
			
		||||
	umask 0 &&
 | 
			
		||||
	cd hgrepo &&
 | 
			
		||||
	hg update &&
 | 
			
		||||
	stat content2 >expected &&
 | 
			
		||||
	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
 | 
			
		||||
							
								
								
									
										369
									
								
								test/main.t
									
									
									
									
									
								
							
							
						
						
									
										369
									
								
								test/main.t
									
									
									
									
									
								
							@@ -11,18 +11,15 @@ 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 with mercurial not available'
 | 
			
		||||
	skip_all='skipping remote-hg tests; python not available'
 | 
			
		||||
	test_done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if ! python2 -c 'import mercurial' > /dev/null 2>&1
 | 
			
		||||
then
 | 
			
		||||
	skip_all='skipping remote-hg tests; mercurial not available'
 | 
			
		||||
	test_done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
@@ -84,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
 | 
			
		||||
}
 | 
			
		||||
@@ -176,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
 | 
			
		||||
@@ -442,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
 | 
			
		||||
	) &&
 | 
			
		||||
 | 
			
		||||
@@ -467,52 +467,6 @@ 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" &&
 | 
			
		||||
 | 
			
		||||
@@ -664,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_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_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*" &&
 | 
			
		||||
 | 
			
		||||
	(
 | 
			
		||||
@@ -737,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
 | 
			
		||||
	)
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
test_expect_success 'remote big push force' '
 | 
			
		||||
test_expect_failure 'remote big push force' '
 | 
			
		||||
	test_when_finished "rm -rf hgrepo gitrepo*" &&
 | 
			
		||||
 | 
			
		||||
	setup_big_push
 | 
			
		||||
@@ -771,19 +700,6 @@ 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
 | 
			
		||||
@@ -794,9 +710,9 @@ test_expect_success 'remote big push force' '
 | 
			
		||||
	bad_bmark2:forced-update
 | 
			
		||||
	branches/bad_branch:forced-update
 | 
			
		||||
	EOF
 | 
			
		||||
	fi
 | 
			
		||||
	) &&
 | 
			
		||||
 | 
			
		||||
	check_branch hgrepo default six &&
 | 
			
		||||
	check_branch hgrepo good_branch eight &&
 | 
			
		||||
	check_branch hgrepo bad_branch nine &&
 | 
			
		||||
	check_branch hgrepo new_branch ten &&
 | 
			
		||||
@@ -806,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
 | 
			
		||||
@@ -837,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' '
 | 
			
		||||
@@ -911,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*" &&
 | 
			
		||||
@@ -1028,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" &&
 | 
			
		||||
 | 
			
		||||
	(
 | 
			
		||||
@@ -1045,7 +844,7 @@ testpushupdatesnotes='
 | 
			
		||||
	(
 | 
			
		||||
	cd gitrepo &&
 | 
			
		||||
	echo two > content &&
 | 
			
		||||
	git commit -a -m two &&
 | 
			
		||||
	git commit -a -m two
 | 
			
		||||
	git push
 | 
			
		||||
	) &&
 | 
			
		||||
 | 
			
		||||
@@ -1054,38 +853,6 @@ 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_success 'pull tags' '
 | 
			
		||||
	test_when_finished "rm -rf hgrepo gitrepo" &&
 | 
			
		||||
 | 
			
		||||
@@ -1131,7 +898,7 @@ test_expect_success 'push merged named branch' '
 | 
			
		||||
	git push
 | 
			
		||||
	) &&
 | 
			
		||||
 | 
			
		||||
	cat > expected <<-EOF &&
 | 
			
		||||
	cat > expected <<-EOF
 | 
			
		||||
	Merge
 | 
			
		||||
	three
 | 
			
		||||
	two
 | 
			
		||||
@@ -1172,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
 | 
			
		||||
@@ -1257,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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										394
									
								
								test/sharness.sh
									
									
									
									
									
								
							
							
						
						
									
										394
									
								
								test/sharness.sh
									
									
									
									
									
								
							@@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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,62 +1,12 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
if [ -z "$SHARNESS" ] ; then
 | 
			
		||||
	for d in \
 | 
			
		||||
		"." \
 | 
			
		||||
		"$HOME/share/sharness" \
 | 
			
		||||
		"/usr/local/share/sharness" \
 | 
			
		||||
		"/usr/share/sharness"
 | 
			
		||||
	do
 | 
			
		||||
		f="$d/sharness.sh"
 | 
			
		||||
		if [ -f "$f" ] ; then
 | 
			
		||||
			SHARNESS="$f"
 | 
			
		||||
		fi
 | 
			
		||||
	done
 | 
			
		||||
fi
 | 
			
		||||
if [ -z "$SHARNESS" ] || [ ! -f "$SHARNESS" ] ; then
 | 
			
		||||
	echo "sharness.sh not found" >&2
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
. ./sharness.sh
 | 
			
		||||
 | 
			
		||||
# Prevent sharness from adding the source directory to PATH
 | 
			
		||||
# since the scripts use unversioned python for their shebang
 | 
			
		||||
# but tests should run under the python with mercurial support
 | 
			
		||||
# so create an empty directory and strip it from PATH afterwards
 | 
			
		||||
SHARNESS_BUILD_DIRECTORY="$(mktemp -d)"
 | 
			
		||||
. "$SHARNESS"
 | 
			
		||||
export PATH="${PATH#*:}"
 | 
			
		||||
rmdir "$SHARNESS_BUILD_DIRECTORY"
 | 
			
		||||
 | 
			
		||||
if [ -n "$PYTHON" ] && "$PYTHON" -c 'import mercurial' 2> /dev/null ; then
 | 
			
		||||
	: Use chosen Python version
 | 
			
		||||
elif python3 -c 'import mercurial' 2> /dev/null ; then
 | 
			
		||||
	PYTHON=python3
 | 
			
		||||
elif python2 -c 'import mercurial' 2> /dev/null ; then
 | 
			
		||||
	PYTHON=python2
 | 
			
		||||
elif python -c 'import mercurial' 2> /dev/null ; then
 | 
			
		||||
	PYTHON=python
 | 
			
		||||
fi
 | 
			
		||||
if [ -n "$PYTHON" ] ; then
 | 
			
		||||
test_set_prereq PYTHON
 | 
			
		||||
 | 
			
		||||
	# Change shebang on a copy of scripts to chosen Python version
 | 
			
		||||
	TEST_BIN="$SHARNESS_TRASH_DIRECTORY/bin"
 | 
			
		||||
	mkdir -p "$TEST_BIN"
 | 
			
		||||
	for s in git-remote-hg git-hg-helper ; do
 | 
			
		||||
		printf "%s\n" "#!/usr/bin/env $PYTHON" > "$TEST_BIN/$s"
 | 
			
		||||
		tail -n +2 "$SHARNESS_TEST_DIRECTORY/../$s" >> "$TEST_BIN/$s"
 | 
			
		||||
		chmod u+x "$TEST_BIN/$s"
 | 
			
		||||
	done
 | 
			
		||||
	export PATH="$TEST_BIN${PATH:+:$PATH}"
 | 
			
		||||
	unset TEST_BIN
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
GIT_AUTHOR_EMAIL=author@example.com
 | 
			
		||||
GIT_AUTHOR_NAME='A U Thor'
 | 
			
		||||
GIT_COMMITTER_EMAIL=committer@example.com
 | 
			
		||||
GIT_COMMITTER_NAME='C O Mitter'
 | 
			
		||||
export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
 | 
			
		||||
export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
 | 
			
		||||
# maintain backwards compatible default
 | 
			
		||||
# (as used in remote helper)
 | 
			
		||||
git config --global init.defaultBranch master
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								tools/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tools/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
results.txt
 | 
			
		||||
@@ -1,303 +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'
 | 
			
		||||
require 'tmpdir'
 | 
			
		||||
 | 
			
		||||
$tests = %w[main.t bidi.t hg-git.t]
 | 
			
		||||
$workdir = "#{Dir.home}/.cache/git-remote-hg"
 | 
			
		||||
$builddir = Dir.mktmpdir("git-remote-hg-build-")
 | 
			
		||||
$testoutdir = Dir.mktmpdir("git-remote-hg-tests-")
 | 
			
		||||
 | 
			
		||||
at_exit {
 | 
			
		||||
  FileUtils.remove_entry($builddir)
 | 
			
		||||
  FileUtils.remove_entry($testoutdir)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
@@ -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()
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
		Reference in New Issue
	
	Block a user