--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/eol.py Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,256 @@
+"""automatically manage newlines in repository files
+
+This extension allows you to manage the type of line endings (CRLF or
+LF) that are used in the repository and in the local working
+directory. That way you can get CRLF line endings on Windows and LF on
+Unix/Mac, thereby letting everybody use their OS native line endings.
+
+The extension reads its configuration from a versioned ``.hgeol``
+configuration file every time you run an ``hg`` command. The
+``.hgeol`` file use the same syntax as all other Mercurial
+configuration files. It uses two sections, ``[patterns]`` and
+``[repository]``.
+
+The ``[patterns]`` section specifies the line endings used in the
+working directory. The format is specified by a file pattern. The
+first match is used, so put more specific patterns first. The
+available line endings are ``LF``, ``CRLF``, and ``BIN``.
+
+Files with the declared format of ``CRLF`` or ``LF`` are always
+checked out in that format and files declared to be binary (``BIN``)
+are left unchanged. Additionally, ``native`` is an alias for the
+platform's default line ending: ``LF`` on Unix (including Mac OS X)
+and ``CRLF`` on Windows. Note that ``BIN`` (do nothing to line
+endings) is Mercurial's default behaviour; it is only needed if you
+need to override a later, more general pattern.
+
+The optional ``[repository]`` section specifies the line endings to
+use for files stored in the repository. It has a single setting,
+``native``, which determines the storage line endings for files
+declared as ``native`` in the ``[patterns]`` section. It can be set to
+``LF`` or ``CRLF``. The default is ``LF``. For example, this means
+that on Windows, files configured as ``native`` (``CRLF`` by default)
+will be converted to ``LF`` when stored in the repository. Files
+declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
+are always stored as-is in the repository.
+
+Example versioned ``.hgeol`` file::
+
+ [patterns]
+ **.py = native
+ **.vcproj = CRLF
+ **.txt = native
+ Makefile = LF
+ **.jpg = BIN
+
+ [repository]
+ native = LF
+
+The extension uses an optional ``[eol]`` section in your hgrc file
+(not the ``.hgeol`` file) for settings that control the overall
+behavior. There are two settings:
+
+- ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
+ ``CRLF`` override the default interpretation of ``native`` for
+ checkout. This can be used with :hg:`archive` on Unix, say, to
+ generate an archive where files have line endings for Windows.
+
+- ``eol.only-consistent`` (default True) can be set to False to make
+ the extension convert files with inconsistent EOLs. Inconsistent
+ means that there is both ``CRLF`` and ``LF`` present in the file.
+ Such files are normally not touched under the assumption that they
+ have mixed EOLs on purpose.
+
+See :hg:`help patterns` for more information about the glob patterns
+used.
+"""
+
+from mercurial.i18n import _
+from mercurial import util, config, extensions, commands, match, cmdutil
+import re, os
+
+# Matches a lone LF, i.e., one that is not part of CRLF.
+singlelf = re.compile('(^|[^\r])\n')
+# Matches a single EOL which can either be a CRLF where repeated CR
+# are removed or a LF. We do not care about old Machintosh files, so a
+# stray CR is an error.
+eolre = re.compile('\r*\n')
+
+
+def inconsistenteol(data):
+ return '\r\n' in data and singlelf.search(data)
+
+def tolf(s, params, ui, **kwargs):
+ """Filter to convert to LF EOLs."""
+ if util.binary(s):
+ return s
+ if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
+ return s
+ return eolre.sub('\n', s)
+
+def tocrlf(s, params, ui, **kwargs):
+ """Filter to convert to CRLF EOLs."""
+ if util.binary(s):
+ return s
+ if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
+ return s
+ return eolre.sub('\r\n', s)
+
+def isbinary(s, params):
+ """Filter to do nothing with the file."""
+ return s
+
+filters = {
+ 'to-lf': tolf,
+ 'to-crlf': tocrlf,
+ 'is-binary': isbinary,
+}
+
+
+def hook(ui, repo, node, hooktype, **kwargs):
+ """verify that files have expected EOLs"""
+ files = set()
+ for rev in xrange(repo[node].rev(), len(repo)):
+ files.update(repo[rev].files())
+ tip = repo['tip']
+ for f in files:
+ if f not in tip:
+ continue
+ for pattern, target in ui.configitems('encode'):
+ if match.match(repo.root, '', [pattern])(f):
+ data = tip[f].data()
+ if target == "to-lf" and "\r\n" in data:
+ raise util.Abort(_("%s should not have CRLF line endings")
+ % f)
+ elif target == "to-crlf" and singlelf.search(data):
+ raise util.Abort(_("%s should not have LF line endings")
+ % f)
+
+
+def preupdate(ui, repo, hooktype, parent1, parent2):
+ #print "preupdate for %s: %s -> %s" % (repo.root, parent1, parent2)
+ repo.readhgeol(parent1)
+ return False
+
+def uisetup(ui):
+ ui.setconfig('hooks', 'preupdate.eol', preupdate)
+
+def extsetup(ui):
+ try:
+ extensions.find('win32text')
+ raise util.Abort(_("the eol extension is incompatible with the "
+ "win32text extension"))
+ except KeyError:
+ pass
+
+
+def reposetup(ui, repo):
+ #print "reposetup for", repo.root
+
+ if not repo.local():
+ return
+ for name, fn in filters.iteritems():
+ repo.adddatafilter(name, fn)
+
+ ui.setconfig('patch', 'eol', 'auto')
+
+ class eolrepo(repo.__class__):
+
+ _decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
+ _encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
+
+ def readhgeol(self, node=None, data=None):
+ if data is None:
+ try:
+ if node is None:
+ data = self.wfile('.hgeol').read()
+ else:
+ data = self[node]['.hgeol'].data()
+ except (IOError, LookupError):
+ return None
+
+ if self.ui.config('eol', 'native', os.linesep) in ('LF', '\n'):
+ self._decode['NATIVE'] = 'to-lf'
+ else:
+ self._decode['NATIVE'] = 'to-crlf'
+
+ eol = config.config()
+ eol.parse('.hgeol', data)
+
+ if eol.get('repository', 'native') == 'CRLF':
+ self._encode['NATIVE'] = 'to-crlf'
+ else:
+ self._encode['NATIVE'] = 'to-lf'
+
+ for pattern, style in eol.items('patterns'):
+ key = style.upper()
+ try:
+ self.ui.setconfig('decode', pattern, self._decode[key])
+ self.ui.setconfig('encode', pattern, self._encode[key])
+ except KeyError:
+ self.ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
+ % (style, eol.source('patterns', pattern)))
+
+ include = []
+ exclude = []
+ for pattern, style in eol.items('patterns'):
+ key = style.upper()
+ if key == 'BIN':
+ exclude.append(pattern)
+ else:
+ include.append(pattern)
+
+ # This will match the files for which we need to care
+ # about inconsistent newlines.
+ return match.match(self.root, '', [], include, exclude)
+
+ def _hgcleardirstate(self):
+ self._eolfile = self.readhgeol() or self.readhgeol('tip')
+
+ if not self._eolfile:
+ self._eolfile = util.never
+ return
+
+ try:
+ cachemtime = os.path.getmtime(self.join("eol.cache"))
+ except OSError:
+ cachemtime = 0
+
+ try:
+ eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
+ except OSError:
+ eolmtime = 0
+
+ if eolmtime > cachemtime:
+ ui.debug("eol: detected change in .hgeol\n")
+ # TODO: we could introduce a method for this in dirstate.
+ wlock = None
+ try:
+ wlock = self.wlock()
+ for f, e in self.dirstate._map.iteritems():
+ self.dirstate._map[f] = (e[0], e[1], -1, 0)
+ self.dirstate._dirty = True
+ # Touch the cache to update mtime. TODO: are we sure this
+ # always enought to update the mtime, or should we write a
+ # bit to the file?
+ self.opener("eol.cache", "w").close()
+ finally:
+ if wlock is not None:
+ wlock.release()
+
+ def commitctx(self, ctx, error=False):
+ for f in sorted(ctx.added() + ctx.modified()):
+ if not self._eolfile(f):
+ continue
+ data = ctx[f].data()
+ if util.binary(data):
+ # We should not abort here, since the user should
+ # be able to say "** = native" to automatically
+ # have all non-binary files taken care of.
+ continue
+ if inconsistenteol(data):
+ raise util.Abort(_("inconsistent newline style "
+ "in %s\n" % f))
+ return super(eolrepo, self).commitctx(ctx, error)
+ repo.__class__ = eolrepo
+ repo._hgcleardirstate()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,180 @@
+#!/bin/sh
+
+cat > $HGRCPATH <<EOF
+[diff]
+git = True
+EOF
+
+cat > switch-eol.py <<EOF
+import sys
+
+try:
+ import os, msvcrt
+ msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+except ImportError:
+ pass
+
+(old, new) = sys.argv[1] == 'LF' and ('\n', '\r\n') or ('\r\n', '\n')
+print "%% switching encoding from %r to %r" % (old, new)
+for path in sys.argv[2:]:
+ data = file(path, 'rb').read()
+ data = data.replace(old, new)
+ file(path, 'wb').write(data)
+EOF
+
+seteol () {
+ if [ $1 = "LF" ]; then
+ EOL='\n'
+ else
+ EOL='\r\n'
+ fi
+}
+
+makerepo () {
+ seteol $1
+ echo "% setup $1 repository"
+ hg init repo
+ cd repo
+
+ cat > .hgeol <<EOF
+[repository]
+native = $1
+
+[patterns]
+mixed.txt = BIN
+**.txt = native
+EOF
+
+ printf "first${EOL}second${EOL}third${EOL}" > a.txt
+ hg commit --addremove -m 'checkin'
+ echo
+ cd ..
+}
+
+dotest () {
+ seteol $1
+ echo "% hg clone repo repo-$1"
+ hg clone --noupdate repo repo-$1
+ cd repo-$1
+
+ cat > .hg/hgrc <<EOF
+[extensions]
+eol =
+
+[eol]
+native = $1
+EOF
+
+ hg update
+ echo '% printrepr.py a.txt'
+ python $TESTDIR/printrepr.py < a.txt
+ echo '% hg cat a.txt'
+ hg cat a.txt | python $TESTDIR/printrepr.py
+
+ printf "fourth${EOL}" >> a.txt
+ echo '% printrepr.py a.txt'
+ python $TESTDIR/printrepr.py < a.txt
+ hg diff | python $TESTDIR/printrepr.py
+
+ python ../switch-eol.py $1 a.txt
+ echo '% hg diff only reports a single changed line:'
+ hg diff | python $TESTDIR/printrepr.py
+
+ echo "% reverting back to $1 format"
+ hg revert a.txt
+ python $TESTDIR/printrepr.py < a.txt
+
+ printf "first\r\nsecond\n" > mixed.txt
+ hg add mixed.txt
+ echo "% hg commit of inconsistent .txt file marked as binary (should work)"
+ hg commit -m 'binary file'
+
+ echo "% hg commit of inconsistent .txt file marked as native (should fail)"
+ printf "first\nsecond\r\nthird\nfourth\r\n" > a.txt
+ hg commit -m 'inconsistent file'
+
+ echo "% hg commit --config eol.only-consistent=False (should work)"
+ hg commit --config eol.only-consistent=False -m 'inconsistent file'
+
+ echo "% hg commit of binary .txt file marked as native (binary files always okay)"
+ printf "first${EOL}\0${EOL}third${EOL}" > a.txt
+ hg commit -m 'binary file'
+
+ cd ..
+ rm -r repo-$1
+}
+
+makerepo LF
+dotest LF
+dotest CRLF
+rm -r repo
+
+makerepo CRLF
+dotest LF
+dotest CRLF
+rm -r repo
+
+
+makemixedrepo () {
+ echo
+ echo "# setup $1 repository"
+ hg init mixed
+ cd mixed
+ printf "foo\r\nbar\r\nbaz\r\n" > win.txt
+ printf "foo\nbar\nbaz\n" > unix.txt
+ #printf "foo\r\nbar\nbaz\r\n" > mixed.txt
+
+ hg commit --addremove -m 'created mixed files'
+
+ echo "# setting repository-native EOLs to $1"
+ cat > .hgeol <<EOF
+[repository]
+native = $1
+
+[patterns]
+**.txt = native
+EOF
+ hg commit --addremove -m 'added .hgeol'
+ cd ..
+}
+
+testmixed () {
+ echo
+ echo "% hg clone mixed mixed-$1"
+ hg clone mixed mixed-$1
+ cd mixed-$1
+
+ echo '% hg status (eol extension not yet activated)'
+ hg status
+
+ cat > .hg/hgrc <<EOF
+[extensions]
+eol =
+
+[eol]
+native = $1
+EOF
+
+ echo '% hg status (eol activated)'
+ hg status
+ echo '% hg commit'
+ hg commit -m 'synchronized EOLs'
+
+ echo '% hg status'
+ hg status
+
+ cd ..
+ rm -r mixed-$1
+}
+
+makemixedrepo LF
+testmixed LF
+testmixed CRLF
+rm -r mixed
+
+makemixedrepo CRLF
+testmixed LF
+testmixed CRLF
+rm -r mixed
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-add Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+cat > $HGRCPATH <<EOF
+[diff]
+git = 1
+EOF
+
+seteol () {
+ if [ $1 = "LF" ]; then
+ EOL='\n'
+ else
+ EOL='\r\n'
+ fi
+}
+
+makerepo () {
+ echo
+ echo "# ==== setup repository ===="
+ echo '% hg init'
+ hg init repo
+ cd repo
+
+ printf "first\nsecond\nthird\n" > a.txt
+ hg commit -d '100 0' --addremove -m 'LF commit'
+ cd ..
+}
+
+dotest () {
+ seteol $1
+
+ echo
+ echo "% hg clone repo repo-$1"
+ hg clone repo repo-$1
+ cd repo-$1
+
+ cat > .hg/hgrc <<EOF
+[extensions]
+eol =
+
+[eol]
+native = LF
+EOF
+
+ cat > .hgeol <<EOF
+[patterns]
+**.txt = native
+
+[repository]
+native = $1
+EOF
+
+ echo '% hg add .hgeol'
+ hg add .hgeol
+ echo '% hg status'
+ hg status
+
+ echo '% hg commit'
+ hg commit -d '200 0' -m 'Added .hgeol file'
+
+ echo '% hg status'
+ hg status
+
+ echo '% hg tip -p'
+ hg tip -p | python $TESTDIR/printrepr.py
+
+ cd ..
+ rm -r repo-$1
+}
+
+makerepo
+dotest LF
+dotest CRLF
+rm -r repo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-add.out Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,69 @@
+
+# ==== setup repository ====
+% hg init
+adding a.txt
+
+% hg clone repo repo-LF
+updating to branch default
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% hg add .hgeol
+% hg status
+A .hgeol
+% hg commit
+% hg status
+% hg tip -p
+changeset: 1:34614fc6dc02
+tag: tip
+user: test
+date: Thu Jan 01 00:03:20 1970 +0000
+summary: Added .hgeol file
+
+diff --git a/.hgeol b/.hgeol
+new file mode 100644
+--- /dev/null
++++ b/.hgeol
+@@ -0,0 +1,5 @@
++[patterns]
++**.txt = native
++
++[repository]
++native = LF
+
+
+% hg clone repo repo-CRLF
+updating to branch default
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% hg add .hgeol
+% hg status
+M a.txt
+A .hgeol
+% hg commit
+% hg status
+% hg tip -p
+changeset: 1:4bbdacd3fe39
+tag: tip
+user: test
+date: Thu Jan 01 00:03:20 1970 +0000
+summary: Added .hgeol file
+
+diff --git a/.hgeol b/.hgeol
+new file mode 100644
+--- /dev/null
++++ b/.hgeol
+@@ -0,0 +1,5 @@
++[patterns]
++**.txt = native
++
++[repository]
++native = CRLF
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,3 @@
+-first
+-second
+-third
++first\r
++second\r
++third\r
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-clone Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+cat > $HGRCPATH <<EOF
+[diff]
+git = True
+
+[extensions]
+eol =
+
+[eol]
+native = CRLF
+EOF
+
+echo "% setup repository"
+hg init repo
+cd repo
+
+cat > .hgeol <<EOF
+[patterns]
+**.txt = native
+EOF
+
+printf "first\r\nsecond\r\nthird\r\n" > a.txt
+hg commit --addremove -m 'checkin'
+cd ..
+
+echo "% hg clone repo repo-2"
+hg clone repo repo-2
+cd repo-2
+
+echo '% printrepr.py a.txt'
+python $TESTDIR/printrepr.py < a.txt
+echo '% hg cat a.txt'
+hg cat a.txt | python $TESTDIR/printrepr.py
+
+hg remove .hgeol
+hg commit -m 'remove eol'
+hg push --quiet
+
+cd ..
+
+# Test clone of repo with .hgeol in working dir, but no .hgeol in tip
+echo "% hg clone repo repo-3"
+hg clone repo repo-3
+cd repo-3
+
+echo '% printrepr.py a.txt'
+python $TESTDIR/printrepr.py < a.txt
+
+cd ..
+
+# Test clone of revision with .hgeol
+echo "% hg clone -r 1 repo repo-4"
+hg clone -r 0 repo repo-4
+cd repo-4
+
+echo '% cat .hgeol'
+cat .hgeol
+
+echo '% printrepr.py a.txt'
+python $TESTDIR/printrepr.py < a.txt
+
+cd ..
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-clone.out Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,36 @@
+% setup repository
+adding .hgeol
+adding a.txt
+% hg clone repo repo-2
+updating to branch default
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt
+first\r
+second\r
+third\r
+% hg cat a.txt
+first
+second
+third
+% hg clone repo repo-3
+updating to branch default
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt
+first
+second
+third
+% hg clone -r 1 repo repo-4
+requesting all changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 2 changes to 2 files
+updating to branch default
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% cat .hgeol
+[patterns]
+**.txt = native
+% printrepr.py a.txt
+first\r
+second\r
+third\r
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-hook Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+cat > $HGRCPATH <<EOF
+[diff]
+git = True
+EOF
+
+hg init main
+cat > main/.hg/hgrc <<EOF
+[extensions]
+eol =
+
+[hooks]
+pretxnchangegroup = python:hgext.eol.hook
+EOF
+
+hg clone main fork
+
+cd fork
+cat > .hgeol <<EOF
+[patterns]
+mixed.txt = BIN
+**.txt = native
+EOF
+
+hg add .hgeol
+hg commit -m 'Commit .hgeol'
+
+printf "first\nsecond\nthird\n" > a.txt
+hg add a.txt
+echo "% hg commit (LF a.txt)"
+hg commit -m 'LF a.txt'
+echo "% hg push"
+hg push ../main
+
+printf "first\r\nsecond\r\nthird\n" > a.txt
+echo "% hg commit (CRLF a.txt)"
+hg commit -m 'CRLF a.txt'
+echo "% hg push"
+hg push ../main
+
+
+echo "% hg commit (LF a.txt)"
+printf "first\nsecond\nthird\n" > a.txt
+hg commit -m 'LF a.txt (fixed)'
+echo "% hg push"
+hg push ../main
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-hook.out Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,30 @@
+updating to branch default
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% hg commit (LF a.txt)
+% hg push
+pushing to ../main
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 2 files
+% hg commit (CRLF a.txt)
+% hg push
+pushing to ../main
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
+error: pretxnchangegroup hook failed: a.txt should not have CRLF line endings
+transaction abort!
+rollback completed
+abort: a.txt should not have CRLF line endings
+% hg commit (LF a.txt)
+% hg push
+pushing to ../main
+searching for changes
+adding changesets
+adding manifests
+adding file changes
+added 2 changesets with 2 changes to 1 files
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-patch Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+cat > $HGRCPATH <<EOF
+[diff]
+git = 1
+EOF
+
+seteol () {
+ if [ $1 = "LF" ]; then
+ EOL='\n'
+ else
+ EOL='\r\n'
+ fi
+}
+
+makerepo () {
+ seteol $1
+ echo
+ echo "# ==== setup $1 repository ===="
+ echo '% hg init'
+ hg init repo
+ cd repo
+
+ cat > .hgeol <<EOF
+[repository]
+native = $1
+
+[patterns]
+unix.txt = LF
+win.txt = CRLF
+**.txt = native
+EOF
+
+ printf "first\r\nsecond\r\nthird\r\n" > win.txt
+ printf "first\nsecond\nthird\n" > unix.txt
+ printf "first${EOL}second${EOL}third${EOL}" > native.txt
+ hg commit --addremove -m 'checkin'
+ cd ..
+}
+
+dotest () {
+ seteol $1
+
+ echo
+ echo "% hg clone repo repo-$1"
+ hg clone --noupdate repo repo-$1
+ cd repo-$1
+
+ cat > .hg/hgrc <<EOF
+[extensions]
+eol =
+
+[eol]
+native = $1
+EOF
+
+ hg update
+ echo '% printrepr.py native.txt'
+ python $TESTDIR/printrepr.py < native.txt
+
+ echo '% printrepr.py unix.txt'
+ python $TESTDIR/printrepr.py < unix.txt
+
+ echo '% printrepr.py win.txt'
+ python $TESTDIR/printrepr.py < win.txt
+
+ printf "first${EOL}third${EOL}" > native.txt
+ printf "first\r\nthird\r\n" > win.txt
+ printf "first\nthird\n" > unix.txt
+
+ echo '% hg diff'
+ hg diff > p
+ python $TESTDIR/printrepr.py < p
+
+ echo '% hg revert'
+ hg revert --all
+
+ echo '% hg import'
+ hg import -m 'patch' p
+
+ echo '% printrepr.py native.txt'
+ python $TESTDIR/printrepr.py < native.txt
+ echo '% printrepr.py unix.txt'
+ python $TESTDIR/printrepr.py < unix.txt
+ echo '% printrepr.py win.txt'
+ python $TESTDIR/printrepr.py < win.txt
+
+ echo '% hg diff -c tip'
+ hg diff -c tip | python $TESTDIR/printrepr.py
+
+ cd ..
+ rm -r repo-$1
+}
+
+makerepo LF
+dotest LF
+dotest CRLF
+rm -r repo
+
+makerepo CRLF
+dotest LF
+dotest CRLF
+rm -r repo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-patch.out Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,310 @@
+
+# ==== setup LF repository ====
+% hg init
+adding .hgeol
+adding native.txt
+adding unix.txt
+adding win.txt
+
+% hg clone repo repo-LF
+4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py native.txt
+first
+second
+third
+% printrepr.py unix.txt
+first
+second
+third
+% printrepr.py win.txt
+first\r
+second\r
+third\r
+% hg diff
+diff --git a/native.txt b/native.txt
+--- a/native.txt
++++ b/native.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/unix.txt b/unix.txt
+--- a/unix.txt
++++ b/unix.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/win.txt b/win.txt
+--- a/win.txt
++++ b/win.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+% hg revert
+reverting native.txt
+reverting unix.txt
+reverting win.txt
+% hg import
+applying p
+% printrepr.py native.txt
+first
+third
+% printrepr.py unix.txt
+first
+third
+% printrepr.py win.txt
+first\r
+third\r
+% hg diff -c tip
+diff --git a/native.txt b/native.txt
+--- a/native.txt
++++ b/native.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/unix.txt b/unix.txt
+--- a/unix.txt
++++ b/unix.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/win.txt b/win.txt
+--- a/win.txt
++++ b/win.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+
+% hg clone repo repo-CRLF
+4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py native.txt
+first\r
+second\r
+third\r
+% printrepr.py unix.txt
+first
+second
+third
+% printrepr.py win.txt
+first\r
+second\r
+third\r
+% hg diff
+diff --git a/native.txt b/native.txt
+--- a/native.txt
++++ b/native.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/unix.txt b/unix.txt
+--- a/unix.txt
++++ b/unix.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/win.txt b/win.txt
+--- a/win.txt
++++ b/win.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+% hg revert
+reverting native.txt
+reverting unix.txt
+reverting win.txt
+% hg import
+applying p
+% printrepr.py native.txt
+first\r
+third\r
+% printrepr.py unix.txt
+first
+third
+% printrepr.py win.txt
+first\r
+third\r
+% hg diff -c tip
+diff --git a/native.txt b/native.txt
+--- a/native.txt
++++ b/native.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/unix.txt b/unix.txt
+--- a/unix.txt
++++ b/unix.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/win.txt b/win.txt
+--- a/win.txt
++++ b/win.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+
+# ==== setup CRLF repository ====
+% hg init
+adding .hgeol
+adding native.txt
+adding unix.txt
+adding win.txt
+
+% hg clone repo repo-LF
+4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py native.txt
+first
+second
+third
+% printrepr.py unix.txt
+first
+second
+third
+% printrepr.py win.txt
+first\r
+second\r
+third\r
+% hg diff
+diff --git a/native.txt b/native.txt
+--- a/native.txt
++++ b/native.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+diff --git a/unix.txt b/unix.txt
+--- a/unix.txt
++++ b/unix.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/win.txt b/win.txt
+--- a/win.txt
++++ b/win.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+% hg revert
+reverting native.txt
+reverting unix.txt
+reverting win.txt
+% hg import
+applying p
+% printrepr.py native.txt
+first
+third
+% printrepr.py unix.txt
+first
+third
+% printrepr.py win.txt
+first\r
+third\r
+% hg diff -c tip
+diff --git a/native.txt b/native.txt
+--- a/native.txt
++++ b/native.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+diff --git a/unix.txt b/unix.txt
+--- a/unix.txt
++++ b/unix.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/win.txt b/win.txt
+--- a/win.txt
++++ b/win.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+
+% hg clone repo repo-CRLF
+4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py native.txt
+first\r
+second\r
+third\r
+% printrepr.py unix.txt
+first
+second
+third
+% printrepr.py win.txt
+first\r
+second\r
+third\r
+% hg diff
+diff --git a/native.txt b/native.txt
+--- a/native.txt
++++ b/native.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+diff --git a/unix.txt b/unix.txt
+--- a/unix.txt
++++ b/unix.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/win.txt b/win.txt
+--- a/win.txt
++++ b/win.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+% hg revert
+reverting native.txt
+reverting unix.txt
+reverting win.txt
+% hg import
+applying p
+% printrepr.py native.txt
+first\r
+third\r
+% printrepr.py unix.txt
+first
+third
+% printrepr.py win.txt
+first\r
+third\r
+% hg diff -c tip
+diff --git a/native.txt b/native.txt
+--- a/native.txt
++++ b/native.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+diff --git a/unix.txt b/unix.txt
+--- a/unix.txt
++++ b/unix.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+diff --git a/win.txt b/win.txt
+--- a/win.txt
++++ b/win.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-update Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+cat > $HGRCPATH <<EOF
+[diff]
+git = 1
+EOF
+
+seteol () {
+ if [ $1 = "LF" ]; then
+ EOL='\n'
+ else
+ EOL='\r\n'
+ fi
+}
+
+makerepo () {
+ echo
+ echo "# ==== setup repository ===="
+ echo '% hg init'
+ hg init repo
+ cd repo
+
+ cat > .hgeol <<EOF
+[patterns]
+**.txt = LF
+EOF
+
+ printf "first\nsecond\nthird\n" > a.txt
+ hg commit --addremove -m 'LF commit'
+
+ cat > .hgeol <<EOF
+[patterns]
+**.txt = CRLF
+EOF
+
+ printf "first\r\nsecond\r\nthird\r\n" > a.txt
+ hg commit -m 'CRLF commit'
+
+ cd ..
+}
+
+dotest () {
+ seteol $1
+
+ echo
+ echo "% hg clone repo repo-$1"
+ hg clone --noupdate repo repo-$1
+ cd repo-$1
+
+ cat > .hg/hgrc <<EOF
+[extensions]
+eol =
+EOF
+
+ hg update
+
+ echo '% printrepr.py a.txt (before)'
+ python $TESTDIR/printrepr.py < a.txt
+
+ printf "first${EOL}third${EOL}" > a.txt
+
+ echo '% printrepr.py a.txt (after)'
+ python $TESTDIR/printrepr.py < a.txt
+ echo '% hg diff'
+ hg diff | python $TESTDIR/printrepr.py
+
+ echo '% hg update 0'
+ hg update 0
+
+ echo '% printrepr.py a.txt'
+ python $TESTDIR/printrepr.py < a.txt
+ echo '% hg diff'
+ hg diff | python $TESTDIR/printrepr.py
+
+
+ cd ..
+ rm -r repo-$1
+}
+
+makerepo
+dotest LF
+dotest CRLF
+rm -r repo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol-update.out Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,69 @@
+
+# ==== setup repository ====
+% hg init
+adding .hgeol
+adding a.txt
+
+% hg clone repo repo-LF
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt (before)
+first\r
+second\r
+third\r
+% printrepr.py a.txt (after)
+first
+third
+% hg diff
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+% hg update 0
+merging a.txt
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt
+first\r
+third\r
+% hg diff
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
+
+% hg clone repo repo-CRLF
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt (before)
+first\r
+second\r
+third\r
+% printrepr.py a.txt (after)
+first\r
+third\r
+% hg diff
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,2 @@
+ first\r
+-second\r
+ third\r
+% hg update 0
+merging a.txt
+1 files updated, 1 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt
+first\r
+third\r
+% hg diff
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,2 @@
+ first
+-second
+ third
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-eol.out Mon May 31 21:37:01 2010 +0200
@@ -0,0 +1,228 @@
+% setup LF repository
+adding .hgeol
+adding a.txt
+
+% hg clone repo repo-LF
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt
+first
+second
+third
+% hg cat a.txt
+first
+second
+third
+% printrepr.py a.txt
+first
+second
+third
+fourth
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,4 @@
+ first
+ second
+ third
++fourth
+% switching encoding from '\n' to '\r\n'
+% hg diff only reports a single changed line:
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,4 @@
+ first
+ second
+ third
++fourth
+% reverting back to LF format
+first
+second
+third
+% hg commit of inconsistent .txt file marked as binary (should work)
+% hg commit of inconsistent .txt file marked as native (should fail)
+abort: inconsistent newline style in a.txt
+
+% hg commit --config eol.only-consistent=False (should work)
+% hg commit of binary .txt file marked as native (binary files always okay)
+% hg clone repo repo-CRLF
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt
+first\r
+second\r
+third\r
+% hg cat a.txt
+first
+second
+third
+% printrepr.py a.txt
+first\r
+second\r
+third\r
+fourth\r
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,4 @@
+ first
+ second
+ third
++fourth
+% switching encoding from '\r\n' to '\n'
+% hg diff only reports a single changed line:
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,4 @@
+ first
+ second
+ third
++fourth
+% reverting back to CRLF format
+first\r
+second\r
+third\r
+% hg commit of inconsistent .txt file marked as binary (should work)
+% hg commit of inconsistent .txt file marked as native (should fail)
+abort: inconsistent newline style in a.txt
+
+% hg commit --config eol.only-consistent=False (should work)
+% hg commit of binary .txt file marked as native (binary files always okay)
+% setup CRLF repository
+adding .hgeol
+adding a.txt
+
+% hg clone repo repo-LF
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt
+first
+second
+third
+% hg cat a.txt
+first\r
+second\r
+third\r
+% printrepr.py a.txt
+first
+second
+third
+fourth
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,4 @@
+ first\r
+ second\r
+ third\r
++fourth\r
+% switching encoding from '\n' to '\r\n'
+% hg diff only reports a single changed line:
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,4 @@
+ first\r
+ second\r
+ third\r
++fourth\r
+% reverting back to LF format
+first
+second
+third
+% hg commit of inconsistent .txt file marked as binary (should work)
+% hg commit of inconsistent .txt file marked as native (should fail)
+abort: inconsistent newline style in a.txt
+
+% hg commit --config eol.only-consistent=False (should work)
+% hg commit of binary .txt file marked as native (binary files always okay)
+% hg clone repo repo-CRLF
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% printrepr.py a.txt
+first\r
+second\r
+third\r
+% hg cat a.txt
+first\r
+second\r
+third\r
+% printrepr.py a.txt
+first\r
+second\r
+third\r
+fourth\r
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,4 @@
+ first\r
+ second\r
+ third\r
++fourth\r
+% switching encoding from '\r\n' to '\n'
+% hg diff only reports a single changed line:
+diff --git a/a.txt b/a.txt
+--- a/a.txt
++++ b/a.txt
+@@ -1,3 +1,4 @@
+ first\r
+ second\r
+ third\r
++fourth\r
+% reverting back to CRLF format
+first\r
+second\r
+third\r
+% hg commit of inconsistent .txt file marked as binary (should work)
+% hg commit of inconsistent .txt file marked as native (should fail)
+abort: inconsistent newline style in a.txt
+
+% hg commit --config eol.only-consistent=False (should work)
+% hg commit of binary .txt file marked as native (binary files always okay)
+
+# setup LF repository
+adding unix.txt
+adding win.txt
+# setting repository-native EOLs to LF
+adding .hgeol
+
+% hg clone mixed mixed-LF
+updating to branch default
+3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% hg status (eol extension not yet activated)
+% hg status (eol activated)
+M win.txt
+% hg commit
+% hg status
+
+% hg clone mixed mixed-CRLF
+updating to branch default
+3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% hg status (eol extension not yet activated)
+% hg status (eol activated)
+M win.txt
+% hg commit
+% hg status
+
+# setup CRLF repository
+adding unix.txt
+adding win.txt
+# setting repository-native EOLs to CRLF
+adding .hgeol
+
+% hg clone mixed mixed-LF
+updating to branch default
+3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% hg status (eol extension not yet activated)
+% hg status (eol activated)
+M unix.txt
+% hg commit
+% hg status
+
+% hg clone mixed mixed-CRLF
+updating to branch default
+3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+% hg status (eol extension not yet activated)
+% hg status (eol activated)
+M unix.txt
+% hg commit
+% hg status