[PATCH] add standard hook to reject text files with CRLF

Jesse Glick jesse.glick at sun.com
Wed Dec 19 12:55:27 CST 2007


> # HG changeset patch
> # User Jesse Glick <jesse.glick at sun.com>
> # Date 1198089898 18000
> # Node ID ff5aadbd4939f419554d6d43eb8e821735a21184
> # Parent  9d6ad26fab10e06768858ed1a74eff80207cb0f5
> Issue 882: add standard hook to reject text files with CRLF.
> While the win32text extension does LF <-> CRLF conversion, and will issue a
> warning in case a file already in the repository uses CRLF, it provides no
> mechanism for verifying that incoming changes use LF. In a large development
> team with some Windows users, it is virtually guaranteed that someone will
> forget to set up the encode filter correctly and accidentally check in a file
> using CRLF, which can cause warnings for other Windows users when they next
> fetch changes. Since this is a general problem it is desirable to have a
> pre-commit (or -push) hook available to reject such accidents earlier rather
> than trying to fix them up after the fact.
> 
> diff --git a/hgext/win32text.py b/hgext/win32text.py
> --- a/hgext/win32text.py
> +++ b/hgext/win32text.py
> @@ -1,5 +1,6 @@ from mercurial import util, ui
>  from mercurial import util, ui
>  from mercurial.i18n import gettext as _
> +from mercurial.node import *
>  import re
>  
>  # regexp for single LF without CR preceding.
> @@ -43,3 +44,40 @@ util.filtertable.update({
>      'cleverdecode:': cleverdecode,
>      'cleverencode:': cleverencode,
>      })
> +
> +def forbidcrlf(ui, repo, hooktype, node, **kwargs):
> +    '''Prevent text files containing CRLF from being committed or pushed.
> +
> +    Usage:
> +    [hooks]
> +    pretxncommit.crlf = python:hgext.win32text.forbidcrlf
> +    pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf'''
> +    halt = False
> +    for rev in xrange(repo.changelog.rev(bin(node)), repo.changelog.count()):
> +        c = repo.changectx(rev)
> +        for f in c.files():
> +            if f not in c:
> +                continue
> +            data = c[f].data()
> +            if '\0' not in data and '\r\n' in data:
> +                if not halt:
> +                    ui.warn(_('Attempt to commit or push text file(s) '
> +                              'using CRLF line endings\n'))
> +                ui.warn(_('in %s: %s\n') % (short(c.node()), f))
> +                halt = True
> +    if halt and hooktype == 'pretxnchangegroup':
> +        ui.warn(_('\nTo prevent this mistake in your local repository,\n'
> +                  'add to Mercurial.ini or .hg/hgrc:\n'
> +                  '\n'
> +                  '[hooks]\n'
> +                  'pretxncommit.crlf = python:hgext.win32text.forbidcrlf\n'
> +                  '\n'
> +                  'and also consider adding:\n'
> +                  '\n'
> +                  '[extensions]\n'
> +                  'hgext.win32text =\n'
> +                  '[encode]\n'
> +                  '** = cleverencode:\n'
> +                  '[decode]\n'
> +                  '** = cleverdecode:\n'))
> +    return halt
> diff --git a/tests/test-win32text b/tests/test-win32text
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-win32text
> @@ -0,0 +1,56 @@
> +#!/bin/sh
> +
> +hg init
> +echo '[hooks]' >> .hg/hgrc
> +echo 'pretxncommit.crlf = python:hgext.win32text.forbidcrlf' >> .hg/hgrc
> +echo 'pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf' >> .hg/hgrc
> +cat .hg/hgrc
> +echo
> +
> +echo hello > f
> +hg add f
> +hg ci -m 1 -d'0 0'
> +echo
> +
> +unix2dos f
> +hg ci -m 2 -d'0 0'
> +hg revert -a
> +echo
> +
> +mkdir d
> +echo hello > d/f2
> +unix2dos d/f2
> +hg add d/f2
> +hg ci -m 3 -d'0 0'
> +hg revert -a
> +rm d/f2
> +echo
> +
> +hg rem f
> +hg ci -m 4 -d'0 0'
> +echo
> +
> +printf 'hello\x00\x0D\x0A' > bin
> +hg add bin
> +hg ci -m 5 -d'0 0'
> +hg log -v
> +echo
> +
> +hg clone . dupe
> +echo
> +for x in a b c d; do echo content > dupe/$x; done
> +hg -R dupe add
> +unix2dos dupe/b dupe/c dupe/d
> +hg -R dupe ci -m a -d'0 0' dupe/a
> +hg -R dupe ci -m b/c -d'0 0' dupe/[bc]
> +hg -R dupe ci -m d -d'0 0' dupe/d
> +hg -R dupe log -v
> +echo
> +
> +hg pull dupe
> +echo
> +
> +hg log -v
> +echo
> +
> +# XXX missing tests for encode/decode hooks
> diff --git a/tests/test-win32text.out b/tests/test-win32text.out
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-win32text.out
> @@ -0,0 +1,157 @@
> +[hooks]
> +pretxncommit.crlf = python:hgext.win32text.forbidcrlf
> +pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
> +
> +
> +Attempt to commit or push text file(s) using CRLF line endings
> +in b1aa5cde7ff4: f
> +transaction abort!
> +rollback completed
> +abort: pretxncommit.crlf hook failed
> +reverting f
> +
> +Attempt to commit or push text file(s) using CRLF line endings
> +in 88b17af74937: d/f2
> +transaction abort!
> +rollback completed
> +abort: pretxncommit.crlf hook failed
> +forgetting d/f2
> +
> +
> +changeset:   2:a55cab36df04
> +tag:         tip
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       bin
> +description:
> +5
> +
> +
> +changeset:   1:c72a7d1d0907
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       f
> +description:
> +4
> +
> +
> +changeset:   0:fcf06d5c4e1d
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       f
> +description:
> +1
> +
> +
> +
> +1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +
> +adding dupe/a
> +adding dupe/b
> +adding dupe/c
> +adding dupe/d
> +changeset:   5:81c49ee61396
> +tag:         tip
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       d
> +description:
> +d
> +
> +
> +changeset:   4:02184785bcac
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       b c
> +description:
> +b/c
> +
> +
> +changeset:   3:36e70ffe2c3d
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       a
> +description:
> +a
> +
> +
> +changeset:   2:a55cab36df04
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       bin
> +description:
> +5
> +
> +
> +changeset:   1:c72a7d1d0907
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       f
> +description:
> +4
> +
> +
> +changeset:   0:fcf06d5c4e1d
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       f
> +description:
> +1
> +
> +
> +
> +pulling from dupe
> +searching for changes
> +adding changesets
> +adding manifests
> +adding file changes
> +added 3 changesets with 4 changes to 4 files
> +Attempt to commit or push text file(s) using CRLF line endings
> +in 02184785bcac: b
> +in 02184785bcac: c
> +in 81c49ee61396: d
> +
> +To prevent this mistake in your local repository,
> +add to Mercurial.ini or .hg/hgrc:
> +
> +[hooks]
> +pretxncommit.crlf = python:hgext.win32text.forbidcrlf
> +
> +and also consider adding:
> +
> +[extensions]
> +hgext.win32text =
> +[encode]
> +** = cleverencode:
> +[decode]
> +** = cleverdecode:
> +transaction abort!
> +rollback completed
> +abort: pretxnchangegroup.crlf hook failed
> +
> +changeset:   2:a55cab36df04
> +tag:         tip
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       bin
> +description:
> +5
> +
> +
> +changeset:   1:c72a7d1d0907
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       f
> +description:
> +4
> +
> +
> +changeset:   0:fcf06d5c4e1d
> +user:        test
> +date:        Thu Jan 01 00:00:00 1970 +0000
> +files:       f
> +description:
> +1
> +
> +
> +



More information about the Mercurial-devel mailing list