filepatterns.rs
134 lines
| 4.2 KiB
| application/rls-services+xml
|
RustLexer
|
r42515 | // 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` | ||||
|
r43109 | //! and can be used as replacement for the the pure `filepatterns` Python | ||
//! module. | ||||
|
r42515 | //! | ||
|
r42828 | use crate::exceptions::{PatternError, PatternFileError}; | ||
|
r42515 | use cpython::{ | ||
|
r44096 | PyBytes, PyDict, PyModule, PyObject, PyResult, PyTuple, Python, ToPyObject, | ||
|
r42515 | }; | ||
|
r44210 | use hg::utils::files; | ||
use hg::{build_single_regex, read_pattern_file, LineNumber, PatternTuple}; | ||||
|
r43227 | use std::path::PathBuf; | ||
|
r42515 | |||
/// 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, | ||||
|
r42630 | file_path: PyObject, | ||
|
r42515 | warn: bool, | ||
source_info: bool, | ||||
) -> PyResult<PyTuple> { | ||||
|
r43227 | let bytes = file_path.extract::<PyBytes>(py)?; | ||
|
r44210 | let path = files::get_path_from_bytes(bytes.data(py)); | ||
|
r43227 | match read_pattern_file(path, warn) { | ||
|
r42515 | Ok((patterns, warnings)) => { | ||
if source_info { | ||||
|
r42630 | 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(); | ||||
|
r42857 | return Ok((results, warnings_to_py_bytes(py, &warnings)) | ||
.to_py_object(py)); | ||||
|
r42515 | } | ||
|
r42630 | let itemgetter = |x: &PatternTuple| PyBytes::new(py, &x.0); | ||
let results: Vec<PyBytes> = | ||||
|
r42515 | patterns.iter().map(itemgetter).collect(); | ||
|
r42857 | Ok( | ||
(results, warnings_to_py_bytes(py, &warnings)) | ||||
.to_py_object(py), | ||||
) | ||||
|
r42515 | } | ||
Err(e) => Err(PatternFileError::pynew(py, e)), | ||||
} | ||||
} | ||||
|
r42857 | fn warnings_to_py_bytes( | ||
py: Python, | ||||
|
r43227 | warnings: &[(PathBuf, Vec<u8>)], | ||
|
r44096 | ) -> Vec<(PyBytes, PyBytes)> { | ||
|
r42857 | warnings | ||
.iter() | ||||
|
r43227 | .map(|(path, syn)| { | ||
( | ||||
|
r44211 | PyBytes::new(py, &files::get_bytes_from_path(path)), | ||
|
r43227 | PyBytes::new(py, syn), | ||
) | ||||
}) | ||||
|
r42857 | .collect() | ||
} | ||||
|
r42515 | fn build_single_regex_wrapper( | ||
py: Python, | ||||
|
r42630 | kind: PyObject, | ||
pat: PyObject, | ||||
globsuffix: PyObject, | ||||
) -> PyResult<PyBytes> { | ||||
|
r42515 | match build_single_regex( | ||
|
r42630 | kind.extract::<PyBytes>(py)?.data(py), | ||
pat.extract::<PyBytes>(py)?.data(py), | ||||
globsuffix.extract::<PyBytes>(py)?.data(py), | ||||
|
r42515 | ) { | ||
|
r42630 | Ok(regex) => Ok(PyBytes::new(py, ®ex)), | ||
|
r42515 | 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( | ||||
|
r42630 | kind: PyObject, | ||
pat: PyObject, | ||||
globsuffix: PyObject | ||||
|
r42515 | ) | ||
), | ||||
)?; | ||||
m.add( | ||||
py, | ||||
"read_pattern_file", | ||||
py_fn!( | ||||
py, | ||||
read_pattern_file_wrapper( | ||||
|
r42630 | file_path: PyObject, | ||
|
r42515 | warn: bool, | ||
source_info: bool | ||||
) | ||||
), | ||||
)?; | ||||
|
r42630 | m.add(py, "PatternError", py.get_type::<PatternError>())?; | ||
|
r42515 | 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) | ||||
} | ||||