Patchwork [3,of,3] rust-filepatterns: call new Rust implementations from Python

login
register
mail settings
Submitter Raphaël Gomès
Date April 17, 2019, midnight
Message ID <ba9a1dd508c6c167d0c9.1555459240@alphare-carbon.lan>
Download mbox | patch
Permalink /patch/39681/
State New
Headers show

Comments

Raphaël Gomès - April 17, 2019, midnight
# HG changeset patch
# User Raphaël Gomès <rgomes@octobus.net>
# Date 1555442904 -7200
#      Tue Apr 16 21:28:24 2019 +0200
# Node ID ba9a1dd508c6c167d0c920ece643854c5bc6b6e7
# Parent  8586c2273ee3f0c4dd08bf69474fa33bb19de405
# EXP-Topic rust-filepatterns
rust-filepatterns: call new Rust implementations from Python

This change adds the import to the `rust-cpython` bindings and uses
them when appropriate.

A wrapper function has been defined in the case of `_regex` to
keep this patch simple.
Raphaël Gomès - April 18, 2019, 12:17 p.m.
This patch stack was re-sent using Phabricator as D6271, D6272 and D6273.

On 4/17/19 2:00 AM, Raphaël Gomès wrote:
> # HG changeset patch
> # User Raphaël Gomès <rgomes@octobus.net>
> # Date 1555442904 -7200
> #      Tue Apr 16 21:28:24 2019 +0200
> # Node ID ba9a1dd508c6c167d0c920ece643854c5bc6b6e7
> # Parent  8586c2273ee3f0c4dd08bf69474fa33bb19de405
> # EXP-Topic rust-filepatterns
> rust-filepatterns: call new Rust implementations from Python
>
> This change adds the import to the `rust-cpython` bindings and uses
> them when appropriate.
>
> A wrapper function has been defined in the case of `_regex` to
> keep this patch simple.
>
> diff -r 8586c2273ee3 -r ba9a1dd508c6 mercurial/match.py
> --- a/mercurial/match.py	Tue Apr 16 21:27:47 2019 +0200
> +++ b/mercurial/match.py	Tue Apr 16 21:28:24 2019 +0200
> @@ -24,6 +24,12 @@
>       stringutil,
>   )
>   
> +try:
> +    from . import rustext
> +    rustext.__name__  # force actual import (see hgdemandimport)
> +except ImportError:
> +    rustext = None
> +
>   allpatternkinds = ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
>                      'rootglob',
>                      'listfile', 'listfile0', 'set', 'include', 'subinclude',
> @@ -1178,8 +1184,22 @@
>       return res
>   
>   def _regex(kind, pat, globsuffix):
> -    '''Convert a (normalized) pattern of any kind into a regular expression.
> +    '''Convert a (normalized) pattern of any kind into a
> +    regular expression.
>       globsuffix is appended to the regexp of globs.'''
> +
> +    if rustext is not None:
> +        try:
> +            return rustext.filepatterns.build_single_regex(
> +                kind,
> +                pat,
> +                globsuffix
> +            )
> +        except rustext.filepatterns.PatternError:
> +            raise error.ProgrammingError(
> +                'not a regex pattern: %s:%s' % (kind, pat)
> +            )
> +
>       if not pat:
>           return ''
>       if kind == 're':
> @@ -1421,9 +1441,24 @@
>       pattern        # pattern of the current default type
>   
>       if sourceinfo is set, returns a list of tuples:
> -    (pattern, lineno, originalline). This is useful to debug ignore patterns.
> +    (pattern, lineno, originalline).
> +    This is useful to debug ignore patterns.
>       '''
>   
> +    if rustext is not None:
> +        result, warnings = rustext.filepatterns.read_pattern_file(
> +            filepath,
> +            bool(warn),
> +            sourceinfo,
> +        )
> +
> +        for warning_params in warnings:
> +            # Can't be easily emitted from Rust, because it would require
> +            # a mechanism for both gettext and calling the `warn` function.
> +            warn(_("%s: ignoring invalid syntax '%s'\n") % warning_params)
> +
> +        return result
> +
>       syntaxes = {
>           're': 'relre:',
>           'regexp': 'relre:',
> diff -r 8586c2273ee3 -r ba9a1dd508c6 tests/common-pattern.py
> --- a/tests/common-pattern.py	Tue Apr 16 21:27:47 2019 +0200
> +++ b/tests/common-pattern.py	Tue Apr 16 21:28:24 2019 +0200
> @@ -115,6 +115,11 @@
>   # Various platform error strings, keyed on a common replacement string
>   _errors = {
>       br'$ENOENT$': (
> +        # IOError in Python does not have the same error message
> +        # than in Rust, and automatic conversion is not possible
> +        # because of module member privacy.
> +        br'No such file or directory \(os error 2\)',
> +
>           # strerror()
>           br'No such file or directory',
>   
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Patch

diff -r 8586c2273ee3 -r ba9a1dd508c6 mercurial/match.py
--- a/mercurial/match.py	Tue Apr 16 21:27:47 2019 +0200
+++ b/mercurial/match.py	Tue Apr 16 21:28:24 2019 +0200
@@ -24,6 +24,12 @@ 
     stringutil,
 )
 
+try:
+    from . import rustext
+    rustext.__name__  # force actual import (see hgdemandimport)
+except ImportError:
+    rustext = None
+
 allpatternkinds = ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
                    'rootglob',
                    'listfile', 'listfile0', 'set', 'include', 'subinclude',
@@ -1178,8 +1184,22 @@ 
     return res
 
 def _regex(kind, pat, globsuffix):
-    '''Convert a (normalized) pattern of any kind into a regular expression.
+    '''Convert a (normalized) pattern of any kind into a
+    regular expression.
     globsuffix is appended to the regexp of globs.'''
+
+    if rustext is not None:
+        try:
+            return rustext.filepatterns.build_single_regex(
+                kind,
+                pat,
+                globsuffix
+            )
+        except rustext.filepatterns.PatternError:
+            raise error.ProgrammingError(
+                'not a regex pattern: %s:%s' % (kind, pat)
+            )
+
     if not pat:
         return ''
     if kind == 're':
@@ -1421,9 +1441,24 @@ 
     pattern        # pattern of the current default type
 
     if sourceinfo is set, returns a list of tuples:
-    (pattern, lineno, originalline). This is useful to debug ignore patterns.
+    (pattern, lineno, originalline).
+    This is useful to debug ignore patterns.
     '''
 
+    if rustext is not None:
+        result, warnings = rustext.filepatterns.read_pattern_file(
+            filepath,
+            bool(warn),
+            sourceinfo,
+        )
+
+        for warning_params in warnings:
+            # Can't be easily emitted from Rust, because it would require
+            # a mechanism for both gettext and calling the `warn` function.
+            warn(_("%s: ignoring invalid syntax '%s'\n") % warning_params)
+
+        return result
+
     syntaxes = {
         're': 'relre:',
         'regexp': 'relre:',
diff -r 8586c2273ee3 -r ba9a1dd508c6 tests/common-pattern.py
--- a/tests/common-pattern.py	Tue Apr 16 21:27:47 2019 +0200
+++ b/tests/common-pattern.py	Tue Apr 16 21:28:24 2019 +0200
@@ -115,6 +115,11 @@ 
 # Various platform error strings, keyed on a common replacement string
 _errors = {
     br'$ENOENT$': (
+        # IOError in Python does not have the same error message
+        # than in Rust, and automatic conversion is not possible
+        # because of module member privacy.
+        br'No such file or directory \(os error 2\)',
+
         # strerror()
         br'No such file or directory',