##// END OF EJS Templates
sharesafe: introduce functionality to automatically upgrade shares...
sharesafe: introduce functionality to automatically upgrade shares In past few months, we have developed a `share-safe` mode for sharing repository in which share source requirements and config values are shared with the shares. To get it rolling, an important task is to get these shares automatically upgraded. We are focusing on an installation where shares are created by scripts and test jobs. It will be difficult to manually upgrade these and we need some functionality to do so automatically. This patch introduces a config option to deal with it. If all of the following conditions are met, we upgrade the share repository automatically: * If the config option is enabled * Share source repository is share-safe enabled * Share is not share-safe enabled * Any command is run in the share Upgrading the share is pretty easy as it involves only editing the requirements file. Differential Revision: https://phab.mercurial-scm.org/D9679

File last commit:

r46465:c9c3c277 default
r46852:0babe12e default
Show More
status.rs
303 lines | 9.8 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-status: properly translate OSError to Python...
r46465 use cpython::exc::OSError;
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 }
Raphaël Gomès
rust-status: properly translate OSError to Python...
r46465 StatusError::IO(e) => PyErr::new::<OSError, _>(py, e.to_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,
Raphaël Gomès
rust-hg-cpython: update status bridge with the new `traversedir` support...
r45354 collect_traversed_dirs: bool,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 ) -> 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,
Raphaël Gomès
rust-status: refactor status into a struct...
r45671 root_dir.to_path_buf(),
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-hg-cpython: update status bridge with the new `traversedir` support...
r45354 collect_traversed_dirs,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 },
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?;
Raphaël Gomès
rust: start plugging the dirstate tree behind a feature gate...
r46185 let matcher = FileMatcher::new(files.as_ref())
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 .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,
Raphaël Gomès
rust-status: refactor status into a struct...
r45671 root_dir.to_path_buf(),
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-hg-cpython: update status bridge with the new `traversedir` support...
r45354 collect_traversed_dirs,
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 },
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,
Raphaël Gomès
rust-status: refactor status into a struct...
r45671 root_dir.to_path_buf(),
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-hg-cpython: update status bridge with the new `traversedir` support...
r45354 collect_traversed_dirs,
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))?;
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 }
Raphaël Gomès
rust: do a clippy pass...
r45500 e => Err(PyErr::new::<ValueError, _>(
py,
format!("Unsupported matcher {}", e),
)),
Raphaël Gomès
rust-dirstate-status: update bridge for new rust version of `dirstate.status`...
r44368 }
}
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())?;
Raphaël Gomès
rust-hg-cpython: update status bridge with the new `traversedir` support...
r45354 let traversed = collect_pybytes_list(py, status_res.traversed.as_ref());
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 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-hg-cpython: update status bridge with the new `traversedir` support...
r45354 traversed.into_object(),
Raphaël Gomès
rust-status: update rust-cpython bridge to account for the changes in core...
r45016 ][..],
))
Raphaël Gomès
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
r43567 }