win32text.py
158 lines
| 5.0 KiB
| text/x-python
|
PythonLexer
/ hgext / win32text.py
OHASHI Hideya
|
r6481 | # win32text.py - LF <-> CRLF/CR translation utilities for Windows/Mac users | ||
Jesse Glick
|
r5675 | # | ||
Martin Geisler
|
r8253 | # Copyright 2005, 2007-2009 Matt Mackall <mpm@selenic.com> and others | ||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2, incorporated herein by reference. | ||||
Dirkjan Ochtman
|
r8873 | |||
Cédric Duval
|
r8894 | '''perform automatic newline conversion | ||
Dirkjan Ochtman
|
r8873 | |||
Martin Geisler
|
r9217 | To perform automatic newline conversion, use:: | ||
Dirkjan Ochtman
|
r8873 | |||
Martin Geisler
|
r9217 | [extensions] | ||
Martin Geisler
|
r10112 | win32text = | ||
Martin Geisler
|
r9217 | [encode] | ||
** = cleverencode: | ||||
# or ** = macencode: | ||||
Dirkjan Ochtman
|
r8873 | |||
Martin Geisler
|
r9217 | [decode] | ||
** = cleverdecode: | ||||
# or ** = macdecode: | ||||
Dirkjan Ochtman
|
r8873 | |||
Martin Geisler
|
r9217 | If not doing conversion, to make sure you do not commit CRLF/CR by accident:: | ||
Dirkjan Ochtman
|
r8873 | |||
Martin Geisler
|
r9217 | [hooks] | ||
pretxncommit.crlf = python:hgext.win32text.forbidcrlf | ||||
# or pretxncommit.cr = python:hgext.win32text.forbidcr | ||||
Dirkjan Ochtman
|
r8873 | |||
To do the same check on a server to prevent CRLF/CR from being | ||||
Martin Geisler
|
r9217 | pushed or pulled:: | ||
Dirkjan Ochtman
|
r8873 | |||
Martin Geisler
|
r9217 | [hooks] | ||
pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf | ||||
# or pretxnchangegroup.cr = python:hgext.win32text.forbidcr | ||||
Dirkjan Ochtman
|
r8873 | ''' | ||
Jesse Glick
|
r5675 | |||
Martin Geisler
|
r7225 | from mercurial.i18n import _ | ||
Peter Arrenbrecht
|
r7873 | from mercurial.node import short | ||
Dirkjan Ochtman
|
r6510 | from mercurial import util | ||
Lee Cantey
|
r4859 | import re | ||
# regexp for single LF without CR preceding. | ||||
re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE) | ||||
OHASHI Hideya
|
r6481 | newlinestr = {'\r\n': 'CRLF', '\r': 'CR'} | ||
filterstr = {'\r\n': 'clever', '\r': 'mac'} | ||||
def checknewline(s, newline, ui=None, repo=None, filename=None): | ||||
# warn if already has 'newline' in repository. | ||||
Lee Cantey
|
r4859 | # it might cause unexpected eol conversion. | ||
# see issue 302: | ||||
Dirkjan Ochtman
|
r8936 | # http://mercurial.selenic.com/bts/issue302 | ||
OHASHI Hideya
|
r6481 | if newline in s and ui and filename and repo: | ||
ui.warn(_('WARNING: %s already has %s line endings\n' | ||||
Jesse Glick
|
r5967 | 'and does not need EOL conversion by the win32text plugin.\n' | ||
'Before your next commit, please reconsider your ' | ||||
'encode/decode settings in \nMercurial.ini or %s.\n') % | ||||
OHASHI Hideya
|
r6481 | (filename, newlinestr[newline], repo.join('hgrc'))) | ||
def dumbdecode(s, cmd, **kwargs): | ||||
checknewline(s, '\r\n', **kwargs) | ||||
Lee Cantey
|
r4859 | # replace single LF to CRLF | ||
return re_single_lf.sub('\\1\r\n', s) | ||||
def dumbencode(s, cmd): | ||||
return s.replace('\r\n', '\n') | ||||
OHASHI Hideya
|
r6481 | def macdumbdecode(s, cmd, **kwargs): | ||
checknewline(s, '\r', **kwargs) | ||||
return s.replace('\n', '\r') | ||||
def macdumbencode(s, cmd): | ||||
return s.replace('\r', '\n') | ||||
Jesse Glick
|
r5967 | def cleverdecode(s, cmd, **kwargs): | ||
Bryan O'Sullivan
|
r6508 | if not util.binary(s): | ||
Patrick Mezard
|
r6473 | return dumbdecode(s, cmd, **kwargs) | ||
return s | ||||
Lee Cantey
|
r4859 | |||
def cleverencode(s, cmd): | ||||
Bryan O'Sullivan
|
r6508 | if not util.binary(s): | ||
Patrick Mezard
|
r6473 | return dumbencode(s, cmd) | ||
return s | ||||
Lee Cantey
|
r4859 | |||
OHASHI Hideya
|
r6481 | def macdecode(s, cmd, **kwargs): | ||
Bryan O'Sullivan
|
r6508 | if not util.binary(s): | ||
Patrick Mezard
|
r6484 | return macdumbdecode(s, cmd, **kwargs) | ||
return s | ||||
OHASHI Hideya
|
r6481 | |||
def macencode(s, cmd): | ||||
Bryan O'Sullivan
|
r6508 | if not util.binary(s): | ||
Patrick Mezard
|
r6484 | return macdumbencode(s, cmd) | ||
return s | ||||
OHASHI Hideya
|
r6481 | |||
Patrick Mezard
|
r5966 | _filters = { | ||
Lee Cantey
|
r4859 | 'dumbdecode:': dumbdecode, | ||
'dumbencode:': dumbencode, | ||||
'cleverdecode:': cleverdecode, | ||||
'cleverencode:': cleverencode, | ||||
OHASHI Hideya
|
r6481 | 'macdumbdecode:': macdumbdecode, | ||
'macdumbencode:': macdumbencode, | ||||
'macdecode:': macdecode, | ||||
'macencode:': macencode, | ||||
Patrick Mezard
|
r5966 | } | ||
Jesse Glick
|
r5675 | |||
Patrick Mezard
|
r6483 | def forbidnewline(ui, repo, hooktype, node, newline, **kwargs): | ||
Jesse Glick
|
r5675 | halt = False | ||
Martin Geisler
|
r8150 | seen = set() | ||
Bryan O'Sullivan
|
r8147 | # we try to walk changesets in reverse order from newest to | ||
# oldest, so that if we see a file multiple times, we take the | ||||
# newest version as canonical. this prevents us from blocking a | ||||
# changegroup that contains an unacceptable commit followed later | ||||
# by a commit that fixes the problem. | ||||
tip = repo['tip'] | ||||
for rev in xrange(len(repo)-1, repo[node].rev()-1, -1): | ||||
Matt Mackall
|
r6747 | c = repo[rev] | ||
Jesse Glick
|
r5675 | for f in c.files(): | ||
Bryan O'Sullivan
|
r8147 | if f in seen or f not in tip or f not in c: | ||
Jesse Glick
|
r5675 | continue | ||
Bryan O'Sullivan
|
r8147 | seen.add(f) | ||
Jesse Glick
|
r5675 | data = c[f].data() | ||
Bryan O'Sullivan
|
r6508 | if not util.binary(data) and newline in data: | ||
Jesse Glick
|
r5675 | if not halt: | ||
ui.warn(_('Attempt to commit or push text file(s) ' | ||||
OHASHI Hideya
|
r6481 | 'using %s line endings\n') % | ||
newlinestr[newline]) | ||||
Jesse Glick
|
r5675 | ui.warn(_('in %s: %s\n') % (short(c.node()), f)) | ||
halt = True | ||||
if halt and hooktype == 'pretxnchangegroup': | ||||
OHASHI Hideya
|
r6481 | crlf = newlinestr[newline].lower() | ||
filter = filterstr[newline] | ||||
Jesse Glick
|
r5675 | ui.warn(_('\nTo prevent this mistake in your local repository,\n' | ||
'add to Mercurial.ini or .hg/hgrc:\n' | ||||
'\n' | ||||
'[hooks]\n' | ||||
OHASHI Hideya
|
r6481 | 'pretxncommit.%s = python:hgext.win32text.forbid%s\n' | ||
Jesse Glick
|
r5675 | '\n' | ||
'and also consider adding:\n' | ||||
'\n' | ||||
'[extensions]\n' | ||||
Martin Geisler
|
r10132 | 'win32text =\n' | ||
Jesse Glick
|
r5675 | '[encode]\n' | ||
OHASHI Hideya
|
r6481 | '** = %sencode:\n' | ||
Jesse Glick
|
r5675 | '[decode]\n' | ||
OHASHI Hideya
|
r6481 | '** = %sdecode:\n') % (crlf, crlf, filter, filter)) | ||
Jesse Glick
|
r5675 | return halt | ||
Patrick Mezard
|
r5966 | |||
OHASHI Hideya
|
r6481 | def forbidcrlf(ui, repo, hooktype, node, **kwargs): | ||
Patrick Mezard
|
r6483 | return forbidnewline(ui, repo, hooktype, node, '\r\n', **kwargs) | ||
OHASHI Hideya
|
r6481 | |||
def forbidcr(ui, repo, hooktype, node, **kwargs): | ||||
Patrick Mezard
|
r6483 | return forbidnewline(ui, repo, hooktype, node, '\r', **kwargs) | ||
OHASHI Hideya
|
r6481 | |||
Patrick Mezard
|
r5966 | def reposetup(ui, repo): | ||
if not repo.local(): | ||||
return | ||||
for name, fn in _filters.iteritems(): | ||||
repo.adddatafilter(name, fn) | ||||