summaryrefslogtreecommitdiff
path: root/exporters
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@frugalware.org>2009-07-25 13:12:15 +0200
committerMiklos Vajna <vmiklos@frugalware.org>2009-07-25 13:12:15 +0200
commit122e02c3d7a3c6196f54204174000b6089640899 (patch)
treed04730fa6a6f41f7795fa092f71290d30f708ad9 /exporters
parent5b935b4bb76687c93ecf5c3afc2c3e38256a167e (diff)
parentdd8b6a4e38675f5445557339b96e1afd718f74bb (diff)
downloadbzr-fastimport-122e02c3d7a3c6196f54204174000b6089640899.tar.gz
Merge darcs-fast-export
Diffstat (limited to 'exporters')
-rw-r--r--exporters/darcs/.gitignore3
-rw-r--r--exporters/darcs/Makefile55
-rw-r--r--exporters/darcs/NEWS26
-rw-r--r--exporters/darcs/README192
-rw-r--r--exporters/darcs/TODO6
-rw-r--r--exporters/darcs/asciidoc.conf21
-rwxr-xr-xexporters/darcs/d2x114
-rw-r--r--exporters/darcs/d2x.txt27
-rwxr-xr-xexporters/darcs/darcs-fast-export337
-rw-r--r--exporters/darcs/darcs-fast-export.txt61
-rwxr-xr-xexporters/darcs/darcs-fast-import310
-rw-r--r--exporters/darcs/darcs-fast-import.txt35
-rwxr-xr-xexporters/darcs/git-darcs264
-rw-r--r--exporters/darcs/git-darcs.txt72
-rw-r--r--exporters/darcs/t/Makefile9
-rw-r--r--exporters/darcs/t/bench-results/Makefile5
-rw-r--r--exporters/darcs/t/bench-results/bench-results.gnu6
-rw-r--r--exporters/darcs/t/bench-results/bench-results.py23
-rw-r--r--exporters/darcs/t/bench-tailor.sh59
-rw-r--r--exporters/darcs/t/bench.sh38
-rw-r--r--exporters/darcs/t/data/hungarian.gifbin0 -> 90 bytes
-rw-r--r--exporters/darcs/t/lib.sh303
-rw-r--r--exporters/darcs/t/test-bzr.sh16
-rw-r--r--exporters/darcs/t/test-git-d2x.sh19
-rw-r--r--exporters/darcs/t/test-git-incremental.sh24
-rw-r--r--exporters/darcs/t/test-git-progress.sh18
-rw-r--r--exporters/darcs/t/test-git.sh18
-rw-r--r--exporters/darcs/t/test-hg-d2x.sh12
-rw-r--r--exporters/darcs/t/test-hg.sh16
-rw-r--r--exporters/darcs/t/test2-bzr-d2x.sh19
-rw-r--r--exporters/darcs/t/test2-bzr-incremental.sh21
-rw-r--r--exporters/darcs/t/test2-git-funny-tagname.sh25
-rw-r--r--exporters/darcs/t/test2-git-incremental-specworkdir.sh22
-rw-r--r--exporters/darcs/t/test2-git-incremental.sh21
-rw-r--r--exporters/darcs/t/test2-git.sh18
-rw-r--r--exporters/darcs/t/testimport-bzr-x2d.sh15
-rw-r--r--exporters/darcs/t/testimport-bzr.sh15
-rw-r--r--exporters/darcs/t/testimport-copy.sh26
-rw-r--r--exporters/darcs/t/testimport-darcs.sh17
-rw-r--r--exporters/darcs/t/testimport-deleteall.sh31
-rw-r--r--exporters/darcs/t/testimport-git-incremental.sh16
-rw-r--r--exporters/darcs/t/testimport-git-twoway-gd.sh34
-rw-r--r--exporters/darcs/t/testimport-git-twoway.sh30
-rw-r--r--exporters/darcs/t/testimport-git-x2d.sh15
-rw-r--r--exporters/darcs/t/testimport-git.sh15
-rw-r--r--exporters/darcs/t/testimport-hg-x2d.sh15
-rw-r--r--exporters/darcs/t/testimport-hg.sh16
-rw-r--r--exporters/darcs/t/testimport-rename.sh25
-rwxr-xr-xexporters/darcs/x2d121
-rw-r--r--exporters/darcs/x2d.txt26
50 files changed, 2632 insertions, 0 deletions
diff --git a/exporters/darcs/.gitignore b/exporters/darcs/.gitignore
new file mode 100644
index 0000000..d26377c
--- /dev/null
+++ b/exporters/darcs/.gitignore
@@ -0,0 +1,3 @@
+Changelog
+HEADER.html
+.htaccess
diff --git a/exporters/darcs/Makefile b/exporters/darcs/Makefile
new file mode 100644
index 0000000..0c81c68
--- /dev/null
+++ b/exporters/darcs/Makefile
@@ -0,0 +1,55 @@
+VERSION = 0.9
+DATE := $(shell date +%Y-%m-%d)
+
+INSTALL = /usr/bin/install -c
+DESTDIR =
+prefix = /usr
+bindir = $(prefix)/bin
+mandir = $(prefix)/share/man/man1
+
+MAN_TXT = $(wildcard *.txt)
+MAN_HTML=$(patsubst %.txt,%.html,$(MAN_TXT))
+MAN=$(patsubst %.txt,%.1,$(MAN_TXT))
+
+PROGRAMS = darcs-fast-export darcs-fast-import d2x x2d git-darcs
+
+all: man
+
+install: all
+ $(INSTALL) -d $(DESTDIR)$(bindir)
+ $(INSTALL) -d $(DESTDIR)$(mandir)
+ $(INSTALL) -m755 $(PROGRAMS) $(DESTDIR)$(bindir)
+ $(INSTALL) -m644 *.1 $(DESTDIR)$(mandir)
+
+doc: HEADER.html Changelog html
+
+HEADER.html: README Makefile
+ asciidoc -a toc -a numbered -a sectids -o HEADER.html README
+
+Changelog: .git/refs/heads/master
+ git log >Changelog
+
+%.html: %.txt
+ asciidoc $^
+
+%.1: %.txt asciidoc.conf
+ a2x --asciidoc-opts="-f asciidoc.conf" \
+ -a dfe_version=$(VERSION) -a dfe_date=$(DATE) -f manpage $<
+
+man: $(MAN)
+
+html: $(MAN_HTML)
+
+dist:
+ git archive --format=tar --prefix=darcs-fast-export-$(VERSION)/ $(VERSION) > darcs-fast-export-$(VERSION).tar
+ mkdir -p darcs-fast-export-$(VERSION)
+ git log > darcs-fast-export-$(VERSION)/Changelog
+ tar rf darcs-fast-export-$(VERSION).tar darcs-fast-export-$(VERSION)/Changelog
+ rm -rf darcs-fast-export-$(VERSION)
+ gzip -f -9 darcs-fast-export-$(VERSION).tar
+
+release:
+ git tag -l |grep -q $(VERSION) || dg tag $(VERSION)
+ $(MAKE) dist
+ gpg --comment "See http://vmiklos.hu/gpg/ for info" \
+ -ba darcs-fast-export-$(VERSION).tar.gz
diff --git a/exporters/darcs/NEWS b/exporters/darcs/NEWS
new file mode 100644
index 0000000..1a0daa5
--- /dev/null
+++ b/exporters/darcs/NEWS
@@ -0,0 +1,26 @@
+VERSION DESCRIPTION
+-----------------------------------------------------------------------------
+0.9 - fix handling of accents in tag names
+ - warning fixes for Python-2.6
+ - git-darcs: the add subcommand can now remember d-f-e
+ options
+ - git-darcs: new list, find-darcs and find-git subcommands
+0.8 - revert the "not exporting unchanged files multiple
+ times" optimization, it causes corrupted results in some
+ cases.
+0.7 - new darcs-fast-export option: --progress
+ - massive speedup in darcs-fast-export due to not
+ exporting unchanged files multiple times and reading
+ patches directly
+0.6 - add a new darcs-fast-import script, allowing two-way sync
+ - new darcs-fast-export option: --git-branch
+ - add a new git-darcs script, making two-way sync easy
+0.5 - new --help, --encoding, --authors-file, --working and
+ --logfile options
+ - add "hashed" support (see darcs init -h)
+ - add incremental conversion support for darcs1 as well
+ - add d2x wrapper script
+0.4 - add incremental conversion support
+0.3 - add darcs2 support
+0.2 - add bzr and hg support
+0.1 - initial short and fast version, supporting darcs1->git
diff --git a/exporters/darcs/README b/exporters/darcs/README
new file mode 100644
index 0000000..4b13e3b
--- /dev/null
+++ b/exporters/darcs/README
@@ -0,0 +1,192 @@
+= darcs backend for fast data importers
+Miklos Vajna <vmiklos-at-frugalware-dot-org>
+
+== Purpose and Features
+
+darcs-fast-export is a tool to dump a http://darcs.net/[darcs]
+repository in a format understood by "fast-importers" such as
+http://git.or.cz/[git]
+http://www.kernel.org/pub/software/scm/git/docs/git-fast-import.html[fast-import].
+It exhibits the following _features:_
+
+Fast::
+ darcs-fast-export provides a fast darcs backend for fast-import.
+ See link:t/bench-results/[here] for exact details.
+
+Correct::
+ darcs-fast-export produces correct results in any extreme cases.
+ It has been tested with a collection of large darcs repos (called
+ http://code.haskell.org/darcs/big-zoo/[big-zoo]). And several testcases
+ under the `t/` directory.
+
+Independent::
+ Ideally it should work with any fast importer, but actually it has been
+ tested with git fast-import, bzr fast-import and hg fastimport. (These
+ are the three fast-import implementations available ATM.)
+ +
+ hg fastimport needs three patches. While they are not in the upstream,
+ you can get it from my repository using
++
+----
+$ hg clone static-http://frugalware.org/~vmiklos/hg/hg-fastimport
+----
+
+Formats::
+ It supports the 'darcs-2', 'hashed', and 'old-fashioned-inventory' darcs
+ repository formats.
+
+Incremental conversions::
+ It supports the usual `--export-marks` / `--import-marks` switches to
+ allow incremental conversion.
+
+Wrapper scripts::
+ A wrapper script called `d2x` is available if you find typing
+ `--export-marks` / `--import-marks` all the time boring. A similar one
+ is also provided for the other direction, called `x2d`. Finally, if you
+ want to work on darcs repos with git, you can use the `git-darcs`
+ wrapper.
+
+Author mappings::
+ Supports `--authors-file` option like Git's SVN adaptor, for DARCS
+ repositories that originated in CVS or SVN.
+
+Import script::
+ The pair of `darcs-fast-export`, `darcs-fast-import` is also
+ included in this repo. It has been tested with the fast-expoters of Git,
+ Hg, Bzr and - of course - Darcs itself.
+
+Two-way sync::
+ Using `darcs-fast-export` / `darcs-fast-import`, it is possible to
+ convert a darcs repo to an other VCS, work there, then convert your work
+ back to Darcs (or vica versa). This has been tested with "darcs -> git;
+ hack hack; git -> darcs".
+
+== Usage
+
+See the manpages:
+
+* link:darcs-fast-export.html[darcs-fast-export]
+* link:darcs-fast-import.html[darcs-fast-import]
+* link:d2x.html[d2x]
+* link:x2d.html[x2d]
+* link:git-darcs.html[git-darcs]
+
+=== Example
+
+Assuming that `test/` is a darcs repo, you could do this:
+----
+$ mkdir test.git
+$ cd test.git
+$ git --bare init
+$ cd ..
+$ darcs-fast-export test |(cd test.git; git fast-import)
+----
+
+For more examples (especially for bzr and hg), see the `t/` directory.
+
+== Download
+
+Using git:
+----
+$ git clone git://vmiklos.hu/darcs-fast-export
+----
+
+== Status
+
+In general, darcs-fast-export should work fine. darcs-fast-import has
+known problems with tags - other than that it should be okay. git-darcs
+should work properly as long as you are not paying too much attention to
+the imported tags (newly created tags won't be pushed back).
+
+darcs-fast-export has been tested with the following versions:
+
+Darcs version (see http://bugs.darcs.net/issue844[this bug] on why do
+you need such a new version):
+----
+$ darcs --version
+2.2.0 (release)
+----
+
+Git version:
+----
+$ git --version
+git version 1.6.0.2
+----
+
+Bzr versions:
+----
+$ bzr version
+Bazaar (bzr) 1.12
+$ (cd ~/bzr/fastimport; bzr log --limit 1|grep revno)
+revno: 181
+----
+
+Yes, you need the fastiport plugin from BZR, the last hg release series
+supported by fastimport-0.6 is hg-1.0.x.
+
+Mercurial (Hg) version:
+----
+$ hg version
+Mercurial Distributed SCM (version 1.2.1)
+----
+
+Strictly speaking this document is a wrong place to talk about enabling
+hg plugins. However...
+
+----
+$ cat ~/.hgrc
+[extensions]
+hgext.fastimport=
+----
+
+and once you installed the plugin correctly, you should have something like:
+
+----
+$ ls /usr/lib/python*/site-packages/hgext/fastimport/__init__.py
+/usr/lib/python2.5/site-packages/hgext/fastimport/__init__.py
+----
+
+== Additional resources
+
+You can reach the Changelog link:Changelog[here], and a gitweb interface
+http://vmiklos.hu/gitweb/?p=darcs-fast-export.git[here].
+
+The fast-import stream format documentation is
+http://git.kernel.org/?p=git/git.git;a=blob;f=fast-import.c;hb=HEAD[here]
+if you're interested.
+
+== Alternatives
+
+- http://repo.or.cz/w/darcs2git.git[darcs2git] tries to find conflict
+ resolutions (to map them to merge commits), but it's rather slow
+ because of this. It does not support the darcs2 format and/or
+ incremental conversions, either. darcs-fast-export may support mapping
+ to merge commits later, but not before
+ http://bugs.darcs.net/issue1261[this issue] is addressed.
+
+- http://progetti.arstecnica.it/tailor[tailor] is an any2any VCS
+ converter, but it produces corrupted results when converting the
+ big-zoo - see http://progetti.arstecnica.it/tailor/ticket/171[this
+ ticket].
+
+- http://git.sanityinc.com/?p=darcs-to-git.git[darcs-to-git] is similar
+ to darcs2git, but it fails for the testcases found in the testsuite of
+ darcs-fast-export.
+
+- http://github.com/freshtonic/undarcs/tree/master[undarcs] claims to be
+ fast, but its own README says it produces incorrect results. When I
+ tried, it did not handle the darcs2 format, binary files and incremental
+ support.
+
+== Thanks
+
+- Jason Dagit for helping me with darcs2 issues
+- Shawn O. Pearce and Johannes Schindelin for writing `git-fast-import`
+ / `git-fast-export`
+- Ian Clatworthy for writing bzr fast-import
+- Paul Crowley for writing hg fast-import
+- Matthias Andree for assorted improvements, among them the --help,
+ --encoding and --authors-file features (using Python's optparse), support
+ for hashed repositories, `_darcs/format` interpretation, and mangling
+ whitespace in tags to cope with repos imported into DARCS from CVS.
+- Pieter de Bie for writing git-bzr, which was the base of git-darcs
diff --git a/exporters/darcs/TODO b/exporters/darcs/TODO
new file mode 100644
index 0000000..2f199d1
--- /dev/null
+++ b/exporters/darcs/TODO
@@ -0,0 +1,6 @@
+more intelligent tests, such as detect if the hg fastimport extension is
+not enabled, etc.
+
+parse the patches manually so we can avoid re-adding existing files manually.
+
+avoid darcs apply.
diff --git a/exporters/darcs/asciidoc.conf b/exporters/darcs/asciidoc.conf
new file mode 100644
index 0000000..cb31717
--- /dev/null
+++ b/exporters/darcs/asciidoc.conf
@@ -0,0 +1,21 @@
+ifdef::doctype-manpage[]
+ifdef::backend-docbook[]
+[header]
+template::[header-declarations]
+<refentry>
+ <refentryinfo>
+ <date>{dfe_date}</date>
+ </refentryinfo>
+ <refmeta>
+ <refentrytitle>{mantitle}</refentrytitle>
+ <manvolnum>{manvolnum}</manvolnum>
+ <refmiscinfo class="source">darcs-fast-export</refmiscinfo>
+ <refmiscinfo class="version">{dfe_version}</refmiscinfo>
+ <refmiscinfo class="manual">darcs-fast-export manual</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>{manname}</refname>
+ <refpurpose>{manpurpose}</refpurpose>
+ </refnamediv>
+endif::backend-docbook[]
+endif::doctype-manpage[]
diff --git a/exporters/darcs/d2x b/exporters/darcs/d2x
new file mode 100755
index 0000000..79e18a3
--- /dev/null
+++ b/exporters/darcs/d2x
@@ -0,0 +1,114 @@
+#!/bin/sh
+#
+# d2x - convert darcs repos to git, bzr or hg using fast-import
+#
+# Copyright (c) 2008 by Miklos Vajna <vmiklos@frugalware.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+# USA.
+#
+
+usage()
+{
+ echo "Usage: d2x -f format darcsrepo"
+}
+
+die()
+{
+ echo "$@"
+ usage
+ exit 1
+}
+
+check_up_to_date()
+{
+ upstreamnum=$(cd $origin; darcs show repo|grep 'Num Patches'|sed 's/.*: //')
+ if [ "$upstreamnum" = "$(eval $*)" ]; then
+ echo "No remote changes to pull!"
+ exit 0
+ fi
+}
+
+case $1 in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -f)
+ format="$2"
+ shift 2
+ ;;
+esac
+
+[ -n "$format" ] || die "Target format is not given!"
+
+case $format in
+ git|bzr|hg)
+ ;;
+ *)
+ die "The requested target format is not yet supported!"
+ ;;
+esac
+
+origin="$1"
+shift 1
+
+[ -d "$origin" ] || die "Source repo does not exist!"
+
+# convert to abspath
+cd $origin
+origin=$(pwd)
+
+dmark="$origin.$format/darcs/dfe-marks"
+fmark="$origin.$format/darcs/ffi-marks"
+
+mkdir -p $origin.$format/darcs
+cd $origin.$format
+
+common_opts="--working $origin.$format/darcs/repo --logfile $origin.$format/darcs/log $origin"
+if [ ! -f $dmark ]; then
+ case $format in
+ git)
+ git --bare init
+ darcs-fast-export $* --export-marks=$dmark $common_opts | \
+ git fast-import --export-marks=$fmark
+ ;;
+ bzr)
+ bzr init-repo .
+ darcs-fast-export $* --export-marks=$dmark $common_opts | \
+ bzr fast-import --export-marks=$fmark -
+ ;;
+ hg)
+ hg init
+ darcs-fast-export $* $origin | \
+ hg fastimport /dev/stdin
+ esac
+else
+ case $format in
+ git)
+ check_up_to_date "git rev-list HEAD |wc -l"
+ darcs-fast-export $* --export-marks=$dmark --import-marks=$dmark $common_opts | \
+ git fast-import --export-marks=$fmark --import-marks=$fmark
+ ;;
+ bzr)
+ check_up_to_date "cd master; bzr revno"
+ darcs-fast-export $* --export-marks=$dmark --import-marks=$dmark $common_opts | \
+ bzr fast-import --export-marks=$fmark --import-marks=$fmark -
+ ;;
+ hg)
+ die "Incremental conversion to hg is not yet supported by hg fastimport."
+ ;;
+ esac
+fi
diff --git a/exporters/darcs/d2x.txt b/exporters/darcs/d2x.txt
new file mode 100644
index 0000000..41732fd
--- /dev/null
+++ b/exporters/darcs/d2x.txt
@@ -0,0 +1,27 @@
+= d2x(1)
+
+== NAME
+
+d2x - convert darcs repos to git, bzr or hg using fast-import
+
+== SYNOPSIS
+
+d2x -f <format> <darcsrepo> [<darcs-fast-export options>]
+
+== DESCRIPTION
+
+d2x is a wrapper script that just automates doing an initial or
+continuing an incremental conversion. All it does is initializing the
+target repo, starting darcs-fast-export and the relevant importer with
+the proper switches and pipe the exporter's output to the importer's
+standard input.
+
+== OPTIONS
+
+--help::
+ Display usage.
+
+-f <format>::
+ Specify the format of the target repo. Currently supported targets are
+ git, bzr and hg. Incremental conversion is supported in case of git and
+ bzr.
diff --git a/exporters/darcs/darcs-fast-export b/exporters/darcs/darcs-fast-export
new file mode 100755
index 0000000..7fa9663
--- /dev/null
+++ b/exporters/darcs/darcs-fast-export
@@ -0,0 +1,337 @@
+#!/usr/bin/env python
+
+"""
+
+ darcs-fast-export - darcs backend for fast data importers
+
+ Copyright (c) 2008 Miklos Vajna <vmiklos@frugalware.org>
+ Copyright (c) 2008 Matthias Andree <matthias.andree@gmx.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+"""
+
+import xml.dom.minidom
+import xml.parsers.expat
+import os
+import sys
+import gzip
+import time
+import shutil
+import subprocess
+import optparse
+import re
+
+sys = reload(sys)
+sys.setdefaultencoding("utf-8")
+
+def __get_zone():
+ now = time.localtime()
+ if time.daylight and now[-1]:
+ offset = time.altzone
+ else:
+ offset = time.timezone
+ hours, minutes = divmod(abs(offset), 3600)
+ if offset > 0:
+ sign = "-"
+ else:
+ sign = "+"
+ return sign, hours, minutes
+
+def get_zone_str():
+ sign, hours, minutes = __get_zone()
+ return "%s%02d%02d" % (sign, hours, minutes // 60)
+
+def get_zone_int():
+ sign, hours, minutes = __get_zone()
+ ret = hours*3600+minutes*60
+ if sign == "-":
+ ret *= -1
+ return ret
+
+def get_patchname(patch):
+ ret = []
+ s = ""
+ if patch.attributes['inverted'].value == 'True':
+ s = "UNDO: "
+ ret.append(s + patch.getElementsByTagName("name")[0].childNodes[0].data)
+ lines = patch.getElementsByTagName("comment")
+ if lines:
+ for i in lines[0].childNodes[0].data.split('\n'):
+ if not i.startswith("Ignore-this: "):
+ ret.append(i)
+ return "\n".join(ret).encode('utf-8')
+
+def get_author(patch):
+ """darcs allows any freeform string, but fast-import has a more
+ strict format, so fix up broken author names here."""
+
+ author = patch.attributes['author'].value
+ if author in authormap:
+ author = authormap[author]
+ if not len(author):
+ author = "darcs-fast-export <darcs-fast-export>"
+ # add missing name
+ elif not ">" in author:
+ author = "%s <%s>" % (author.split('@')[0], author)
+ # avoid double quoting
+ elif author[0] == '"' and author[-1] == '"':
+ author = author[1:-1]
+ # name after email
+ elif author[-1] != '>':
+ author = author[author.index('>')+2:] + ' ' + author[:author.index('>')+1]
+ return author.encode('utf-8')
+
+def get_date(patch):
+ try:
+ date = time.strptime(patch, "%Y%m%d%H%M%S")
+ except ValueError:
+ date = time.strptime(patch[:19] + patch[-5:], '%a %b %d %H:%M:%S %Y')
+ return int(time.mktime(date)) + get_zone_int()
+
+def progress(s):
+ print "progress [%s] %s" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), s)
+ sys.stdout.flush()
+
+def log(s):
+ logsock.write("[%s] %s" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), s))
+ logsock.flush()
+
+hashes = []
+def parse_inventory(sock=None):
+ prev = None
+ nextprev = False
+ buf = []
+ if not sock:
+ sock = open(os.path.join("_darcs", "hashed_inventory"))
+ for i in sock.readlines():
+ if i.startswith("hash"):
+ buf.insert(0, i[6:-1])
+ if i.startswith("Starting with inventory:"):
+ nextprev = True
+ elif nextprev:
+ prev = i[:-1]
+ nextprev = False
+ sock.close()
+ for i in buf:
+ hashes.insert(0, i)
+ if prev:
+ sock = gzip.open(os.path.join("_darcs", "inventories", prev))
+ parse_inventory(sock)
+
+# Option Parser
+usage="%prog [options] darcsrepo"
+opp = optparse.OptionParser(usage=usage)
+opp.add_option("--import-marks", metavar="IFILE",
+ help="read state for incremental imports from IFILE")
+opp.add_option("--export-marks", metavar="OFILE",
+ help="write state for incremental imports from OFILE")
+opp.add_option("--encoding",
+ help="encoding of log [default: %default], if unspecified and input isn't utf-8, guess")
+opp.add_option("--authors-file", metavar="F",
+ help="read author transformations in old=new format from F")
+opp.add_option("--working", metavar="W",
+ help="working directory which is removed at the end of non-incremental conversions")
+opp.add_option("--logfile", metavar="L",
+ help="log file which contains the output of external programs invoked during the conversion")
+opp.add_option("--git-branch", metavar="B",
+ help="git branch [default: refs/heads/master]")
+opp.add_option("--progress", metavar="P",
+ help="insert progress statements after every n commit [default: 100]")
+(options, args) = opp.parse_args()
+if len(args) < 1:
+ opp.error("darcsrepo required")
+
+export_marks = []
+import_marks = []
+if options.import_marks:
+ sock = open(options.import_marks)
+ for i in sock.readlines():
+ line = i.strip()
+ if not len(line):
+ continue
+ import_marks.append(line.split(' ')[1])
+ export_marks.append(line)
+ sock.close()
+
+# read author mapping file in gitauthors format,
+# i. e. in=out (one per # line)
+authormap = {}
+if options.authors_file:
+ sock = open(options.authors_file)
+ authormap = dict([i.strip().split('=',1) for i in sock])
+ sock.close()
+
+origin = os.path.abspath(args[0])
+if options.working:
+ working = os.path.abspath(options.working)
+else:
+ working = "%s.darcs" % origin
+patchfile = "%s.patch" % origin
+if options.logfile:
+ logfile = os.path.abspath(options.logfile)
+else:
+ logfile = "%s.log" % origin
+logsock = open(logfile, "a")
+if options.git_branch:
+ git_branch = options.git_branch
+else:
+ git_branch = "refs/heads/master"
+
+if options.progress:
+ prognum = int(options.progress)
+else:
+ prognum = 100
+
+progress("getting list of patches")
+if not len(import_marks):
+ sock = os.popen("darcs changes --xml --reverse --repo %s" % origin)
+else:
+ sock = os.popen("darcs changes --xml --reverse --repo %s --from-match 'hash %s'" % (origin, import_marks[-1]))
+buf = sock.read()
+sock.close()
+# this is hackish. we need to escape some bad chars, otherwise the xml
+# will not be valid
+buf = buf.replace('\x1b', '^[')
+if options.encoding:
+ xmldoc = xml.dom.minidom.parseString(unicode(buf, options.encoding).encode('utf-8'))
+else:
+ try:
+ xmldoc = xml.dom.minidom.parseString(buf)
+ except xml.parsers.expat.ExpatError:
+ import chardet
+ progress("encoding is not utf8, guessing charset")
+ encoding = chardet.detect(buf)['encoding']
+ progress("detected encoding is %s" % encoding)
+ xmldoc = xml.dom.minidom.parseString(unicode(buf, encoding).encode('utf-8'))
+sys.stdout.flush()
+
+darcs2 = False
+oldfashionedpatch = True
+cwd = os.getcwd()
+if os.path.exists(os.path.join(origin, "_darcs", "format")):
+ sock = open(os.path.join(origin, "_darcs", "format"))
+ format = [x.strip() for x in sock]
+ sock.close()
+ darcs2 = 'darcs-2' in format
+ oldfashionedpatch = not 'hashed' in format
+if not oldfashionedpatch:
+ progress("parsing the inventory")
+ os.chdir(origin)
+ parse_inventory()
+if not options.import_marks or not os.path.exists(working):
+ # init the tmp darcs repo
+ os.mkdir(working)
+ os.chdir(working)
+ if darcs2:
+ os.system("darcs init --darcs-2")
+ else:
+ os.system("darcs init --old-fashioned-inventory")
+else:
+ os.chdir(working)
+if options.import_marks:
+ sock = os.popen("darcs pull -a --match 'hash %s' %s" % (import_marks[-1], origin))
+ log("Building/updating working directory:\n%s" % sock.read())
+ sock.close()
+
+# this is the number of the NEXT patch
+count = 1
+patches = xmldoc.getElementsByTagName('patch')
+if len(import_marks):
+ patches = patches[1:]
+ count = len(import_marks) + 1
+if len(export_marks):
+ # this is the mark number of the NEXT patch
+ markcount = int(export_marks[-1].split(' ')[0][1:]) + 1
+else:
+ markcount = count
+# this may be huge and we need it many times
+patchnum = len(patches)
+
+if not len(import_marks):
+ progress("starting export, repo has %d patches" % patchnum)
+else:
+ progress("continuing export, %d patches to convert" % patchnum)
+paths = []
+for i in patches:
+ # apply the patch
+ hash = i.attributes['hash'].value
+ buf = ["\nNew patches:\n"]
+ if oldfashionedpatch:
+ sock = gzip.open(os.path.join(origin, "_darcs", "patches", hash))
+ else:
+ sock = gzip.open(os.path.join(origin, "_darcs", "patches", hashes[count-1]))
+ buf.append(sock.read())
+ sock.close()
+ sock = os.popen("darcs changes --context")
+ buf.append(sock.read())
+ sock.close()
+ sock = subprocess.Popen(["darcs", "apply", "--allow-conflicts"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ sock.stdin.write("".join(buf))
+ sock.stdin.close()
+ log("Applying %s:\n%s" % (hash, sock.stdout.read()))
+ sock.stdout.close()
+ message = get_patchname(i)
+ # export the commit
+ print "commit %s" % git_branch
+ print "mark :%s" % markcount
+ if options.export_marks:
+ export_marks.append(":%s %s" % (markcount, hash))
+ date = get_date(i.attributes['date'].value)
+ print "committer %s %s %s" % (get_author(i), date, get_zone_str())
+ print "data %d\n%s" % (len(message), message)
+ if markcount > 1:
+ print "from :%s" % (markcount-1)
+ # export the files
+ for j in paths:
+ print "D %s" % j
+ paths = []
+ for (root, dirs, files) in os.walk ("."):
+ for f in files:
+ j = os.path.normpath(os.path.join(root, f))
+ if j.startswith("_darcs") or "-darcs-backup" in j:
+ continue
+ paths.append(j)
+ sock = open(j)
+ buf = sock.read()
+ sock.close()
+ # darcs does not track the executable bit :/
+ print "M 644 inline %s" % j
+ print "data %s\n%s" % (len(buf), buf)
+ if message[:4] == "TAG ":
+ tag = re.sub('[^\xe9-\xf8\w.\-]+', '_', message[4:].strip().split('\n')[0]).strip('_')
+ print "tag %s" % tag
+ print "from :%s" % markcount
+ print "tagger %s %s %s" % (get_author(i), date, get_zone_str())
+ print "data %d\n%s" % (len(message), message)
+ if count % prognum == 0:
+ progress("%d/%d patches" % (count, patchnum))
+ count += 1
+ markcount += 1
+
+os.chdir(cwd)
+
+if not options.export_marks:
+ shutil.rmtree(working)
+logsock.close()
+
+if options.export_marks:
+ progress("writing export marks")
+ sock = open(options.export_marks, 'w')
+ sock.write("\n".join(export_marks))
+ sock.write("\n")
+ sock.close()
+
+progress("finished")
diff --git a/exporters/darcs/darcs-fast-export.txt b/exporters/darcs/darcs-fast-export.txt
new file mode 100644
index 0000000..f0dabf9
--- /dev/null
+++ b/exporters/darcs/darcs-fast-export.txt
@@ -0,0 +1,61 @@
+= darcs-fast-export(1)
+
+== NAME
+
+darcs-fast-export - darcs frontend to git fast-import
+
+== SYNOPSIS
+
+darcs-fast-export [<options>] <darcsrepo>
+
+== DESCRIPTION
+
+darcs-fast-export expects one argument, the path to the source darcs
+repository. It will print the git fast-import format on standard output
+(stdout).
+
+The script can produce the fast-import stream format from the darcs
+repository. It supports incremental conversion as well, via the
+--import-marks / --export-marks switches.
+
+== OPTIONS
+
+-h, --help::
+ Display usage.
+
+--import-marks::
+ Import marks from a given file. This is read at the beginning of the
+ conversion at once. Use it if you want to continue an incremental
+ conversion.
+
+--export-marks::
+ Export marks to a given file at the end of the conversion. It can be the
+ same as the one for --import-marks as it is written only once at the
+ end. Use it if you want to be able to incrementally update the target
+ repository later.
+
+--encoding::
+ The encoding of the author names and commit messages in the repository.
+ The default is utf-8. If it is not the default, it will be guessed.
+ Given that it takes some time, you can explicitly specify it as an
+ option to make the conversion faster. Content in the output will encoded
+ as utf-8 and will be written that way to the target repository, unless
+ the importer re-encodes it again to some other character set.
+
+--working::
+ The conversion is done by applying the patches one by one and recording
+ the state of the working directory. You can specify the path of this
+ directory using this option.
+
+--logfile::
+ The output of external commands are redirected to a log file. You can
+ specify the path of that file with this parameter.
+
+--git-branch::
+ There is only one branch in one darcs repository, but the fast-import
+ stream format allows multiple branches, thus the exporter has to name
+ darcs's branch. The default value is 'refs/heads/master'.
+
+--progress::
+ Insert progress statements after every <n> patches, to be shown by the
+ fast importer during import.
diff --git a/exporters/darcs/darcs-fast-import b/exporters/darcs/darcs-fast-import
new file mode 100755
index 0000000..2955164
--- /dev/null
+++ b/exporters/darcs/darcs-fast-import
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+
+"""
+
+ darcs-fast-export - darcs backend for fast data exporters
+
+ Copyright (c) 2008 Miklos Vajna <vmiklos@frugalware.org>
+ Copyright (c) 2008 Matthias Andree <matthias.andree@gmx.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+"""
+
+import sys
+import os
+import re
+import time
+import shutil
+import optparse
+import subprocess
+
+class Handler:
+ def __init__(self):
+ self.marks = {}
+ self.files = []
+ self.prevfiles = None
+ self.ch = None
+ self.line = None
+ self.unread_line = False
+ self.eof = False
+ self.debug = False
+ self.export_marks = []
+ self.import_marks = []
+
+ def read_next_line(self):
+ if self.unread_line:
+ self.unread_line = False
+ return
+ self.line = ""
+ if self.eof:
+ return
+ if self.ch:
+ self.line += self.ch
+ self.ch = None
+ buf = sys.stdin.readline()
+ if not len(buf):
+ self.eof = True
+ else:
+ self.line += buf
+ if self.debug:
+ print "read_next_line: '%s'" % self.line
+
+ def read(self, length):
+ buf = ""
+ if self.ch:
+ buf += self.ch
+ self.ch = None
+ buf += sys.stdin.read(length)
+ if self.debug:
+ print "read: '%s'" % buf
+ return buf
+
+ def skip_optional_lf(self):
+ self.ch = self.read(1)
+ if self.ch == "\n":
+ self.ch = None
+
+ def bug(self, s):
+ raise Exception(s)
+
+ def get_date(self, ts, tz):
+ # int(ts) is seconds since epoch. Since we're trying to
+ # capture both the absolute time of the commit and the
+ # localtime in the timezone of the committer, we need to turn
+ # the (seconds-since-epoch, committer-timezone-offset) pair
+ # that we get from the git-fast-export stream format into a
+ # localized-time-plus-timezone-marker string that darcs will
+ # accept. Therefore, we parse the timezone-offset (which
+ # looks like +0500 or +0000 or -0730 or something) and add it
+ # to seconds-since-epoch before calling gmtime().
+ mo = re.search(r'^([\+\-])(\d\d)(\d\d)$', tz)
+ offset = 60*60*int(mo.group(2)) + 60*int(mo.group(3))
+ if mo.group(1) == "-":
+ offset = -offset
+ offset_time = int(ts) + offset
+ s = time.strftime("%a %b %d %H:%M:%S %Y", time.gmtime(offset_time))
+ items = s.split(' ')
+ return " ".join(items[:-1]) + " " + tz + " " + items[-1]
+
+ def handle_mark(self):
+ if self.line.startswith("mark :"):
+ self.mark_num = int(self.line[6:-1])
+ self.read_next_line()
+
+ def handle_data(self):
+ if not self.line.startswith("data "):
+ self.bug("Expected 'data n' command, found: '%s'" % self.line[:-1])
+ length = int(self.line[5:-1])
+ self.buf = self.read(length)
+ self.skip_optional_lf()
+
+ def handle_blob(self):
+ self.read_next_line()
+ self.handle_mark()
+ self.handle_data()
+ self.marks[self.mark_num] = self.buf
+
+ def handle_ident(self, s):
+ items = s.split(' ')
+ self.ident = " ".join(items[:-2])
+ self.date = self.get_date(items[-2], items[-1])
+
+ def handle_msg(self):
+ items = self.buf.split('\n')
+ self.short = items[0]
+ self.long = "\n".join(items[1:])
+
+ def handle_tag(self):
+ version = self.line[:-1].split(' ')[1]
+ self.read_next_line()
+ if self.line.startswith("from "):
+ self.read_next_line()
+ if self.line.startswith("tagger "):
+ self.handle_ident(self.line[7:-1])
+ self.read_next_line()
+ self.handle_data()
+ self.skip_optional_lf()
+ sock = subprocess.Popen(["darcs", "tag", "--pipe"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ buf = [self.date, self.ident, version]
+ sock.stdin.write("\n".join(buf))
+ sock.stdin.close()
+ self.log("Tagging %s:\n%s" % (version, sock.stdout.read()))
+ sock.stdout.close()
+
+ def handle_commit(self):
+ if not self.prevfiles and self.options.import_marks:
+ # first commit in an incremental continued
+ # import
+ for (root, dirs, files) in os.walk("."):
+ for i in files:
+ path = os.path.normpath(os.path.join(root, i))
+ if path.startswith("_darcs") or "-darcs-backup" in path:
+ continue
+ self.files.append(path)
+ self.prevfiles = self.files[:]
+ adds = []
+
+ self.read_next_line()
+ self.handle_mark()
+ if self.line.startswith("author "):
+ self.handle_ident(self.line[7:-1])
+ self.read_next_line()
+ if self.line.startswith("committer "):
+ self.handle_ident(self.line[10:-1])
+ self.read_next_line()
+ self.handle_data()
+ self.skip_optional_lf()
+ self.handle_msg()
+ self.read_next_line()
+ if self.line.startswith("from "):
+ self.read_next_line()
+ while self.line.startswith("merge "):
+ self.read_next_line()
+ while len(self.line) > 0:
+ if self.line.startswith("deleteall"):
+ path = self.line[2:-1]
+ for path in self.files:
+ os.unlink(path)
+ self.files = []
+ elif self.line.startswith("D "):
+ path = self.line[2:-1]
+ if os.path.exists(path):
+ os.unlink(path)
+ if path in self.files:
+ self.files.remove(path)
+ elif self.line.startswith("R "):
+ os.system("darcs mv %s" % self.line[2:])
+ elif self.line.startswith("C "):
+ src, dest = self.line[:-1].split(' ')[1:]
+ shutil.copy(src.strip('"'), dest.strip('"'))
+ os.system("darcs add %s" % dest)
+ elif self.line.startswith("M "):
+ items = self.line.split(' ')
+ path = items[3][:-1]
+ sock = open(path, "w")
+ if items[2] != "inline":
+ idx = int(items[2][1:])
+ sock.write(self.marks[idx])
+ del self.marks[idx]
+ else:
+ self.read_next_line()
+ self.handle_data()
+ sock.write(self.buf)
+ sock.close()
+ if path not in self.prevfiles:
+ adds.append(path)
+ if path not in self.files:
+ self.files.append(path)
+ else:
+ self.unread_line = True
+ break
+ self.read_next_line()
+ if not len(self.line):
+ break
+
+ for i in adds:
+ os.system("darcs add %s" % i)
+ sock = subprocess.Popen(["darcs", "record", "--ignore-times", "-a", "--pipe"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ buf = [self.date, self.ident, self.short, self.long]
+ sock.stdin.write("\n".join(buf))
+ sock.stdin.close()
+ self.log("Recording :%s:\n%s" % (self.mark_num, sock.stdout.read()))
+ sock.stdout.close()
+
+ if self.options.export_marks:
+ # yeah, an xml parser would be better, but
+ # should we mess with encodings just because of
+ # this? i hope not
+ sock = os.popen("darcs changes --last=1 --xml", "r")
+ buf = sock.read()
+ sock.close()
+ hash = buf.split('\n')[1].split("'")[-2]
+ self.export_marks.append(":%s %s" % (self.mark_num, hash))
+
+ def handle_progress(self, s):
+ print "progress [%s] %s" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), s.strip())
+ sys.stdout.flush()
+
+ def handle_opts(self):
+ # Option Parser
+ usage="%prog [options]"
+ opp = optparse.OptionParser(usage=usage)
+ opp.add_option("--import-marks", metavar="IFILE",
+ help="read state for incremental imports from IFILE")
+ opp.add_option("--export-marks", metavar="OFILE",
+ help="write state for incremental imports to OFILE")
+ opp.add_option("--logfile", metavar="L",
+ help="log file which contains the output of external programs invoked during the conversion")
+ (self.options, args) = opp.parse_args()
+
+ if self.options.logfile:
+ logfile = self.options.logfile
+ else:
+ logfile = "_darcs/import.log"
+ self.logsock = open(os.path.abspath(logfile), "a")
+
+ def log(self, s):
+ self.logsock.write("[%s] %s" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), s))
+ self.logsock.flush()
+
+ def handle_export_marks(self):
+ if self.options.export_marks:
+ sock = open(self.options.export_marks, 'w')
+ sock.write("\n".join(self.export_marks))
+ sock.write("\n")
+ sock.close()
+
+ def handle_import_marks(self):
+ if self.options.import_marks:
+ sock = open(self.options.import_marks)
+ for i in sock.readlines():
+ line = i.strip()
+ if not len(line):
+ continue
+ self.import_marks.append(line.split(' ')[1])
+ self.export_marks.append(line)
+ sock.close()
+
+ def handle(self):
+ self.handle_opts()
+ self.handle_import_marks()
+
+ while not self.eof:
+ self.read_next_line()
+ if not len(self.line[:-1]):
+ pass
+ elif self.line.startswith("blob"):
+ self.handle_blob()
+ elif self.line.startswith("commit"):
+ self.handle_commit()
+ elif self.line.startswith("tag"):
+ self.handle_tag()
+ elif self.line.startswith("reset"):
+ self.read_next_line()
+ if not self.line.startswith("from "):
+ self.unread_line = True
+ elif self.line.startswith("checkpoint"):
+ pass
+ elif self.line.startswith("progress"):
+ self.handle_progress(self.line[9:])
+ else:
+ self.bug("'%s': invalid command" % self.line[:-1])
+
+ self.handle_export_marks()
+
+if __name__ == "__main__":
+ h = Handler()
+ h.handle()
diff --git a/exporters/darcs/darcs-fast-import.txt b/exporters/darcs/darcs-fast-import.txt
new file mode 100644
index 0000000..09c7b1e
--- /dev/null
+++ b/exporters/darcs/darcs-fast-import.txt
@@ -0,0 +1,35 @@
+= darcs-fast-import(1)
+
+== NAME
+
+darcs-fast-import - darcs backend to the 'fast-import stream' format
+
+== SYNOPSIS
+
+darcs-fast-import [<options>]
+
+== DESCRIPTION
+
+darcs-fast-import can produce a darcs repository from a fast-import
+stream, read from the standard input. It supports incremental conversion
+as well, via the --import-marks / --export-marks switches.
+
+== OPTIONS
+
+-h, --help::
+ Display usage.
+
+--import-marks::
+ Import marks from a given file. This is read at the beginning of the
+ conversion at once. Use it if you want to continue an incremental
+ conversion.
+
+--export-marks::
+ Export marks to a given file at the end of the conversion. It can be the
+ same as the one for --import-marks as it is written only once at the
+ end. Use it if you want to be able to incrementally update the target
+ repository later.
+
+--logfile::
+ The output of external commands are redirected to a log file. You can
+ specify the path of that file with this parameter.
diff --git a/exporters/darcs/git-darcs b/exporters/darcs/git-darcs
new file mode 100755
index 0000000..eb70338
--- /dev/null
+++ b/exporters/darcs/git-darcs
@@ -0,0 +1,264 @@
+#!/bin/bash
+#
+# git-darcs - bidirectional operation between a darcs repo and git
+#
+# Copyright (c) 2008 by Miklos Vajna <vmiklos@frugalware.org>
+#
+# Based on git-bzr, which is
+#
+# Copyright (c) 2008 Pieter de Bie <pdebie@ai.rug.nl>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+# USA.
+#
+
+add()
+{
+ name="$1"
+ shift
+ location="$1"
+ shift
+ if ! [ -n "$name" -a -n "$location" ]; then
+ echo "Usage: git darcs add name location [darcs-fast-export options]"
+ exit
+ fi
+ if git remote show |grep -q $name; then
+ echo "There is already a remote with that name"
+ exit
+ fi
+ if [ -n "$(git config git-darcs.$name.location)" ]; then
+ echo "There is already a darcs repo with that name"
+ exit
+ fi
+ if [ ! -d $location/_darcs ]; then
+ echo "Remote is not a darcs repository"
+ exit
+ fi
+ git config git-darcs.$name.location $location
+ git config git-darcs.$name.darcs-fast-export-options "$*"
+ echo "Darcs repo $name added. You can fetch it with 'git darcs fetch $name'"
+ if ! [ -z "$*" ]; then
+ echo "darcs-fast-export will get options: $*"
+ fi
+}
+
+get_location()
+{
+ l=$(git config git-darcs.$remote.location)
+ if [ -z "$l" ]; then
+ echo "Cannot find darcs remote with name '$remote'." >&2
+ exit
+ fi
+ echo $l
+}
+
+fetch()
+{
+ remote="$1"
+ shift
+ if ! [ -n "$remote" -a -z "$*" ]; then
+ echo "Usage: git darcs fetch reponame"
+ exit
+ fi
+ location=$(get_location $remote)
+ git_map=$git_dir/darcs-git/$remote-git-map
+ darcs_map=$git_dir/darcs-git/$remote-darcs-map
+ common_opts="--working $git_dir/darcs-git/repo --logfile $git_dir/darcs-git/fetch.log --git-branch=darcs/$remote"
+ dfe_opts=$(git config git-darcs.$remote.darcs-fast-export-options)
+ if [ ! -f $git_map -a ! -f $darcs_map ]; then
+ echo "There doesn't seem to be an existing refmap."
+ echo "Doing an initial import"
+ mkdir -p $git_dir/darcs-git
+ darcs-fast-export --export-marks=$darcs_map $common_opts $dfe_opts $location | \
+ git fast-import --export-marks=$git_map
+ elif [ -f $git_map -a -f $darcs_map ]; then
+ echo "Updating remote $remote"
+ old_rev=$(git rev-parse darcs/$remote)
+ darcs-fast-export --import-marks=$darcs_map --export-marks=$darcs_map $common_opts $dfe_opts $location | \
+ git fast-import --quiet --import-marks=$git_map --export-marks=$git_map
+ new_rev=$(git rev-parse darcs/$remote)
+ if [ "$old_rev" != "$new_rev" ]; then
+ echo "Fetched the following updates:"
+ git shortlog $old_rev..$new_rev
+ else
+ echo "Nothing fetched."
+ exit
+ fi
+ else
+ echo "One of the mapfiles is missing! Something went wrong!"
+ exit
+ fi
+}
+
+pull()
+{
+ remote="$1"
+ shift
+ if ! [ -n "$remote" -a -z "$*" ]; then
+ echo "Usage: git darcs pull reponame"
+ exit
+ fi
+ fetch $remote
+ # see if we need to merge or rebase
+ branch=$(git symbolic-ref HEAD|sed 's|.*/||')
+ if [ "$(git config branch.$branch.rebase)" = "true" ]; then
+ git rebase darcs/$remote
+ else
+ git merge darcs/$remote
+ fi
+}
+
+push()
+{
+ remote="$1"
+ shift
+ if ! [ -n "$remote" -a -z "$*" ]; then
+ echo "Usage: git darcs push reponame"
+ exit
+ fi
+ location=$(get_location $remote)
+ if [ -n "$(git rev-list --left-right HEAD...darcs/$remote | sed -n '/^>/ p')" ]; then
+ echo "HEAD is not a strict child of $remote, cannot push. Merge first"
+ exit
+ fi
+ if [ -z "$(git rev-list --left-right HEAD...darcs/$remote | sed -n '/^</ p')" ]; then
+ echo "Nothing to push. Commit something first"
+ exit
+ fi
+ git_map=$git_dir/darcs-git/$remote-git-map
+ darcs_map=$git_dir/darcs-git/$remote-darcs-map
+ if [ ! -f $git_map -o ! -f $darcs_map ]; then
+ echo "We do not have refmapping yet. Then how can I push?"
+ exit
+ fi
+ echo "Pushing the following updates:"
+ git shortlog darcs/$remote..
+ git fast-export --import-marks=$git_map --export-marks=$git_map HEAD | \
+ (cd $location; darcs-fast-import --import-marks=$darcs_map --export-marks=$darcs_map \
+ --logfile $git_dir/darcs-git/push.log)
+ if [ $? == 0 ]; then
+ git update-ref darcs/$remote HEAD
+ fi
+}
+
+# List the darcs remotes
+list()
+{
+ if [ -z "$*" ]
+ then
+ git config -l | sed -n -e '/git-darcs\..*/ {s/git-darcs\.//; s/\.location=.*//p}'
+ exit
+ elif [ "$#" -eq 1 ]
+ then
+ case $1 in
+ -v|--verbose)
+ git config -l | sed -n -e '/git-darcs\..*/ {s/git-darcs\.//; s/\.location=/\t/p}'
+ exit
+ ;;
+ esac
+ fi
+ echo "Usage: git darcs list [-v|--verbose]"
+ exit 1
+}
+
+# Find the darcs commit(s) supporting a git SHA1 prefix
+find_darcs()
+{
+ sha1="$1"
+ shift
+ if [ -z "$sha1" -o -n "$*" ]
+ then
+ echo "Usage: git darcs find-darcs <sha1-prefix>"
+ exit 1
+ fi
+ for remote in $git_dir/darcs/*
+ do
+ remote=`basename $remote`
+ git_map=$git_dir/darcs-git/$remote-git-map
+ darcs_map=$git_dir/darcs-git/$remote-darcs-map
+ if [ ! -f $git_map -o ! -f $darcs_map ]
+ then
+ echo "Missing mappings for remote $remote"
+ exit 1
+ fi
+ for row in `sed -n -e "/:.* $sha1.*/ s/[^ ]*/&/p" $git_map`
+ do
+ sed -n -e "/$row / {s/[^ ]*//; s/.*/$remote\t&/p}" $darcs_map
+ done
+ done
+}
+
+# Find the git commit(s) supporting a darcs patch prefix
+find_git()
+{
+ patch="$1"
+ shift
+ if [ -z "$patch" -o -n "$*" ]
+ then
+ echo "Usage: git darcs find-git <patch-prefix>"
+ exit 1
+ fi
+ for remote in $git_dir/darcs/*
+ do
+ remote=`basename $remote`
+ git_map=$git_dir/darcs-git/$remote-git-map
+ darcs_map=$git_dir/darcs-git/$remote-darcs-map
+ if [ ! -f $git_map -o ! -f $darcs_map ]
+ then
+ echo "Missing mappings for remote $remote"
+ exit 1
+ fi
+ for row in `sed -n -e "/:.* $patch.*/ s/[^ ]*/&/p" $darcs_map`
+ do
+ sed -n -e "/$row / {s/[^ ]* \(.*\)/$remote\t\1/p}" $git_map
+ done
+ done
+}
+
+git rev-parse 2> /dev/null
+if [ $? != 0 ]; then
+ echo "Must be inside a git repository to work"
+ exit
+fi
+
+git_dir=$(git rev-parse --git-dir)
+# make it absolute
+cd $git_dir
+git_dir=$(pwd)
+cd - >/dev/null
+command="$1"
+shift
+
+case $command in
+ add|push|fetch|pull|list)
+ ;;
+ find-darcs)
+ command=find_darcs
+ ;;
+ find-git)
+ command=find_git
+ ;;
+ *)
+ echo "Usage: git darcs [COMMAND] [OPTIONS]"
+ echo "Commands: add, push, fetch, pull, list, find-darcs, find-git"
+ exit
+ ;;
+esac
+
+
+up=$(git rev-parse --show-cdup)
+[ -z "$up" ] && up="."
+cd $up
+$command "$@"
diff --git a/exporters/darcs/git-darcs.txt b/exporters/darcs/git-darcs.txt
new file mode 100644
index 0000000..7558329
--- /dev/null
+++ b/exporters/darcs/git-darcs.txt
@@ -0,0 +1,72 @@
+= git-darcs(1)
+
+== NAME
+
+git-darcs - a bidirectional git - darcs gateway
+
+== SYNOPSIS
+
+git-darcs <command> <options>
+
+== DESCRIPTION
+
+git darcs can convert a darcs repo to a git one, can update such an
+existing git repo later, and finally can push back your changes from the
+git repo to the darcs one.
+
+A typical workflow is:
+
+----
+$ mkdir git-repo
+$ cd git-repo
+$ git init
+$ git darcs add upstream ../darcs-repo
+$ git darcs pull upstream
+
+... hack, hack, hack ...
+
+$ git darcs push upstream
+----
+
+== GLOBAL OPTIONS
+
+-h, --help::
+ Display usage.
+
+== COMMANDS
+
+The supported commands are the followings:
+
+add::
+ This can register a new darcs repo in the git one, so that you
+ can fetch from it. The syntax is `add nick path [dfe-options]`.
+ Add any options you want to be passed to darcs-fast-export,
+ like --encoding=utf-8, or --authors-file AUTHORMAP. Remember
+ that if AUTHORMAP is not absolute, it will be interpreted
+ relative to the git repository's root directory.
+
+push::
+ Transfers your changes created in the current branch back the
+ darcs one. The syntax is `push nick`.
+
+fetch::
+ Downloads changes from the darcs repo and updates the
+ `darcs/<nick>` branch. None of your local branches are updated.
+
+pull::
+ Calls `fetch` then `git merge` or `git rebase` based on the
+ `branch.<branchname>.rebase` configuration setting, where `<branchname>`
+ is the current branch. The default is - just like with `git pull` - is
+ to `git merge`.
+
+list::
+ List the name [and location] of each registered darcs repo.
+ The syntax is `list [-v|--verbose]`.
+
+find-darcs::
+ Searches for darcs patches matching a SHA1 prefix.
+ The syntax is `find-darcs <sha1-prefix>`.
+
+find-git::
+ Searches for git commits matching a darcs patch prefix.
+ The syntax is `find-git <patch-prefix>`.
diff --git a/exporters/darcs/t/Makefile b/exporters/darcs/t/Makefile
new file mode 100644
index 0000000..de8a7ab
--- /dev/null
+++ b/exporters/darcs/t/Makefile
@@ -0,0 +1,9 @@
+T = $(wildcard test*.sh)
+
+all: $(T)
+ @echo "passed $$(echo $(T)|wc -w) tests."
+
+$(T):
+ @echo "*** $@ ***"; sh $@
+
+.PHONY: $(T)
diff --git a/exporters/darcs/t/bench-results/Makefile b/exporters/darcs/t/bench-results/Makefile
new file mode 100644
index 0000000..0157f69
--- /dev/null
+++ b/exporters/darcs/t/bench-results/Makefile
@@ -0,0 +1,5 @@
+bench-results.png: bench-results.gnu bench-results.dat
+ gnuplot bench-results.gnu
+
+bench-results.dat: bench-results.py $(wildcard ../darcs-benchmark/big-zoo/*.log)
+ python bench-results.py > bench-results.dat
diff --git a/exporters/darcs/t/bench-results/bench-results.gnu b/exporters/darcs/t/bench-results/bench-results.gnu
new file mode 100644
index 0000000..f4e8917
--- /dev/null
+++ b/exporters/darcs/t/bench-results/bench-results.gnu
@@ -0,0 +1,6 @@
+set terminal png
+set output 'bench-results.png'
+unset key
+set xlabel "number of patches"
+set ylabel "elapsed time in hours"
+plot 'bench-results.dat' with linespoints
diff --git a/exporters/darcs/t/bench-results/bench-results.py b/exporters/darcs/t/bench-results/bench-results.py
new file mode 100644
index 0000000..fbb834b
--- /dev/null
+++ b/exporters/darcs/t/bench-results/bench-results.py
@@ -0,0 +1,23 @@
+from glob import glob
+import re
+
+def cmp_data(a, b):
+ return cmp(a[0], b[0])
+
+logs = glob("../darcs-benchmark/big-zoo/*.log")
+
+data = []
+
+for i in logs:
+ sock = open(i)
+ for j in sock.readlines():
+ if "Num Patches:" in j:
+ patches = int(j.split(": ")[1].strip())
+ elif j.startswith("real"):
+ l = re.sub("real\t([0-9]+)m([0-9.]+)s\n", r"\1 \2", j).split(" ")
+ secs = int(l[0])*60 + float(l[1])
+ hours = secs / 3600
+ data.append([patches, hours])
+data.sort(cmp=cmp_data)
+for i in data:
+ print "%s %s" % (i[0], i[1])
diff --git a/exporters/darcs/t/bench-tailor.sh b/exporters/darcs/t/bench-tailor.sh
new file mode 100644
index 0000000..7567f7b
--- /dev/null
+++ b/exporters/darcs/t/bench-tailor.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+create_config()
+{
+ cd $1
+ mypath=$(pwd)
+ cd - >/dev/null
+ myname=$(basename $mypath)
+
+ cat > config << EOF
+[DEFAULT]
+encoding-errors-policy = replace
+
+[$myname]
+source = darcs:$myname
+target = git:$myname
+
+[darcs:$myname]
+subdir = darcs
+repository = $mypath
+
+[git:$myname]
+subdir = git
+repository = $mypath.git
+EOF
+}
+
+PATH=$HOME/darcs/tailor:$PATH
+if [ ! -d darcs-benchmark ]; then
+ darcs get http://code.haskell.org/darcs/darcs-benchmark
+ cd darcs-benchmark
+else
+ cd darcs-benchmark
+ darcs pull -a
+fi
+sh initialise.sh
+cd big-zoo
+if [ -n "$1" ]; then
+ targets=$1
+else
+ targets=*_play.tar.gz
+fi
+for i in $targets
+do
+ echo "benchmarking $i"
+ rm -rf _playground
+ tar xf $i
+ cd _playground
+ log="../$i.tailor-$(tailor --version).log"
+ create_config sandbox
+ sh -c 'time tailor --configfile config' 2>&1 |tee $log
+ if diff --exclude _darcs --exclude .git -Nur sandbox git >/dev/null; then
+ echo "ok, the result is correct" >> $log
+ else
+ echo "ouch, the result is corrupted" >> $log
+ exit 1
+ fi
+ cd ..
+done
diff --git a/exporters/darcs/t/bench.sh b/exporters/darcs/t/bench.sh
new file mode 100644
index 0000000..a4b3d0d
--- /dev/null
+++ b/exporters/darcs/t/bench.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# this is a test as well, but it would take a lot of time, so don't
+# prefix it with 'test'.
+
+. lib.sh
+
+if [ ! -d darcs-benchmark ]; then
+ darcs get http://code.haskell.org/darcs/darcs-benchmark
+ cd darcs-benchmark
+else
+ cd darcs-benchmark
+ darcs pull -a
+fi
+sh initialise.sh
+cd big-zoo
+if [ -n "$1" ]; then
+ targets=$1
+else
+ targets=*_play.tar.gz
+fi
+for i in $targets
+do
+ echo "benchmarking $i"
+ rm -rf _playground
+ tar xf $i
+ cd _playground
+ log="../$i.d-f-e-$(git describe).log"
+ sh -c 'time d2x -f git sandbox' 2>&1 |tee $log
+ darcs show repo --repodir sandbox |egrep -v 'Root|Cache|Default' >> $log
+ if diff_git sandbox >/dev/null; then
+ echo "ok, the result is correct" >> $log
+ else
+ echo "ouch, the result is corrupted" >> $log
+ exit 1
+ fi
+ cd ..
+done
diff --git a/exporters/darcs/t/data/hungarian.gif b/exporters/darcs/t/data/hungarian.gif
new file mode 100644
index 0000000..41a36fe
--- /dev/null
+++ b/exporters/darcs/t/data/hungarian.gif
Binary files differ
diff --git a/exporters/darcs/t/lib.sh b/exporters/darcs/t/lib.sh
new file mode 100644
index 0000000..3df0a8a
--- /dev/null
+++ b/exporters/darcs/t/lib.sh
@@ -0,0 +1,303 @@
+export DARCS_EMAIL="user@example.com"
+export GIT_PAGER=cat
+export PATH="$(pwd)/..:$PATH"
+pypath="/$(python -c 'from distutils import sysconfig; print sysconfig.get_python_lib()[1:]')/"
+
+_drrec()
+{
+ darcs rec --ignore-times "$@"
+}
+
+_drrec_multiline()
+{
+ echo -e "`LANG= LC_ALL= date +"%a %b %d %H:%M:%S %Z %Y"`
+$DARCS_EMAIL
+$@" | darcs rec --ignore-times -a --pipe .
+}
+
+_drrecamend()
+{
+ echo y |darcs amend-rec --ignore-times -a
+}
+
+create_darcs()
+{
+ rm -rf $1
+ mkdir -p $1
+ cd $1
+ darcs init $2
+ echo A > file
+ darcs add file
+ _drrec -a -m A
+ cd ..
+ rm -rf $1.tmp
+ darcs get $1 $1.tmp
+ cd $1
+ echo B > file
+ _drrec -a -m B
+ cd ../$1.tmp
+ echo C > file
+ _drrec -a -m C
+ cd ../$1
+ darcs pull -a ../$1.tmp
+ echo D > file
+ _drrec_multiline "first line
+second line
+third line"
+ darcs tag 1.0
+ echo e > file
+ _drrec -a -m e
+ echo f > file
+ _drrec --author="éáõû <$DARCS_EMAIL>" -a -m f
+ echo g > file
+ _drrec --author="" -a -m g
+ cp ../data/hungarian.gif .
+ darcs add hungarian.gif
+ _drrec -a -m "add a binary file"
+ rm file
+ echo test > file2
+ darcs add file2
+ _drrec -a -m "replace file with file2"
+ touch file3
+ darcs add file3
+ _drrec -a -m "add empty file"
+ rm file3
+ _drrec -a -m "remove file"
+ mkdir dir dir2
+ darcs add dir
+ darcs add dir2
+ _drrec -a -m "add empty dirs"
+ darcs mv dir dir-p
+ darcs mv dir2 dir2-p
+ _drrec -a -m "rename empty dirs"
+ echo a > a
+ echo b > b
+ darcs add a b
+ _drrec -a -m "add a b"
+ rm b
+ _drrec -a -m "remove and rename"
+ darcs mv a b
+ _drrecamend
+ cd ..
+}
+
+create_bzr()
+{
+ rm -rf $1
+ mkdir -p $1
+ cd $1
+ bzr init $2
+ echo A > file
+ bzr add file
+ bzr commit -m A
+ cd ..
+ rm -rf $1.tmp
+ bzr branch $1 $1.tmp
+ cd $1
+ echo B > file
+ bzr commit -m B
+ cd ../$1.tmp
+ echo C > file
+ bzr commit -m C
+ cd ../$1
+ bzr merge ../$1.tmp
+ echo D > file
+ bzr resolve file
+ echo "first line
+second line
+third line" | bzr commit -F /dev/stdin
+ bzr tag 1.0
+ echo e > file
+ bzr commit -m e
+ #echo f > file
+ #bzr commit --author="éáõû <$DARCS_EMAIL>" -m f
+ #echo g > file
+ #_drrec --author="" -a -m g
+ cp ../data/hungarian.gif .
+ bzr add hungarian.gif
+ bzr commit -m "add a binary file"
+ rm file
+ echo test > file2
+ bzr add file2
+ bzr commit -m "replace file with file2"
+ touch file3
+ bzr add file3
+ bzr commit -m "add empty file"
+ rm file3
+ bzr commit -m "remove file"
+ cd ..
+}
+
+create_hg()
+{
+ rm -rf $1
+ mkdir -p $1
+ cd $1
+ hg init $2
+ echo A > file
+ hg add file
+ hg commit -m A
+ cd ..
+ rm -rf $1.tmp
+ hg clone $1 $1.tmp
+ cd $1
+ echo B > file
+ hg commit -m B
+ cd ../$1.tmp
+ echo C > file
+ hg commit -m C
+ cd ../$1
+ hg pull ../$1.tmp
+ hg merge
+ echo D > file
+ echo "first line
+second line
+third line" | hg commit -l /dev/stdin
+ hg tag 1.0
+ echo e > file
+ hg commit -m e
+ #echo f > file
+ #bzr commit --author="éáõû <$DARCS_EMAIL>" -m f
+ #echo g > file
+ #_drrec --author="" -a -m g
+ cp ../data/hungarian.gif .
+ hg add hungarian.gif
+ hg commit -m "add a binary file"
+ hg rm file
+ echo test > file2
+ hg add file2
+ hg commit -m "replace file with file2"
+ touch file3
+ hg add file3
+ hg commit -m "add empty file"
+ hg rm file3
+ hg commit -m "remove file"
+ cd ..
+}
+create_git()
+{
+ rm -rf $1
+ mkdir -p $1
+ cd $1
+ git init $2
+ echo A > file
+ git add file
+ git commit -a -m A
+ echo B > file
+ git commit -a -m B
+ git checkout -b tmp HEAD~1
+ echo C > file
+ git commit -a -m C
+ git checkout master
+ git merge tmp
+ echo D > file
+ echo "first line
+second line
+third line" | git commit -a -F -
+ git branch -d tmp
+ git tag 1.0
+ echo e > file
+ git commit -a -m e
+ echo f > file
+ git config i18n.commitencoding ISO-8859-2
+ git commit --author="éáõû <$DARCS_EMAIL>" -a -m f
+ cp ../data/hungarian.gif .
+ git add hungarian.gif
+ git commit -a -m "add a binary file"
+ rm file
+ echo test > file2
+ git add file2
+ git commit -a -m "replace file with file2"
+ touch file3
+ git add file3
+ git commit -a -m "add empty file"
+ rm file3
+ git commit -a -m "remove file"
+ cd ..
+}
+
+diff_git()
+{
+ rm -rf $1.git.nonbare
+ git clone -q $1.git $1.git.nonbare
+ diff --exclude _darcs --exclude .git --exclude '*-darcs-backup*' -Nur $1.git.nonbare $1
+ return $?
+}
+
+diff_importgit()
+{
+ diff --exclude _darcs --exclude .git --exclude '*-darcs-backup*' -Nur $1 $1.darcs
+ return $?
+}
+
+diff_importhg()
+{
+ diff --exclude _darcs --exclude .hg --exclude '*-darcs-backup*' --exclude 'hg-export.*' \
+ --exclude '.hgtags' --exclude '*.orig' -Nur $1 $1.darcs
+ return $?
+}
+
+diff_importdarcs()
+{
+ diff --exclude _darcs --exclude '*-darcs-backup*' -Nur $1 $2
+ return $?
+}
+
+diff_importbzr()
+{
+ diff --exclude _darcs --exclude .bzr --exclude '*-darcs-backup*' -Nur $1 $1.darcs
+ return $?
+}
+
+diff_bzr()
+{
+ cd $1.bzr/trunk
+ bzr update
+ cd - >/dev/null
+ diff --exclude _darcs --exclude .bzr --exclude '*-darcs-backup*' -Nur $1.bzr/trunk $1
+ return $?
+}
+
+diff_hg()
+{
+ diff --exclude _darcs --exclude .hg --exclude '*-darcs-backup*' -Nur $1.hg $1
+ return $?
+}
+
+die()
+{
+ echo "fatal: $@"
+ exit 1
+}
+
+upd_file_darcs()
+{
+ cd $1
+ echo $3 > $2
+ _drrec -a -m "updated '$2' to '$3'"
+ cd ..
+}
+
+upd_file_git()
+{
+ cd $1
+ echo $3 > $2
+ git commit -a -m "updated '$2' to '$3'"
+ cd ..
+}
+
+upd_file_bzr()
+{
+ cd $1
+ echo $3 > $2
+ bzr commit -m "updated '$2' to '$3'"
+ cd ..
+}
+
+upd_file_hg()
+{
+ cd $1
+ echo $3 > $2
+ hg commit -m "updated '$2' to '$3'"
+ cd ..
+}
diff --git a/exporters/darcs/t/test-bzr.sh b/exporters/darcs/t/test-bzr.sh
new file mode 100644
index 0000000..778b778
--- /dev/null
+++ b/exporters/darcs/t/test-bzr.sh
@@ -0,0 +1,16 @@
+. lib.sh
+
+create_darcs test --old-fashioned-inventory
+
+rm -rf test.darcs test.bzr
+mkdir test.bzr
+cd test.bzr
+bzr init-repo .
+cd ..
+if [ "$1" != "--stdout" ]; then
+ darcs-fast-export test |(cd test.bzr; bzr fast-import -)
+ diff_bzr test
+ exit $?
+else
+ darcs-fast-export test
+fi
diff --git a/exporters/darcs/t/test-git-d2x.sh b/exporters/darcs/t/test-git-d2x.sh
new file mode 100644
index 0000000..60868be
--- /dev/null
+++ b/exporters/darcs/t/test-git-d2x.sh
@@ -0,0 +1,19 @@
+. lib.sh
+
+create_darcs test --old-fashioned-inventory
+
+rm -rf test.git
+if [ "$1" != "--stdout" ]; then
+ d2x -f git test
+ diff_git test || die "initial conversion differs"
+ upd_file_darcs test file2 upd_contents
+ d2x -f git test
+ diff_git test || die "update differs"
+ upd_file_darcs test hungarian.gif "binary to text"
+ d2x -f git test
+ diff_git test || die "update2 differs"
+ d2x -f git test
+ diff_git test || die "update3 (noop) differs"
+else
+ darcs-fast-export test
+fi
diff --git a/exporters/darcs/t/test-git-incremental.sh b/exporters/darcs/t/test-git-incremental.sh
new file mode 100644
index 0000000..0b822e7
--- /dev/null
+++ b/exporters/darcs/t/test-git-incremental.sh
@@ -0,0 +1,24 @@
+. lib.sh
+
+create_darcs test --old-fashioned-inventory
+
+rm -rf test.darcs test.git
+mkdir test.git
+cd test.git
+git --bare init
+cd ..
+if [ "$1" != "--stdout" ]; then
+ dmark="$(pwd)/test.dfe-marks"
+ gmark="$(pwd)/test.gfi-marks"
+ rm -f $mark $gmark
+ darcs-fast-export --export-marks=$dmark test |(cd test.git; git fast-import --export-marks=$gmark)
+ diff_git test || die "initial conversion differs"
+ upd_file_darcs test file2 upd_contents
+ darcs-fast-export --export-marks=$dmark --import-marks=$dmark test |(cd test.git; git fast-import --export-marks=$gmark --import-marks=$gmark)
+ diff_git test || die "update differs"
+ upd_file_darcs test hungarian.gif "binary to text"
+ darcs-fast-export --export-marks=$dmark --import-marks=$dmark test |(cd test.git; git fast-import --export-marks=$gmark --import-marks=$gmark)
+ diff_git test || die "update2 differs"
+else
+ darcs-fast-export test
+fi
diff --git a/exporters/darcs/t/test-git-progress.sh b/exporters/darcs/t/test-git-progress.sh
new file mode 100644
index 0000000..1eb371c
--- /dev/null
+++ b/exporters/darcs/t/test-git-progress.sh
@@ -0,0 +1,18 @@
+. lib.sh
+
+create_darcs test --old-fashioned-inventory
+
+rm -rf test.darcs test.git
+mkdir test.git
+cd test.git
+git --bare init
+cd ..
+if [ "$1" != "--stdout" ]; then
+ darcs-fast-export --progres 2 test |(cd test.git; git fast-import)
+ if [ $? = 0 ]; then
+ diff_git test
+ exit $?
+ fi
+else
+ darcs-fast-export test
+fi
diff --git a/exporters/darcs/t/test-git.sh b/exporters/darcs/t/test-git.sh
new file mode 100644
index 0000000..c95fa94
--- /dev/null
+++ b/exporters/darcs/t/test-git.sh
@@ -0,0 +1,18 @@
+. lib.sh
+
+create_darcs test --old-fashioned-inventory
+
+rm -rf test.darcs test.git
+mkdir test.git
+cd test.git
+git --bare init
+cd ..
+if [ "$1" != "--stdout" ]; then
+ darcs-fast-export test |(cd test.git; git fast-import)
+ if [ $? = 0 ]; then
+ diff_git test
+ exit $?
+ fi
+else
+ darcs-fast-export test
+fi
diff --git a/exporters/darcs/t/test-hg-d2x.sh b/exporters/darcs/t/test-hg-d2x.sh
new file mode 100644
index 0000000..cc59bbe
--- /dev/null
+++ b/exporters/darcs/t/test-hg-d2x.sh
@@ -0,0 +1,12 @@
+. lib.sh
+
+create_darcs test --old-fashioned-inventory
+
+rm -rf test.hg
+if [ "$1" != "--stdout" ]; then
+ d2x -f hg test
+ diff_hg test
+ exit $?
+else
+ darcs-fast-export test
+fi
diff --git a/exporters/darcs/t/test-hg.sh b/exporters/darcs/t/test-hg.sh
new file mode 100644
index 0000000..9827375
--- /dev/null
+++ b/exporters/darcs/t/test-hg.sh
@@ -0,0 +1,16 @@
+. lib.sh
+
+create_darcs test --old-fashioned-inventory
+
+rm -rf test.darcs test.hg
+mkdir test.hg
+cd test.hg
+hg init
+cd ..
+if [ "$1" != "--stdout" ]; then
+ darcs-fast-export test |(cd test.hg; hg fastimport /dev/stdin)
+ diff_hg test
+ exit $?
+else
+ darcs-fast-export test
+fi
diff --git a/exporters/darcs/t/test2-bzr-d2x.sh b/exporters/darcs/t/test2-bzr-d2x.sh
new file mode 100644
index 0000000..28820d9
--- /dev/null
+++ b/exporters/darcs/t/test2-bzr-d2x.sh
@@ -0,0 +1,19 @@
+. lib.sh
+
+create_darcs test2 --darcs-2
+
+rm -rf test2.bzr
+if [ "$1" != "--stdout" ]; then
+ d2x -f bzr test2
+ diff_bzr test2 || die "initial conversion differs"
+ upd_file_darcs test2 file2 upd_contents
+ d2x -f bzr test2
+ diff_bzr test2 || die "update differs"
+ upd_file_darcs test2 hungarian.gif "binary to text"
+ d2x -f bzr test2
+ diff_bzr test2 || die "update2 differs"
+ d2x -f bzr test2
+ diff_bzr test2 || die "update3 (noop) differs"
+else
+ darcs-fast-export test2
+fi
diff --git a/exporters/darcs/t/test2-bzr-incremental.sh b/exporters/darcs/t/test2-bzr-incremental.sh
new file mode 100644
index 0000000..ece1623
--- /dev/null
+++ b/exporters/darcs/t/test2-bzr-incremental.sh
@@ -0,0 +1,21 @@
+. lib.sh
+
+create_darcs test2 --darcs-2
+
+rm -rf test2.darcs test2.bzr
+mkdir test2.bzr
+cd test2.bzr
+bzr init-repo .
+cd ..
+if [ "$1" != "--stdout" ]; then
+ dmark="$(pwd)/test2.dfe-marks"
+ bmark="$(pwd)/test2.bfi-marks"
+ rm -f $mark $gmark
+ darcs-fast-export --export-marks=$dmark test2 |(cd test2.bzr; bzr fast-import --export-marks=$bmark -)
+ diff_bzr test2 || die "initial conversion differs"
+ upd_file_darcs test2 file2 upd_contents
+ darcs-fast-export --export-marks=$dmark --import-marks=$dmark test2 |(cd test2.bzr; bzr fast-import --export-marks=$bmark --import-marks=$bmark -)
+ diff_bzr test2 || die "update differs"
+else
+ darcs-fast-export test2
+fi
diff --git a/exporters/darcs/t/test2-git-funny-tagname.sh b/exporters/darcs/t/test2-git-funny-tagname.sh
new file mode 100644
index 0000000..ae1465f
--- /dev/null
+++ b/exporters/darcs/t/test2-git-funny-tagname.sh
@@ -0,0 +1,25 @@
+. lib.sh
+
+create_darcs test2 --darcs-2
+cd test2
+darcs tag "this :just (won't work; die)"
+darcs tag "accent-tag-éáőű"
+cd ..
+
+rm -rf test2.darcs test2.git
+mkdir test2.git
+cd test2.git
+git --bare init
+cd ..
+if [ "$1" != "--stdout" ]; then
+ darcs-fast-export test2 |(cd test2.git; git fast-import)
+ ret=$?
+ if [ $ret = 0 ]; then
+ diff_git test2
+ exit $?
+ else
+ exit $ret
+ fi
+else
+ darcs-fast-export test2
+fi
diff --git a/exporters/darcs/t/test2-git-incremental-specworkdir.sh b/exporters/darcs/t/test2-git-incremental-specworkdir.sh
new file mode 100644
index 0000000..937bb46
--- /dev/null
+++ b/exporters/darcs/t/test2-git-incremental-specworkdir.sh
@@ -0,0 +1,22 @@
+. lib.sh
+
+create_darcs test2 --darcs-2
+
+rm -rf test2.darcs test2.git
+mkdir test2.git
+cd test2.git
+git --bare init
+mkdir darcs
+cd ..
+if [ "$1" != "--stdout" ]; then
+ dmark="$(pwd)/test2.git/darcs/test2.dfe-marks"
+ gmark="$(pwd)/test2.git/darcs/test2.gfi-marks"
+ rm -f $mark $gmark
+ darcs-fast-export --export-marks=$dmark test2 --working test2.git/darcs/repo |(cd test2.git; git fast-import --export-marks=$gmark)
+ diff_git test2 || die "initial conversion differs"
+ upd_file_darcs test2 file2 upd_contents
+ darcs-fast-export --export-marks=$dmark --import-marks=$dmark test2 --working test2.git/darcs/repo |(cd test2.git; git fast-import --export-marks=$gmark --import-marks=$gmark)
+ diff_git test2 || die "update differs"
+else
+ darcs-fast-export test2
+fi
diff --git a/exporters/darcs/t/test2-git-incremental.sh b/exporters/darcs/t/test2-git-incremental.sh
new file mode 100644
index 0000000..1afcfc1
--- /dev/null
+++ b/exporters/darcs/t/test2-git-incremental.sh
@@ -0,0 +1,21 @@
+. lib.sh
+
+create_darcs test2 --darcs-2
+
+rm -rf test2.darcs test2.git
+mkdir test2.git
+cd test2.git
+git --bare init
+cd ..
+if [ "$1" != "--stdout" ]; then
+ dmark="$(pwd)/test2.dfe-marks"
+ gmark="$(pwd)/test2.gfi-marks"
+ rm -f $mark $gmark
+ darcs-fast-export --export-marks=$dmark test2 |(cd test2.git; git fast-import --export-marks=$gmark)
+ diff_git test2 || die "initial conversion differs"
+ upd_file_darcs test2 file2 upd_contents
+ darcs-fast-export --export-marks=$dmark --import-marks=$dmark test2 |(cd test2.git; git fast-import --export-marks=$gmark --import-marks=$gmark)
+ diff_git test2 || die "update differs"
+else
+ darcs-fast-export test2
+fi
diff --git a/exporters/darcs/t/test2-git.sh b/exporters/darcs/t/test2-git.sh
new file mode 100644
index 0000000..8c723de
--- /dev/null
+++ b/exporters/darcs/t/test2-git.sh
@@ -0,0 +1,18 @@
+. lib.sh
+
+create_darcs test2 --darcs-2
+
+rm -rf test2.darcs test2.git
+mkdir test2.git
+cd test2.git
+git --bare init
+cd ..
+if [ "$1" != "--stdout" ]; then
+ darcs-fast-export test2 |(cd test2.git; git fast-import)
+ if [ $? = 0 ]; then
+ diff_git test2
+ exit $?
+ fi
+else
+ darcs-fast-export test2
+fi
diff --git a/exporters/darcs/t/testimport-bzr-x2d.sh b/exporters/darcs/t/testimport-bzr-x2d.sh
new file mode 100644
index 0000000..790bbfd
--- /dev/null
+++ b/exporters/darcs/t/testimport-bzr-x2d.sh
@@ -0,0 +1,15 @@
+. lib.sh
+
+create_bzr test
+
+rm -rf test.darcs
+x2d -f bzr test
+diff_importbzr test || die "initial conversion differs"
+upd_file_bzr test file2 upd_contents
+x2d -f bzr test
+diff_importbzr test || die "update differs"
+upd_file_bzr test hungarian.gif "binary to text"
+x2d -f bzr test
+diff_importbzr test || die "update2 differs"
+x2d -f bzr test
+diff_importbzr test || die "update3 (noop) differs"
diff --git a/exporters/darcs/t/testimport-bzr.sh b/exporters/darcs/t/testimport-bzr.sh
new file mode 100644
index 0000000..fc899b7
--- /dev/null
+++ b/exporters/darcs/t/testimport-bzr.sh
@@ -0,0 +1,15 @@
+. lib.sh
+
+create_bzr test
+
+rm -rf test.darcs
+mkdir test.darcs
+cd test.darcs
+darcs init
+cd ..
+(cd test; bzr fast-export .) | (cd test.darcs; darcs-fast-import)
+if [ $? != 0 ]; then
+ exit 1
+fi
+diff_importbzr test
+exit $?
diff --git a/exporters/darcs/t/testimport-copy.sh b/exporters/darcs/t/testimport-copy.sh
new file mode 100644
index 0000000..37b8bc0
--- /dev/null
+++ b/exporters/darcs/t/testimport-copy.sh
@@ -0,0 +1,26 @@
+. lib.sh
+
+rm -rf test
+mkdir test
+cd test
+git init
+echo a > file
+git add file
+git commit -m a1
+cp file file2
+git add file2
+git commit -m b
+cd ..
+
+rm -rf test.darcs
+mkdir test.darcs
+cd test.darcs
+darcs init
+cd ..
+(cd test; git fast-export -C -C HEAD) > out
+cat out | (cd test.darcs; darcs-fast-import)
+if [ $? != 0 ]; then
+ exit 1
+fi
+diff_importgit test
+exit $?
diff --git a/exporters/darcs/t/testimport-darcs.sh b/exporters/darcs/t/testimport-darcs.sh
new file mode 100644
index 0000000..b003dfd
--- /dev/null
+++ b/exporters/darcs/t/testimport-darcs.sh
@@ -0,0 +1,17 @@
+. lib.sh
+
+create_darcs test2 --darcs-2
+
+rm -rf test2.importdarcs test2.darcs
+mkdir test2.importdarcs
+cd test2.importdarcs
+darcs init
+cd ..
+
+darcs-fast-export test2 | (cd test2.importdarcs; darcs-fast-import)
+
+if [ $? != 0 ]; then
+ exit 1
+fi
+diff_importdarcs test2 test2.importdarcs
+exit $?
diff --git a/exporters/darcs/t/testimport-deleteall.sh b/exporters/darcs/t/testimport-deleteall.sh
new file mode 100644
index 0000000..dd10976
--- /dev/null
+++ b/exporters/darcs/t/testimport-deleteall.sh
@@ -0,0 +1,31 @@
+. lib.sh
+
+rm -rf test
+mkdir test
+cd test
+git init
+echo a > file
+git add file
+echo A > file2
+git add file2
+git commit -m a12
+git rm file*
+echo b>file3
+git add file3
+git commit -m b
+cd ..
+
+rm -rf test.darcs
+mkdir test.darcs
+cd test.darcs
+darcs init
+cd ..
+(cd test; git fast-export --progress=2 HEAD) > out
+sed -i '/^D file$/d' out
+sed -i 's/^D file2$/deleteall/' out
+cat out | (cd test.darcs; darcs-fast-import)
+if [ $? != 0 ]; then
+ exit 1
+fi
+diff_importgit test
+exit $?
diff --git a/exporters/darcs/t/testimport-git-incremental.sh b/exporters/darcs/t/testimport-git-incremental.sh
new file mode 100644
index 0000000..dbd3600
--- /dev/null
+++ b/exporters/darcs/t/testimport-git-incremental.sh
@@ -0,0 +1,16 @@
+. lib.sh
+
+create_git test
+
+rm -rf test.darcs
+mkdir test.darcs
+cd test.darcs
+darcs init
+cd ..
+gmark="$(pwd)/test.gfe-marks"
+dmark="$(pwd)/test.dfi-marks"
+(cd test; git fast-export --export-marks=$gmark HEAD) | (cd test.darcs; darcs-fast-import --export-marks=$dmark)
+diff_importgit test || die "initial conversion differs"
+upd_file_git test file2 upd_contents
+(cd test; git fast-export --export-marks=$gmark --import-marks=$gmark HEAD) | (cd test.darcs; darcs-fast-import --export-marks=$dmark --import-marks=$dmark)
+diff_importgit test || die "update differs"
diff --git a/exporters/darcs/t/testimport-git-twoway-gd.sh b/exporters/darcs/t/testimport-git-twoway-gd.sh
new file mode 100644
index 0000000..ec8b5d5
--- /dev/null
+++ b/exporters/darcs/t/testimport-git-twoway-gd.sh
@@ -0,0 +1,34 @@
+. lib.sh
+
+create_darcs test
+
+rm -rf test.git
+mkdir test.git
+cd test.git
+git init
+git darcs add upstream ../test
+git darcs pull upstream
+cd ..
+diff_git test || die "initial fetch differs"
+upd_file_darcs test file2 upd_contents
+cd test.git
+git darcs pull upstream
+cd ..
+diff_git test || die "fetch #1 differs"
+upd_file_git test.git file2 upd_contents2
+cd test.git
+git darcs push upstream
+cd ..
+diff_git test || die "push #1 difers"
+upd_file_darcs test file2 upd_contents3
+upd_file_darcs test file2 upd_contents32
+cd test.git
+git darcs pull upstream
+cd ..
+diff_git test || die "fetch #2 (multiple commits) differs"
+upd_file_git test.git file2 upd_contents4
+upd_file_git test.git file2 upd_contents42
+cd test.git
+git darcs push upstream
+cd ..
+diff_git test || die "push #2 (multiple commits) differs"
diff --git a/exporters/darcs/t/testimport-git-twoway.sh b/exporters/darcs/t/testimport-git-twoway.sh
new file mode 100644
index 0000000..a3b930c
--- /dev/null
+++ b/exporters/darcs/t/testimport-git-twoway.sh
@@ -0,0 +1,30 @@
+. lib.sh
+
+create_git test
+
+rm -rf test.darcs
+mkdir test.darcs
+cd test.darcs
+darcs init
+cd ..
+gmark="$(pwd)/test.gmarks"
+dmark="$(pwd)/test.dmarks"
+
+(cd test; git fast-export --export-marks=$gmark HEAD) | (cd test.darcs; darcs-fast-import --export-marks=$dmark)
+diff_importgit test || die "initial conversion differs"
+upd_file_git test file2 upd_contents
+(cd test; git fast-export --export-marks=$gmark --import-marks=$gmark HEAD) | (cd test.darcs; darcs-fast-import --export-marks=$dmark --import-marks=$dmark)
+diff_importgit test || die "git -> darcs update #1 differs"
+upd_file_darcs test.darcs file2 upd_contents2
+darcs-fast-export --export-marks=$dmark --import-marks=$dmark --working test/.git/darcs test.darcs | (cd test; git fast-import --export-marks=$gmark --import-marks=$gmark)
+(cd test; git checkout -f)
+diff_importgit test || die "darcs -> git update #2 differs"
+upd_file_git test file2 upd_contents3
+upd_file_git test file2 upd_contents32
+(cd test; git fast-export --export-marks=$gmark --import-marks=$gmark HEAD) | (cd test.darcs; darcs-fast-import --export-marks=$dmark --import-marks=$dmark)
+diff_importgit test || die "git -> darcs update #3 differs"
+upd_file_darcs test.darcs file2 upd_contents4
+upd_file_darcs test.darcs file2 upd_contents42
+darcs-fast-export --export-marks=$dmark --import-marks=$dmark --working test/.git/darcs test.darcs | (cd test; git fast-import --export-marks=$gmark --import-marks=$gmark)
+(cd test; git checkout -f)
+diff_importgit test || die "darcs -> git update #4 differs"
diff --git a/exporters/darcs/t/testimport-git-x2d.sh b/exporters/darcs/t/testimport-git-x2d.sh
new file mode 100644
index 0000000..22871c5
--- /dev/null
+++ b/exporters/darcs/t/testimport-git-x2d.sh
@@ -0,0 +1,15 @@
+. lib.sh
+
+create_git test
+
+rm -rf test.darcs
+x2d -f git test
+diff_importgit test || die "initial conversion differs"
+upd_file_git test file2 upd_contents
+x2d -f git test
+diff_importgit test || die "update differs"
+upd_file_git test hungarian.gif "binary to text"
+x2d -f git test
+diff_importgit test || die "update2 differs"
+x2d -f git test
+diff_importgit test || die "update3 (noop) differs"
diff --git a/exporters/darcs/t/testimport-git.sh b/exporters/darcs/t/testimport-git.sh
new file mode 100644
index 0000000..48a219c
--- /dev/null
+++ b/exporters/darcs/t/testimport-git.sh
@@ -0,0 +1,15 @@
+. lib.sh
+
+create_git test
+
+rm -rf test.darcs
+mkdir test.darcs
+cd test.darcs
+darcs init
+cd ..
+(cd test; git fast-export --progress=2 HEAD) | (cd test.darcs; darcs-fast-import)
+if [ $? != 0 ]; then
+ exit 1
+fi
+diff_importgit test
+exit $?
diff --git a/exporters/darcs/t/testimport-hg-x2d.sh b/exporters/darcs/t/testimport-hg-x2d.sh
new file mode 100644
index 0000000..f6869f5
--- /dev/null
+++ b/exporters/darcs/t/testimport-hg-x2d.sh
@@ -0,0 +1,15 @@
+. lib.sh
+
+create_hg test
+
+rm -rf test.darcs
+x2d -f hg test
+diff_importhg test || die "initial conversion differs"
+upd_file_hg test file2 upd_contents
+x2d -f hg test
+diff_importhg test || die "update differs"
+upd_file_hg test hungarian.gif "binary to text"
+x2d -f hg test
+diff_importhg test || die "update2 differs"
+x2d -f hg test
+diff_importhg test || die "update3 (noop) differs"
diff --git a/exporters/darcs/t/testimport-hg.sh b/exporters/darcs/t/testimport-hg.sh
new file mode 100644
index 0000000..0a60b8c
--- /dev/null
+++ b/exporters/darcs/t/testimport-hg.sh
@@ -0,0 +1,16 @@
+. lib.sh
+
+create_hg test
+
+rm -rf test.darcs
+mkdir test.darcs
+cd test.darcs
+darcs init
+cd ..
+(cd test; $pypath/bzrlib/plugins/fastimport/exporters/hg-fast-export.py -r .) | (cd test.darcs; darcs-fast-import)
+rm test/{*.orig,hg-export.status}
+if [ $? != 0 ]; then
+ exit 1
+fi
+diff_importhg test
+exit $?
diff --git a/exporters/darcs/t/testimport-rename.sh b/exporters/darcs/t/testimport-rename.sh
new file mode 100644
index 0000000..1008bf8
--- /dev/null
+++ b/exporters/darcs/t/testimport-rename.sh
@@ -0,0 +1,25 @@
+. lib.sh
+
+rm -rf test
+mkdir test
+cd test
+git init
+echo a > file
+git add file
+git commit -m a1
+git mv file file2
+git commit -m b
+cd ..
+
+rm -rf test.darcs
+mkdir test.darcs
+cd test.darcs
+darcs init
+cd ..
+(cd test; git fast-export -M HEAD) > out
+cat out | (cd test.darcs; darcs-fast-import)
+if [ $? != 0 ]; then
+ exit 1
+fi
+diff_importgit test
+exit $?
diff --git a/exporters/darcs/x2d b/exporters/darcs/x2d
new file mode 100755
index 0000000..0344e13
--- /dev/null
+++ b/exporters/darcs/x2d
@@ -0,0 +1,121 @@
+#!/bin/sh
+#
+# x2d - convert git, bzr or hg repos to darcs using fast-export
+#
+# Copyright (c) 2008 by Miklos Vajna <vmiklos@frugalware.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+# USA.
+#
+
+usage()
+{
+ echo "Usage: x2d -f format repo"
+}
+
+die()
+{
+ echo "$@"
+ usage
+ exit 1
+}
+
+check_up_to_date()
+{
+ upstreamnum=$(darcs show repo|grep 'Num Patches'|sed 's/.*: //')
+ if [ "$upstreamnum" = "$(cd $origin; eval $*)" ]; then
+ echo "No remote changes to pull!"
+ exit 0
+ fi
+}
+
+case $1 in
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -f)
+ format="$2"
+ shift 2
+ ;;
+esac
+
+[ -n "$format" ] || die "Source format is not given!"
+
+case $format in
+ git|bzr|hg)
+ ;;
+ *)
+ die "The requested source format is not yet supported!"
+ ;;
+esac
+
+origin="$1"
+shift 1
+
+[ -d "$origin" ] || die "Source repo does not exist!"
+
+# convert to abspath
+cd $origin
+origin=$(pwd)
+
+dmark="$origin.darcs/_darcs/fast-import/dfe-marks"
+fmark="$origin.darcs/_darcs/fast-import/ffi-marks"
+
+mkdir -p $origin.darcs
+cd $origin.darcs
+
+common_opts="--logfile $origin.darcs/_darcs/fast-import/log"
+pypath="/$(python -c 'from distutils import sysconfig; print sysconfig.get_python_lib()[1:]')/"
+
+if [ ! -f $dmark ]; then
+ darcs init
+ mkdir -p _darcs/fast-import
+ case $format in
+ git)
+ (cd $origin; git fast-export --export-marks=$fmark HEAD) | \
+ darcs-fast-import --export-marks=$dmark $common_opts
+ ;;
+ bzr)
+ (cd $origin; bzr fast-export \
+ --export-marks=$fmark . ) | darcs-fast-import --export-marks=$dmark $common_opts
+ ;;
+ hg)
+ (cd $origin; $pypath/bzrlib/plugins/fastimport/exporters/hg-fast-export.py -r . ) | \
+ darcs-fast-import --export-marks=$dmark $common_opts
+ esac
+else
+ case $format in
+ git)
+ check_up_to_date "git rev-list HEAD |wc -l"
+ (cd $origin; git fast-export --export-marks=$fmark --import-marks=$fmark HEAD) | \
+ darcs-fast-import --export-marks=$dmark --import-marks=$dmark $common_opts
+ ;;
+ bzr)
+ # bzr revno is not good here, because at merges
+ # it produces less revision than the number we
+ # have in darcs
+ check_up_to_date "bzr log|grep -c revno:"
+ (cd $origin; bzr fast-export \
+ --export-marks=$fmark --import-marks=$fmark . ) | \
+ darcs-fast-import --export-marks=$dmark --import-marks=$dmark $common_opts
+ ;;
+ hg)
+ check_up_to_date 'echo $(($(hg tip --template "{rev}")+1))'
+ (cd $origin; $pypath/bzrlib/plugins/fastimport/exporters/hg-fast-export.py -r . ) | \
+ darcs-fast-import --export-marks=$dmark --import-marks=$dmark $common_opts
+ ;;
+ esac
+fi
diff --git a/exporters/darcs/x2d.txt b/exporters/darcs/x2d.txt
new file mode 100644
index 0000000..eb2ec34
--- /dev/null
+++ b/exporters/darcs/x2d.txt
@@ -0,0 +1,26 @@
+= x2d(1)
+
+== NAME
+
+x2d - convert git, bzr or hg repos to a darcs one using fast-export
+
+== SYNOPSIS
+
+x2d -f <format> <otherrepo>
+
+== DESCRIPTION
+
+x2d is a wrapper script that just automates doing an initial or
+continuing an incremental conversion. All it does is initializing the
+target darcs repo, starting darcs-fast-import and the relevant exporter
+with the proper switches and pipe the importer's output to the
+importer's standard input.
+
+== OPTIONS
+
+--help::
+ Display usage.
+
+-f <format>::
+ Specify the format of the source repo. Currently supported sources are
+ git, bzr and hg. Incremental conversion is supported for all of them.