Mercurial > hg
changeset 11249:0bb67503ad4b stable
eol: extension for managing file EOLs
author | Martin Geisler <mg@lazybytes.net> |
---|---|
date | Mon, 31 May 2010 21:37:01 +0200 |
parents | 8f5ad12db28e |
children | ac6fec2af8c8 640d419725d0 8324a9fca62e |
files | hgext/eol.py tests/test-eol tests/test-eol-add tests/test-eol-add.out tests/test-eol-clone tests/test-eol-clone.out tests/test-eol-hook tests/test-eol-hook.out tests/test-eol-patch tests/test-eol-patch.out tests/test-eol-update tests/test-eol-update.out tests/test-eol.out |
diffstat | 13 files changed, 1547 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /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