##// END OF EJS Templates
fix: allow tools to use :linerange, but also run if a file is unchanged...
fix: allow tools to use :linerange, but also run if a file is unchanged The definition of "unchanged" here is subtle, because pure deletion diff hunks are ignored. That means this is different from using the --whole flag. This change allows you to configure, for example, a code formatter that: 1. Formats specific line ranges if specified via flags 2. Does not format the entire file when there are no line ranges provided 3. Performs some other kind of formatting regardless of provided line ranges This sounds a little far fetched, but it is meant to address a specific corner case encountered in Google's use of the fix extension. The default behavior is kept because it exists to prevent mistakes that could erase uncommitted changes. Differential Revision: https://phab.mercurial-scm.org/D6723

File last commit:

r42997:30320c7b default
r43001:ed0da6e0 default
Show More
dirs_multiset.rs
130 lines | 3.9 KiB | application/rls-services+xml | RustLexer
// dirs_multiset.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::dirstate::dirs_multiset` file provided by the
//! `hg-core` package.
use std::cell::RefCell;
use std::convert::TryInto;
use cpython::{
exc, ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyObject, PyResult,
Python,
};
use crate::{dirstate::extract_dirstate, ref_sharing::PySharedState};
use hg::{
DirsIterable, DirsMultiset, DirstateMapError, DirstateParseError,
EntryState,
};
py_class!(pub class Dirs |py| {
data inner: RefCell<DirsMultiset>;
data py_shared_state: PySharedState;
// `map` is either a `dict` or a flat iterator (usually a `set`, sometimes
// a `list`)
def __new__(
_cls,
map: PyObject,
skip: Option<PyObject> = None
) -> PyResult<Self> {
let mut skip_state: Option<EntryState> = None;
if let Some(skip) = skip {
skip_state = Some(
skip.extract::<PyBytes>(py)?.data(py)[0]
.try_into()
.map_err(|e: DirstateParseError| {
PyErr::new::<exc::ValueError, _>(py, e.to_string())
})?,
);
}
let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
let dirstate = extract_dirstate(py, &map)?;
DirsMultiset::new(
DirsIterable::Dirstate(&dirstate),
skip_state,
)
} else {
let map: Result<Vec<Vec<u8>>, PyErr> = map
.iter(py)?
.map(|o| Ok(o?.extract::<PyBytes>(py)?.data(py).to_owned()))
.collect();
DirsMultiset::new(
DirsIterable::Manifest(&map?),
skip_state,
)
};
Self::create_instance(
py,
RefCell::new(inner),
PySharedState::default()
)
}
def addpath(&self, path: PyObject) -> PyResult<PyObject> {
self.borrow_mut(py)?.add_path(
path.extract::<PyBytes>(py)?.data(py),
);
Ok(py.None())
}
def delpath(&self, path: PyObject) -> PyResult<PyObject> {
self.borrow_mut(py)?.delete_path(
path.extract::<PyBytes>(py)?.data(py),
)
.and(Ok(py.None()))
.or_else(|e| {
match e {
DirstateMapError::PathNotFound(_p) => {
Err(PyErr::new::<exc::ValueError, _>(
py,
"expected a value, found none".to_string(),
))
}
DirstateMapError::EmptyPath => {
Ok(py.None())
}
}
})
}
def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> {
DirsMultisetKeysIterator::create_instance(
py,
RefCell::new(Some(DirsMultisetLeakedRef::new(py, &self))),
RefCell::new(Box::new(self.leak_immutable(py)?.iter())),
)
}
def __contains__(&self, item: PyObject) -> PyResult<bool> {
Ok(self
.inner(py)
.borrow()
.contains(item.extract::<PyBytes>(py)?.data(py).as_ref()))
}
});
py_shared_ref!(Dirs, DirsMultiset, inner, DirsMultisetLeakedRef,);
impl Dirs {
pub fn from_inner(py: Python, d: DirsMultiset) -> PyResult<Self> {
Self::create_instance(py, RefCell::new(d), PySharedState::default())
}
fn translate_key(py: Python, res: &Vec<u8>) -> PyResult<Option<PyBytes>> {
Ok(Some(PyBytes::new(py, res)))
}
}
py_shared_sequence_iterator!(
DirsMultisetKeysIterator,
DirsMultisetLeakedRef,
Vec<u8>,
Dirs::translate_key,
Option<PyBytes>
);