These functions will be used internally by hg-core without needed to be
exposed to Python.
Details
Details
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Branch
- default
- Lint
No Linters Available - Unit
No Unit Test Coverage
These functions will be used internally by hg-core without needed to be
exposed to Python.
| No Linters Available |
| No Unit Test Coverage |
| Path | Packages | |||
|---|---|---|---|---|
| M | mercurial/match.py (23 lines) | |||
| M | rust/hg-cpython/src/exceptions.rs (30 lines) | |||
| D | M | rust/hg-cpython/src/filepatterns.rs (133 lines) | ||
| M | rust/hg-cpython/src/lib.rs (16 lines) |
| Commit | Parents | Author | Summary | Date |
|---|---|---|---|---|
| 8d4522836683 | efc111653d30 | Raphaël Gomès | Jan 24 2020, 4:55 AM |
| error, | error, | ||||
| pathutil, | pathutil, | ||||
| policy, | policy, | ||||
| pycompat, | pycompat, | ||||
| util, | util, | ||||
| ) | ) | ||||
| from .utils import stringutil | from .utils import stringutil | ||||
| rustmod = policy.importrust('filepatterns') | rustmod = policy.importrust('dirstate') | ||||
| allpatternkinds = ( | allpatternkinds = ( | ||||
| b're', | b're', | ||||
| b'glob', | b'glob', | ||||
| b'path', | b'path', | ||||
| b'relglob', | b'relglob', | ||||
| b'relpath', | b'relpath', | ||||
| b'relre', | b'relre', | ||||
| res += escape(c, c) | res += escape(c, c) | ||||
| return res | return res | ||||
| def _regex(kind, pat, globsuffix): | def _regex(kind, pat, globsuffix): | ||||
| '''Convert a (normalized) pattern of any kind into a | '''Convert a (normalized) pattern of any kind into a | ||||
| regular expression. | regular expression. | ||||
| globsuffix is appended to the regexp of globs.''' | globsuffix is appended to the regexp of globs.''' | ||||
| if rustmod is not None: | |||||
| try: | |||||
| return rustmod.build_single_regex(kind, pat, globsuffix) | |||||
| except rustmod.PatternError: | |||||
| raise error.ProgrammingError( | |||||
| b'not a regex pattern: %s:%s' % (kind, pat) | |||||
| ) | |||||
| if not pat and kind in (b'glob', b'relpath'): | if not pat and kind in (b'glob', b'relpath'): | ||||
| return b'' | return b'' | ||||
| if kind == b're': | if kind == b're': | ||||
| return pat | return pat | ||||
| if kind in (b'path', b'relpath'): | if kind in (b'path', b'relpath'): | ||||
| if pat == b'.': | if pat == b'.': | ||||
| return b'' | return b'' | ||||
| return util.stringutil.reescape(pat) + b'(?:/|$)' | return util.stringutil.reescape(pat) + b'(?:/|$)' | ||||
| rootglob:pat # rooted glob (same root as ^ in regexps) | rootglob:pat # rooted glob (same root as ^ in regexps) | ||||
| pattern # pattern of the current default type | pattern # pattern of the current default type | ||||
| if sourceinfo is set, returns a list of tuples: | if sourceinfo is set, returns a list of tuples: | ||||
| (pattern, lineno, originalline). | (pattern, lineno, originalline). | ||||
| This is useful to debug ignore patterns. | This is useful to debug ignore patterns. | ||||
| ''' | ''' | ||||
| if rustmod is not None: | |||||
| result, warnings = rustmod.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(_(b"%s: ignoring invalid syntax '%s'\n") % warning_params) | |||||
| return result | |||||
| syntaxes = { | syntaxes = { | ||||
| b're': b'relre:', | b're': b'relre:', | ||||
| b'regexp': b'relre:', | b'regexp': b'relre:', | ||||
| b'glob': b'relglob:', | b'glob': b'relglob:', | ||||
| b'rootglob': b'rootglob:', | b'rootglob': b'rootglob:', | ||||
| b'include': b'include', | b'include': b'include', | ||||
| b'subinclude': b'subinclude', | b'subinclude': b'subinclude', | ||||
| } | } | ||||
| // ancestors.rs | // ancestors.rs | ||||
| // | // | ||||
| // Copyright 2018 Georges Racinet <gracinet@anybox.fr> | // Copyright 2018 Georges Racinet <gracinet@anybox.fr> | ||||
| // | // | ||||
| // This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
| // GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
| //! Bindings for Rust errors | //! Bindings for Rust errors | ||||
| //! | //! | ||||
| //! [`GraphError`] exposes `hg::GraphError` as a subclass of `ValueError` | //! [`GraphError`] exposes `hg::GraphError` as a subclass of `ValueError` | ||||
| //! but some variants of `hg::GraphError` can be converted directly to other | //! but some variants of `hg::GraphError` can be converted directly to other | ||||
| //! existing Python exceptions if appropriate. | //! existing Python exceptions if appropriate. | ||||
| //! | //! | ||||
| //! [`GraphError`]: struct.GraphError.html | //! [`GraphError`]: struct.GraphError.html | ||||
| use cpython::{ | use cpython::{ | ||||
| exc::{IOError, RuntimeError, ValueError}, | exc::{RuntimeError, ValueError}, | ||||
| py_exception, PyErr, Python, | py_exception, PyErr, Python, | ||||
| }; | }; | ||||
| use hg; | use hg; | ||||
| py_exception!(rustext, GraphError, ValueError); | py_exception!(rustext, GraphError, ValueError); | ||||
| impl GraphError { | impl GraphError { | ||||
| pub fn pynew(py: Python, inner: hg::GraphError) -> PyErr { | pub fn pynew(py: Python, inner: hg::GraphError) -> PyErr { | ||||
| Err(e) => e, | Err(e) => e, | ||||
| Ok(cls) => PyErr::from_instance(py, cls), | Ok(cls) => PyErr::from_instance(py, cls), | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| py_exception!(rustext, PatternError, RuntimeError); | |||||
| py_exception!(rustext, PatternFileError, RuntimeError); | |||||
| py_exception!(rustext, HgPathPyError, RuntimeError); | py_exception!(rustext, HgPathPyError, RuntimeError); | ||||
| impl PatternError { | |||||
| pub fn pynew(py: Python, inner: hg::PatternError) -> PyErr { | |||||
| match inner { | |||||
| hg::PatternError::UnsupportedSyntax(m) => { | |||||
| PatternError::new(py, ("PatternError", m)) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| impl PatternFileError { | |||||
| pub fn pynew(py: Python, inner: hg::PatternFileError) -> PyErr { | |||||
| match inner { | |||||
| hg::PatternFileError::IO(e) => { | |||||
| let value = (e.raw_os_error().unwrap_or(2), e.to_string()); | |||||
| PyErr::new::<IOError, _>(py, value) | |||||
| } | |||||
| hg::PatternFileError::Pattern(e, l) => match e { | |||||
| hg::PatternError::UnsupportedSyntax(m) => { | |||||
| PatternFileError::new(py, ("PatternFileError", m, l)) | |||||
| } | |||||
| }, | |||||
| } | |||||
| } | |||||
| } | |||||
| py_exception!(shared_ref, AlreadyBorrowed, RuntimeError); | py_exception!(shared_ref, AlreadyBorrowed, RuntimeError); | ||||
| // filepatterns.rs | |||||
| // | |||||
| // Copyright 2019, Georges Racinet <gracinet@anybox.fr>, | |||||
| // Raphaël Gomès <rgomes@octobus.net> | |||||
| // | |||||
| // This software may be used and distributed according to the terms of the | |||||
| // GNU General Public License version 2 or any later version. | |||||
| //! Bindings for the `hg::filepatterns` module provided by the | |||||
| //! `hg-core` crate. From Python, this will be seen as `rustext.filepatterns` | |||||
| //! and can be used as replacement for the the pure `filepatterns` Python | |||||
| //! module. | |||||
| use crate::exceptions::{PatternError, PatternFileError}; | |||||
| use cpython::{ | |||||
| PyBytes, PyDict, PyModule, PyObject, PyResult, PyTuple, Python, ToPyObject, | |||||
| }; | |||||
| use hg::utils::files; | |||||
| use hg::{build_single_regex, read_pattern_file, LineNumber, PatternTuple}; | |||||
| use std::path::PathBuf; | |||||
| /// Rust does not like functions with different return signatures. | |||||
| /// The 3-tuple version is always returned by the hg-core function, | |||||
| /// the (potential) conversion is handled at this level since it is not likely | |||||
| /// to have any measurable impact on performance. | |||||
| /// | |||||
| /// The Python implementation passes a function reference for `warn` instead | |||||
| /// of a boolean that is used to emit warnings while parsing. The Rust | |||||
| /// implementation chooses to accumulate the warnings and propagate them to | |||||
| /// Python upon completion. See the `readpatternfile` function in `match.py` | |||||
| /// for more details. | |||||
| fn read_pattern_file_wrapper( | |||||
| py: Python, | |||||
| file_path: PyObject, | |||||
| warn: bool, | |||||
| source_info: bool, | |||||
| ) -> PyResult<PyTuple> { | |||||
| let bytes = file_path.extract::<PyBytes>(py)?; | |||||
| let path = files::get_path_from_bytes(bytes.data(py)); | |||||
| match read_pattern_file(path, warn) { | |||||
| Ok((patterns, warnings)) => { | |||||
| if source_info { | |||||
| let itemgetter = |x: &PatternTuple| { | |||||
| (PyBytes::new(py, &x.0), x.1, PyBytes::new(py, &x.2)) | |||||
| }; | |||||
| let results: Vec<(PyBytes, LineNumber, PyBytes)> = | |||||
| patterns.iter().map(itemgetter).collect(); | |||||
| return Ok((results, warnings_to_py_bytes(py, &warnings)) | |||||
| .to_py_object(py)); | |||||
| } | |||||
| let itemgetter = |x: &PatternTuple| PyBytes::new(py, &x.0); | |||||
| let results: Vec<PyBytes> = | |||||
| patterns.iter().map(itemgetter).collect(); | |||||
| Ok( | |||||
| (results, warnings_to_py_bytes(py, &warnings)) | |||||
| .to_py_object(py), | |||||
| ) | |||||
| } | |||||
| Err(e) => Err(PatternFileError::pynew(py, e)), | |||||
| } | |||||
| } | |||||
| fn warnings_to_py_bytes( | |||||
| py: Python, | |||||
| warnings: &[(PathBuf, Vec<u8>)], | |||||
| ) -> Vec<(PyBytes, PyBytes)> { | |||||
| warnings | |||||
| .iter() | |||||
| .map(|(path, syn)| { | |||||
| ( | |||||
| PyBytes::new(py, &files::get_bytes_from_path(path)), | |||||
| PyBytes::new(py, syn), | |||||
| ) | |||||
| }) | |||||
| .collect() | |||||
| } | |||||
| fn build_single_regex_wrapper( | |||||
| py: Python, | |||||
| kind: PyObject, | |||||
| pat: PyObject, | |||||
| globsuffix: PyObject, | |||||
| ) -> PyResult<PyBytes> { | |||||
| match build_single_regex( | |||||
| kind.extract::<PyBytes>(py)?.data(py), | |||||
| pat.extract::<PyBytes>(py)?.data(py), | |||||
| globsuffix.extract::<PyBytes>(py)?.data(py), | |||||
| ) { | |||||
| Ok(regex) => Ok(PyBytes::new(py, ®ex)), | |||||
| Err(e) => Err(PatternError::pynew(py, e)), | |||||
| } | |||||
| } | |||||
| pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { | |||||
| let dotted_name = &format!("{}.filepatterns", package); | |||||
| let m = PyModule::new(py, dotted_name)?; | |||||
| m.add(py, "__package__", package)?; | |||||
| m.add( | |||||
| py, | |||||
| "__doc__", | |||||
| "Patterns files parsing - Rust implementation", | |||||
| )?; | |||||
| m.add( | |||||
| py, | |||||
| "build_single_regex", | |||||
| py_fn!( | |||||
| py, | |||||
| build_single_regex_wrapper( | |||||
| kind: PyObject, | |||||
| pat: PyObject, | |||||
| globsuffix: PyObject | |||||
| ) | |||||
| ), | |||||
| )?; | |||||
| m.add( | |||||
| py, | |||||
| "read_pattern_file", | |||||
| py_fn!( | |||||
| py, | |||||
| read_pattern_file_wrapper( | |||||
| file_path: PyObject, | |||||
| warn: bool, | |||||
| source_info: bool | |||||
| ) | |||||
| ), | |||||
| )?; | |||||
| m.add(py, "PatternError", py.get_type::<PatternError>())?; | |||||
| let sys = PyModule::import(py, "sys")?; | |||||
| let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; | |||||
| sys_modules.set_item(py, dotted_name, &m)?; | |||||
| Ok(m) | |||||
| } | |||||
| mod cindex; | mod cindex; | ||||
| mod conversion; | mod conversion; | ||||
| #[macro_use] | #[macro_use] | ||||
| pub mod ref_sharing; | pub mod ref_sharing; | ||||
| pub mod dagops; | pub mod dagops; | ||||
| pub mod dirstate; | pub mod dirstate; | ||||
| pub mod discovery; | pub mod discovery; | ||||
| pub mod exceptions; | pub mod exceptions; | ||||
| pub mod filepatterns; | |||||
| pub mod parsers; | pub mod parsers; | ||||
| pub mod revlog; | pub mod revlog; | ||||
| pub mod utils; | pub mod utils; | ||||
| py_module_initializer!(rustext, initrustext, PyInit_rustext, |py, m| { | py_module_initializer!(rustext, initrustext, PyInit_rustext, |py, m| { | ||||
| m.add( | m.add( | ||||
| py, | py, | ||||
| "__doc__", | "__doc__", | ||||
| "Mercurial core concepts - Rust implementation", | "Mercurial core concepts - Rust implementation", | ||||
| )?; | )?; | ||||
| let dotted_name: String = m.get(py, "__name__")?.extract(py)?; | let dotted_name: String = m.get(py, "__name__")?.extract(py)?; | ||||
| m.add(py, "ancestor", ancestors::init_module(py, &dotted_name)?)?; | m.add(py, "ancestor", ancestors::init_module(py, &dotted_name)?)?; | ||||
| m.add(py, "dagop", dagops::init_module(py, &dotted_name)?)?; | m.add(py, "dagop", dagops::init_module(py, &dotted_name)?)?; | ||||
| m.add(py, "discovery", discovery::init_module(py, &dotted_name)?)?; | m.add(py, "discovery", discovery::init_module(py, &dotted_name)?)?; | ||||
| m.add(py, "dirstate", dirstate::init_module(py, &dotted_name)?)?; | m.add(py, "dirstate", dirstate::init_module(py, &dotted_name)?)?; | ||||
| m.add(py, "revlog", revlog::init_module(py, &dotted_name)?)?; | m.add(py, "revlog", revlog::init_module(py, &dotted_name)?)?; | ||||
| m.add( | m.add( | ||||
| py, | py, | ||||
| "filepatterns", | |||||
| filepatterns::init_module(py, &dotted_name)?, | |||||
| )?; | |||||
| m.add( | |||||
| py, | |||||
| "parsers", | "parsers", | ||||
| parsers::init_parsers_module(py, &dotted_name)?, | parsers::init_parsers_module(py, &dotted_name)?, | ||||
| )?; | )?; | ||||
| m.add(py, "GraphError", py.get_type::<exceptions::GraphError>())?; | m.add(py, "GraphError", py.get_type::<exceptions::GraphError>())?; | ||||
| m.add( | |||||
| py, | |||||
| "PatternFileError", | |||||
| py.get_type::<exceptions::PatternFileError>(), | |||||
| )?; | |||||
| m.add( | |||||
| py, | |||||
| "PatternError", | |||||
| py.get_type::<exceptions::PatternError>(), | |||||
| )?; | |||||
| Ok(()) | Ok(()) | ||||
| }); | }); | ||||
| #[cfg(not(any(feature = "python27-bin", feature = "python3-bin")))] | #[cfg(not(any(feature = "python27-bin", feature = "python3-bin")))] | ||||
| #[test] | #[test] | ||||
| #[ignore] | #[ignore] | ||||
| fn libpython_must_be_linked_to_run_tests() { | fn libpython_must_be_linked_to_run_tests() { | ||||
| // stub function to tell that some tests wouldn't run | // stub function to tell that some tests wouldn't run | ||||
| } | } | ||||