##// END OF EJS Templates
packaging: split Inno installer building from Mercurial building...
packaging: split Inno installer building from Mercurial building We want to make the logic for producing the installer agnostic about how Mercurial is built to allow for alternate build methods (like PyOxidizer). Differential Revision: https://phab.mercurial-scm.org/D8472

File last commit:

r45088:e62052d0 default
r45269:eec66d9c stable
Show More
status.rs
297 lines | 9.4 KiB | application/rls-services+xml | RustLexer
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 // status.rs
//
// Copyright 2019, 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::status` module provided by the
Yuya Nishihara
rust-cpython: run cargo fmt
r43612 //! `hg-core` crate. From Python, this will be seen as
//! `rustext.dirstate.status`.
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 use crate::{dirstate::DirstateMap, exceptions::FallbackError};
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 use cpython::{
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 exc::ValueError, ObjectProtocol, PyBytes, PyErr, PyList, PyObject,
PyResult, PyTuple, Python, PythonObject, ToPyObject,
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 };
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 use hg::{
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 matchers::{AlwaysMatcher, FileMatcher, IncludeMatcher},
parse_pattern_syntax, status,
utils::{
files::{get_bytes_from_path, get_path_from_bytes},
hg_path::{HgPath, HgPathBuf},
},
BadMatch, DirstateStatus, IgnorePattern, PatternFileWarning, StatusError,
StatusOptions,
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 };
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 use std::borrow::{Borrow, Cow};
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567
/// This will be useless once trait impls for collection are added to `PyBytes`
/// upstream.
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 fn collect_pybytes_list(
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 py: Python,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 collection: &[impl AsRef<HgPath>],
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 ) -> PyList {
let list = PyList::new(py, &[]);
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 for path in collection.iter() {
list.append(
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 py,
PyBytes::new(py, path.as_ref().as_bytes()).into_object(),
)
}
list
}
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 fn collect_bad_matches(
py: Python,
collection: &[(impl AsRef<HgPath>, BadMatch)],
) -> PyResult<PyList> {
let list = PyList::new(py, &[]);
let os = py.import("os")?;
let get_error_message = |code: i32| -> PyResult<_> {
os.call(
py,
"strerror",
PyTuple::new(py, &[code.to_py_object(py).into_object()]),
None,
)
};
for (path, bad_match) in collection.iter() {
let message = match bad_match {
BadMatch::OsError(code) => get_error_message(*code)?,
BadMatch::BadType(bad_type) => format!(
"unsupported file type (type is {})",
bad_type.to_string()
)
.to_py_object(py)
.into_object(),
};
list.append(
py,
(PyBytes::new(py, path.as_ref().as_bytes()), message)
.to_py_object(py)
.into_object(),
)
}
Ok(list)
}
fn handle_fallback(py: Python, err: StatusError) -> PyErr {
match err {
StatusError::Pattern(e) => {
Raphaël Gomès
rust-status: add trace-level logging for Rust status fallback for debugging...
r45062 let as_string = e.to_string();
log::trace!("Rust status fallback: `{}`", &as_string);
PyErr::new::<FallbackError, _>(py, &as_string)
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 }
e => PyErr::new::<ValueError, _>(py, e.to_string()),
}
}
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 pub fn status_wrapper(
py: Python,
dmap: DirstateMap,
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 matcher: PyObject,
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 root_dir: PyObject,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 ignore_files: PyList,
check_exec: bool,
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 last_normal_time: i64,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 list_clean: bool,
list_ignored: bool,
list_unknown: bool,
) -> PyResult<PyTuple> {
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 let bytes = root_dir.extract::<PyBytes>(py)?;
let root_dir = get_path_from_bytes(bytes.data(py));
let dmap: DirstateMap = dmap.to_py_object(py);
let dmap = dmap.get_inner(py);
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 let ignore_files: PyResult<Vec<_>> = ignore_files
.iter(py)
.map(|b| {
let file = b.extract::<PyBytes>(py)?;
Ok(get_path_from_bytes(file.data(py)).to_owned())
})
.collect();
let ignore_files = ignore_files?;
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 match matcher.get_type(py).name(py).borrow() {
"alwaysmatcher" => {
let matcher = AlwaysMatcher;
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 let ((lookup, status_res), warnings) = status(
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 &dmap,
&matcher,
&root_dir,
Raphaël Gomès
rust-status: only involve ignore mechanism when needed...
r45088 ignore_files,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 StatusOptions {
check_exec,
last_normal_time,
list_clean,
list_ignored,
list_unknown,
},
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 )
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 .map_err(|e| handle_fallback(py, e))?;
build_response(py, lookup, status_res, warnings)
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 }
"exactmatcher" => {
let files = matcher.call_method(
py,
"files",
PyTuple::new(py, &[]),
None,
)?;
let files: PyList = files.cast_into(py)?;
let files: PyResult<Vec<HgPathBuf>> = files
.iter(py)
.map(|f| {
Ok(HgPathBuf::from_bytes(
f.extract::<PyBytes>(py)?.data(py),
))
})
.collect();
Raphaël Gomès
rust-dirstate-status: add `walk_explicit` implementation, use `Matcher` trait...
r44367
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 let files = files?;
let matcher = FileMatcher::new(&files)
.map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?;
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 let ((lookup, status_res), warnings) = status(
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 &dmap,
&matcher,
&root_dir,
Raphaël Gomès
rust-status: only involve ignore mechanism when needed...
r45088 ignore_files,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 StatusOptions {
check_exec,
last_normal_time,
list_clean,
list_ignored,
list_unknown,
},
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 )
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 .map_err(|e| handle_fallback(py, e))?;
build_response(py, lookup, status_res, warnings)
}
"includematcher" => {
// Get the patterns from Python even though most of them are
// redundant with those we will parse later on, as they include
// those passed from the command line.
let ignore_patterns: PyResult<Vec<_>> = matcher
.getattr(py, "_kindpats")?
.iter(py)?
.map(|k| {
let k = k?;
let syntax = parse_pattern_syntax(
&[
k.get_item(py, 0)?
.extract::<PyBytes>(py)?
.data(py),
&b":"[..],
]
.concat(),
)
.map_err(|e| {
handle_fallback(py, StatusError::Pattern(e))
})?;
let pattern = k.get_item(py, 1)?.extract::<PyBytes>(py)?;
let pattern = pattern.data(py);
let source = k.get_item(py, 2)?.extract::<PyBytes>(py)?;
let source = get_path_from_bytes(source.data(py));
let new = IgnorePattern::new(syntax, pattern, source);
Ok(new)
})
.collect();
let ignore_patterns = ignore_patterns?;
let mut all_warnings = vec![];
let (matcher, warnings) =
IncludeMatcher::new(ignore_patterns, &root_dir)
.map_err(|e| handle_fallback(py, e.into()))?;
all_warnings.extend(warnings);
let ((lookup, status_res), warnings) = status(
&dmap,
&matcher,
&root_dir,
Raphaël Gomès
rust-status: only involve ignore mechanism when needed...
r45088 ignore_files,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 StatusOptions {
check_exec,
last_normal_time,
list_clean,
list_ignored,
list_unknown,
},
)
.map_err(|e| handle_fallback(py, e))?;
all_warnings.extend(warnings);
build_response(py, lookup, status_res, all_warnings)
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 }
e => {
return Err(PyErr::new::<ValueError, _>(
py,
format!("Unsupported matcher {}", e),
));
}
}
}
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 fn build_response(
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 py: Python,
lookup: Vec<Cow<HgPath>>,
Raphaël Gomès
rust-status: rename `StatusResult` to `DirstateStatus`...
r45012 status_res: DirstateStatus,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 warnings: Vec<PatternFileWarning>,
) -> PyResult<PyTuple> {
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 let modified = collect_pybytes_list(py, status_res.modified.as_ref());
let added = collect_pybytes_list(py, status_res.added.as_ref());
let removed = collect_pybytes_list(py, status_res.removed.as_ref());
let deleted = collect_pybytes_list(py, status_res.deleted.as_ref());
let clean = collect_pybytes_list(py, status_res.clean.as_ref());
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 let ignored = collect_pybytes_list(py, status_res.ignored.as_ref());
let unknown = collect_pybytes_list(py, status_res.unknown.as_ref());
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 let lookup = collect_pybytes_list(py, lookup.as_ref());
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 let bad = collect_bad_matches(py, status_res.bad.as_ref())?;
let py_warnings = PyList::new(py, &[]);
for warning in warnings.iter() {
// We use duck-typing on the Python side for dispatch, good enough for
// now.
match warning {
PatternFileWarning::InvalidSyntax(file, syn) => {
py_warnings.append(
py,
(
PyBytes::new(py, &get_bytes_from_path(&file)),
PyBytes::new(py, syn),
)
.to_py_object(py)
.into_object(),
);
}
PatternFileWarning::NoSuchFile(file) => py_warnings.append(
py,
PyBytes::new(py, &get_bytes_from_path(&file)).into_object(),
),
}
}
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 Ok(PyTuple::new(
py,
&[
lookup.into_object(),
modified.into_object(),
added.into_object(),
removed.into_object(),
deleted.into_object(),
clean.into_object(),
ignored.into_object(),
unknown.into_object(),
py_warnings.into_object(),
bad.into_object(),
][..],
))
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 }