rust/hg-cpython/src/filepatterns.rs
changeset 42328 94f3a73b6672
parent 41693 060c030c9993
child 42437 9609430d3625
equal deleted inserted replaced
42327:e8f3740cc067 42328:94f3a73b6672
       
     1 // filepatterns.rs
       
     2 //
       
     3 // Copyright 2019, Georges Racinet <gracinet@anybox.fr>,
       
     4 // Raphaël Gomès <rgomes@octobus.net>
       
     5 //
       
     6 // This software may be used and distributed according to the terms of the
       
     7 // GNU General Public License version 2 or any later version.
       
     8 
       
     9 //! Bindings for the `hg::filepatterns` module provided by the
       
    10 //! `hg-core` crate. From Python, this will be seen as `rustext.filepatterns`
       
    11 //! and can be used as replacement for the the pure `filepatterns` Python module.
       
    12 //!
       
    13 use cpython::{
       
    14     exc, PyDict, PyErr, PyModule, PyResult, PyString, PyTuple, Python,
       
    15     ToPyObject,
       
    16 };
       
    17 use hg::{build_single_regex, read_pattern_file, PatternTuple};
       
    18 use exceptions::{
       
    19     PatternError,
       
    20     PatternFileError,
       
    21 };
       
    22 
       
    23 /// Rust does not like functions with different return signatures.
       
    24 /// The 3-tuple version is always returned by the hg-core function,
       
    25 /// the (potential) conversion is handled at this level since it is not likely
       
    26 /// to have any measurable impact on performance.
       
    27 ///
       
    28 /// The Python implementation passes a function reference for `warn` instead
       
    29 /// of a boolean that is used to emit warnings while parsing. The Rust
       
    30 /// implementation chooses to accumulate the warnings and propagate them to
       
    31 /// Python upon completion. See the `readpatternfile` function in `match.py`
       
    32 /// for more details.
       
    33 fn read_pattern_file_wrapper(
       
    34     py: Python,
       
    35     file_path: String,
       
    36     warn: bool,
       
    37     source_info: bool,
       
    38 ) -> PyResult<PyTuple> {
       
    39     match read_pattern_file(file_path, warn) {
       
    40         Ok((patterns, warnings)) => {
       
    41             if source_info {
       
    42                 return Ok((patterns, warnings).to_py_object(py));
       
    43             }
       
    44             let itemgetter = |x: &PatternTuple| x.0.to_py_object(py);
       
    45             let results: Vec<PyString> =
       
    46                 patterns.iter().map(itemgetter).collect();
       
    47             Ok((results, warnings).to_py_object(py))
       
    48         }
       
    49         Err(e) => Err(PatternFileError::pynew(py, e)),
       
    50     }
       
    51 }
       
    52 
       
    53 fn build_single_regex_wrapper(
       
    54     py: Python,
       
    55     kind: String,
       
    56     pat: String,
       
    57     globsuffix: String,
       
    58 ) -> PyResult<PyString> {
       
    59     match build_single_regex(
       
    60         kind.as_ref(),
       
    61         pat.as_bytes(),
       
    62         globsuffix.as_bytes(),
       
    63     ) {
       
    64         Ok(regex) => match String::from_utf8(regex) {
       
    65             Ok(regex) => Ok(regex.to_py_object(py)),
       
    66             Err(e) => Err(PyErr::new::<exc::UnicodeDecodeError, _>(
       
    67                 py,
       
    68                 e.to_string(),
       
    69             )),
       
    70         },
       
    71         Err(e) => Err(PatternError::pynew(py, e)),
       
    72     }
       
    73 }
       
    74 
       
    75 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
       
    76     let dotted_name = &format!("{}.filepatterns", package);
       
    77     let m = PyModule::new(py, dotted_name)?;
       
    78 
       
    79     m.add(py, "__package__", package)?;
       
    80     m.add(
       
    81         py,
       
    82         "__doc__",
       
    83         "Patterns files parsing - Rust implementation",
       
    84     )?;
       
    85     m.add(
       
    86         py,
       
    87         "build_single_regex",
       
    88         py_fn!(
       
    89             py,
       
    90             build_single_regex_wrapper(
       
    91                 kind: String,
       
    92                 pat: String,
       
    93                 globsuffix: String
       
    94             )
       
    95         ),
       
    96     )?;
       
    97     m.add(
       
    98         py,
       
    99         "read_pattern_file",
       
   100         py_fn!(
       
   101             py,
       
   102             read_pattern_file_wrapper(
       
   103                 file_path: String,
       
   104                 warn: bool,
       
   105                 source_info: bool
       
   106             )
       
   107         ),
       
   108     )?;
       
   109 
       
   110     let sys = PyModule::import(py, "sys")?;
       
   111     let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
       
   112     sys_modules.set_item(py, dotted_name, &m)?;
       
   113 
       
   114     Ok(m)
       
   115 }