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 |
---|---|---|---|---|
99b784745695 | e76a9b09e6f9 | Raphaël Gomès | Jan 14 2020, 10:58 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 | ||||
} | } |