hgext/win32text.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43105 649d3ac37a12
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
    54 
    54 
    55 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
    55 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
    56 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
    56 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
    57 # be specifying the version(s) of Mercurial they are tested with, or
    57 # be specifying the version(s) of Mercurial they are tested with, or
    58 # leave the attribute unspecified.
    58 # leave the attribute unspecified.
    59 testedwith = 'ships-with-hg-core'
    59 testedwith = b'ships-with-hg-core'
    60 
    60 
    61 configtable = {}
    61 configtable = {}
    62 configitem = registrar.configitem(configtable)
    62 configitem = registrar.configitem(configtable)
    63 
    63 
    64 configitem(
    64 configitem(
    65     'win32text', 'warn', default=True,
    65     b'win32text', b'warn', default=True,
    66 )
    66 )
    67 
    67 
    68 # regexp for single LF without CR preceding.
    68 # regexp for single LF without CR preceding.
    69 re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE)
    69 re_single_lf = re.compile(b'(^|[^\r])\n', re.MULTILINE)
    70 
    70 
    71 newlinestr = {'\r\n': 'CRLF', '\r': 'CR'}
    71 newlinestr = {b'\r\n': b'CRLF', b'\r': b'CR'}
    72 filterstr = {'\r\n': 'clever', '\r': 'mac'}
    72 filterstr = {b'\r\n': b'clever', b'\r': b'mac'}
    73 
    73 
    74 
    74 
    75 def checknewline(s, newline, ui=None, repo=None, filename=None):
    75 def checknewline(s, newline, ui=None, repo=None, filename=None):
    76     # warn if already has 'newline' in repository.
    76     # warn if already has 'newline' in repository.
    77     # it might cause unexpected eol conversion.
    77     # it might cause unexpected eol conversion.
    78     # see issue 302:
    78     # see issue 302:
    79     #   https://bz.mercurial-scm.org/302
    79     #   https://bz.mercurial-scm.org/302
    80     if newline in s and ui and filename and repo:
    80     if newline in s and ui and filename and repo:
    81         ui.warn(
    81         ui.warn(
    82             _(
    82             _(
    83                 'WARNING: %s already has %s line endings\n'
    83                 b'WARNING: %s already has %s line endings\n'
    84                 'and does not need EOL conversion by the win32text plugin.\n'
    84                 b'and does not need EOL conversion by the win32text plugin.\n'
    85                 'Before your next commit, please reconsider your '
    85                 b'Before your next commit, please reconsider your '
    86                 'encode/decode settings in \nMercurial.ini or %s.\n'
    86                 b'encode/decode settings in \nMercurial.ini or %s.\n'
    87             )
    87             )
    88             % (filename, newlinestr[newline], repo.vfs.join('hgrc'))
    88             % (filename, newlinestr[newline], repo.vfs.join(b'hgrc'))
    89         )
    89         )
    90 
    90 
    91 
    91 
    92 def dumbdecode(s, cmd, **kwargs):
    92 def dumbdecode(s, cmd, **kwargs):
    93     checknewline(s, '\r\n', **kwargs)
    93     checknewline(s, b'\r\n', **kwargs)
    94     # replace single LF to CRLF
    94     # replace single LF to CRLF
    95     return re_single_lf.sub('\\1\r\n', s)
    95     return re_single_lf.sub(b'\\1\r\n', s)
    96 
    96 
    97 
    97 
    98 def dumbencode(s, cmd):
    98 def dumbencode(s, cmd):
    99     return s.replace('\r\n', '\n')
    99     return s.replace(b'\r\n', b'\n')
   100 
   100 
   101 
   101 
   102 def macdumbdecode(s, cmd, **kwargs):
   102 def macdumbdecode(s, cmd, **kwargs):
   103     checknewline(s, '\r', **kwargs)
   103     checknewline(s, b'\r', **kwargs)
   104     return s.replace('\n', '\r')
   104     return s.replace(b'\n', b'\r')
   105 
   105 
   106 
   106 
   107 def macdumbencode(s, cmd):
   107 def macdumbencode(s, cmd):
   108     return s.replace('\r', '\n')
   108     return s.replace(b'\r', b'\n')
   109 
   109 
   110 
   110 
   111 def cleverdecode(s, cmd, **kwargs):
   111 def cleverdecode(s, cmd, **kwargs):
   112     if not stringutil.binary(s):
   112     if not stringutil.binary(s):
   113         return dumbdecode(s, cmd, **kwargs)
   113         return dumbdecode(s, cmd, **kwargs)
   131         return macdumbencode(s, cmd)
   131         return macdumbencode(s, cmd)
   132     return s
   132     return s
   133 
   133 
   134 
   134 
   135 _filters = {
   135 _filters = {
   136     'dumbdecode:': dumbdecode,
   136     b'dumbdecode:': dumbdecode,
   137     'dumbencode:': dumbencode,
   137     b'dumbencode:': dumbencode,
   138     'cleverdecode:': cleverdecode,
   138     b'cleverdecode:': cleverdecode,
   139     'cleverencode:': cleverencode,
   139     b'cleverencode:': cleverencode,
   140     'macdumbdecode:': macdumbdecode,
   140     b'macdumbdecode:': macdumbdecode,
   141     'macdumbencode:': macdumbencode,
   141     b'macdumbencode:': macdumbencode,
   142     'macdecode:': macdecode,
   142     b'macdecode:': macdecode,
   143     'macencode:': macencode,
   143     b'macencode:': macencode,
   144 }
   144 }
   145 
   145 
   146 
   146 
   147 def forbidnewline(ui, repo, hooktype, node, newline, **kwargs):
   147 def forbidnewline(ui, repo, hooktype, node, newline, **kwargs):
   148     halt = False
   148     halt = False
   150     # we try to walk changesets in reverse order from newest to
   150     # we try to walk changesets in reverse order from newest to
   151     # oldest, so that if we see a file multiple times, we take the
   151     # oldest, so that if we see a file multiple times, we take the
   152     # newest version as canonical. this prevents us from blocking a
   152     # newest version as canonical. this prevents us from blocking a
   153     # changegroup that contains an unacceptable commit followed later
   153     # changegroup that contains an unacceptable commit followed later
   154     # by a commit that fixes the problem.
   154     # by a commit that fixes the problem.
   155     tip = repo['tip']
   155     tip = repo[b'tip']
   156     for rev in pycompat.xrange(
   156     for rev in pycompat.xrange(
   157         repo.changelog.tiprev(), repo[node].rev() - 1, -1
   157         repo.changelog.tiprev(), repo[node].rev() - 1, -1
   158     ):
   158     ):
   159         c = repo[rev]
   159         c = repo[rev]
   160         for f in c.files():
   160         for f in c.files():
   164             data = c[f].data()
   164             data = c[f].data()
   165             if not stringutil.binary(data) and newline in data:
   165             if not stringutil.binary(data) and newline in data:
   166                 if not halt:
   166                 if not halt:
   167                     ui.warn(
   167                     ui.warn(
   168                         _(
   168                         _(
   169                             'attempt to commit or push text file(s) '
   169                             b'attempt to commit or push text file(s) '
   170                             'using %s line endings\n'
   170                             b'using %s line endings\n'
   171                         )
   171                         )
   172                         % newlinestr[newline]
   172                         % newlinestr[newline]
   173                     )
   173                     )
   174                 ui.warn(_('in %s: %s\n') % (short(c.node()), f))
   174                 ui.warn(_(b'in %s: %s\n') % (short(c.node()), f))
   175                 halt = True
   175                 halt = True
   176     if halt and hooktype == 'pretxnchangegroup':
   176     if halt and hooktype == b'pretxnchangegroup':
   177         crlf = newlinestr[newline].lower()
   177         crlf = newlinestr[newline].lower()
   178         filter = filterstr[newline]
   178         filter = filterstr[newline]
   179         ui.warn(
   179         ui.warn(
   180             _(
   180             _(
   181                 '\nTo prevent this mistake in your local repository,\n'
   181                 b'\nTo prevent this mistake in your local repository,\n'
   182                 'add to Mercurial.ini or .hg/hgrc:\n'
   182                 b'add to Mercurial.ini or .hg/hgrc:\n'
   183                 '\n'
   183                 b'\n'
   184                 '[hooks]\n'
   184                 b'[hooks]\n'
   185                 'pretxncommit.%s = python:hgext.win32text.forbid%s\n'
   185                 b'pretxncommit.%s = python:hgext.win32text.forbid%s\n'
   186                 '\n'
   186                 b'\n'
   187                 'and also consider adding:\n'
   187                 b'and also consider adding:\n'
   188                 '\n'
   188                 b'\n'
   189                 '[extensions]\n'
   189                 b'[extensions]\n'
   190                 'win32text =\n'
   190                 b'win32text =\n'
   191                 '[encode]\n'
   191                 b'[encode]\n'
   192                 '** = %sencode:\n'
   192                 b'** = %sencode:\n'
   193                 '[decode]\n'
   193                 b'[decode]\n'
   194                 '** = %sdecode:\n'
   194                 b'** = %sdecode:\n'
   195             )
   195             )
   196             % (crlf, crlf, filter, filter)
   196             % (crlf, crlf, filter, filter)
   197         )
   197         )
   198     return halt
   198     return halt
   199 
   199 
   200 
   200 
   201 def forbidcrlf(ui, repo, hooktype, node, **kwargs):
   201 def forbidcrlf(ui, repo, hooktype, node, **kwargs):
   202     return forbidnewline(ui, repo, hooktype, node, '\r\n', **kwargs)
   202     return forbidnewline(ui, repo, hooktype, node, b'\r\n', **kwargs)
   203 
   203 
   204 
   204 
   205 def forbidcr(ui, repo, hooktype, node, **kwargs):
   205 def forbidcr(ui, repo, hooktype, node, **kwargs):
   206     return forbidnewline(ui, repo, hooktype, node, '\r', **kwargs)
   206     return forbidnewline(ui, repo, hooktype, node, b'\r', **kwargs)
   207 
   207 
   208 
   208 
   209 def reposetup(ui, repo):
   209 def reposetup(ui, repo):
   210     if not repo.local():
   210     if not repo.local():
   211         return
   211         return
   213         repo.adddatafilter(name, fn)
   213         repo.adddatafilter(name, fn)
   214 
   214 
   215 
   215 
   216 def extsetup(ui):
   216 def extsetup(ui):
   217     # deprecated config: win32text.warn
   217     # deprecated config: win32text.warn
   218     if ui.configbool('win32text', 'warn'):
   218     if ui.configbool(b'win32text', b'warn'):
   219         ui.warn(
   219         ui.warn(
   220             _(
   220             _(
   221                 "win32text is deprecated: "
   221                 b"win32text is deprecated: "
   222                 "https://mercurial-scm.org/wiki/Win32TextExtension\n"
   222                 b"https://mercurial-scm.org/wiki/Win32TextExtension\n"
   223             )
   223             )
   224         )
   224         )