##// END OF EJS Templates
rust-index: using the `hg::index::Index` in ancestors iterator and lazy set...
rust-index: using the `hg::index::Index` in ancestors iterator and lazy set Since there is no Rust implementation for REVLOGV2/CHANGELOGv2, we declare them to be incompatible with Rust, hence indexes in these formats will use the implementations from Python `mercurial.ancestor`. If this is an unacceptable performance hit for current users of these formats, we can later on add Rust implementations based on the C index for them or implement these formats for the Rust indexes. Among the challenges that we had to meet, we wanted to avoid taking the GIL each time the inner (vcsgraph) iterator has to call the parents function. This would probably still be acceptable in terms of performance with `AncestorsIterator`, but not with `LazyAncestors` nor for the upcoming change in `MissingAncestors`. Hence we enclose the reference to the index in a `PySharedRef`, leading to more rigourous checking of mutations, which does pass now that there no logically immutable methods of `hg::index::Index` that take a mutable reference as input.

File last commit:

r51659:58aa5ee9 default
r52132:7eea2e41 default
Show More
blackbox.rs
177 lines | 5.5 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 //! Logging for repository events, including commands run in the repository.
use crate::CliInvocation;
use format_bytes::format_bytes;
use hg::errors::HgError;
use hg::repo::Repo;
use hg::utils::{files::get_bytes_from_os_str, shell_quote};
Arseniy Alekseyev
rhg: refactor to pass argv down, instead of caling args_os()...
r49961 use std::ffi::OsString;
Simon Sapin
rhg: Add support for the blackbox extension...
r47343
// Python does not support %.3f, only %f
Valentin Gatien-Baron
blackbox: change year in logs to ISO 8601 format...
r49421 const DEFAULT_DATE_FORMAT: &str = "%Y-%m-%d %H:%M:%S%.3f";
Simon Sapin
rhg: Add support for the blackbox extension...
r47343
type DateTime = chrono::DateTime<chrono::Local>;
pub struct ProcessStartTime {
/// For measuring duration
monotonic_clock: std::time::Instant,
/// For formatting with year, month, day, etc.
calendar_based: DateTime,
}
impl ProcessStartTime {
pub fn now() -> Self {
Self {
monotonic_clock: std::time::Instant::now(),
calendar_based: chrono::Local::now(),
}
}
}
pub struct Blackbox<'a> {
process_start_time: &'a ProcessStartTime,
/// Do nothing if this is `None`
configured: Option<ConfiguredBlackbox<'a>>,
}
struct ConfiguredBlackbox<'a> {
repo: &'a Repo,
max_size: u64,
max_files: u32,
date_format: &'a str,
}
impl<'a> Blackbox<'a> {
pub fn new(
invocation: &'a CliInvocation<'a>,
process_start_time: &'a ProcessStartTime,
) -> Result<Self, HgError> {
let configured = if let Ok(repo) = invocation.repo {
Raphaël Gomès
rust-blackbox: use `is_extension_enabled` config helper...
r51659 if !invocation.config.is_extension_enabled(b"blackbox") {
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 None
} else {
Some(ConfiguredBlackbox {
repo,
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 max_size: invocation
.config
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 .get_byte_size(b"blackbox", b"maxsize")?
Raphaël Gomès
configitems: move blackbox's config items to the new configitems.toml...
r51658 .expect(
"blackbox.maxsize should have a default value",
),
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 max_files: invocation
.config
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 .get_u32(b"blackbox", b"maxfiles")?
Raphaël Gomès
configitems: move blackbox's config items to the new configitems.toml...
r51658 .expect(
"blackbox.maxfiles should have a default value",
),
Simon Sapin
rhg: Make configuration available as early as possible in main()...
r47423 date_format: invocation
.config
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 .get_str(b"blackbox", b"date-format")?
Raphaël Gomès
configitems: move blackbox's config items to the new configitems.toml...
r51658 .map(|f| {
if f.is_empty() {
DEFAULT_DATE_FORMAT
} else {
f
}
})
.expect(
"blackbox.date-format should have a default value",
),
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 })
}
} else {
// Without a local repository there’s no `.hg/blackbox.log` to
// write to.
None
};
Ok(Self {
process_start_time,
configured,
})
}
Arseniy Alekseyev
rhg: refactor to pass argv down, instead of caling args_os()...
r49961 pub fn log_command_start<'arg>(
&self,
argv: impl Iterator<Item = &'arg OsString>,
) {
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 if let Some(configured) = &self.configured {
Arseniy Alekseyev
rhg: refactor to pass argv down, instead of caling args_os()...
r49961 let message = format_bytes!(b"(rust) {}", format_cli_args(argv));
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 configured.log(&self.process_start_time.calendar_based, &message);
}
}
Arseniy Alekseyev
rhg: refactor to pass argv down, instead of caling args_os()...
r49961 pub fn log_command_end<'arg>(
&self,
argv: impl Iterator<Item = &'arg OsString>,
exit_code: i32,
) {
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 if let Some(configured) = &self.configured {
let now = chrono::Local::now();
let duration = self
.process_start_time
.monotonic_clock
.elapsed()
.as_secs_f64();
let message = format_bytes!(
b"(rust) {} exited {} after {} seconds",
Arseniy Alekseyev
rhg: refactor to pass argv down, instead of caling args_os()...
r49961 format_cli_args(argv),
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 exit_code,
format_bytes::Utf8(format_args!("{:.03}", duration))
);
configured.log(&now, &message);
}
}
}
impl ConfiguredBlackbox<'_> {
fn log(&self, date_time: &DateTime, message: &[u8]) {
let date = format_bytes::Utf8(date_time.format(self.date_format));
Raphaël Gomès
rust-dependencies: switch from `users` to `whoami`...
r51576 let user = get_bytes_from_os_str(whoami::username_os());
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 let rev = format_bytes::Utf8(match self.repo.dirstate_parents() {
Ok(parents) if parents.p2 == hg::revlog::node::NULL_NODE => {
format!("{:x}", parents.p1)
}
Ok(parents) => format!("{:x}+{:x}", parents.p1, parents.p2),
Err(_dirstate_corruption_error) => {
// TODO: log a non-fatal warning to stderr
"???".to_owned()
}
});
let pid = std::process::id();
let line = format_bytes!(
b"{} {} @{} ({})> {}\n",
date,
user,
rev,
pid,
message
);
let result =
hg::logging::LogFile::new(self.repo.hg_vfs(), "blackbox.log")
.max_size(Some(self.max_size))
.max_files(self.max_files)
.write(&line);
match result {
Ok(()) => {}
Err(_io_error) => {
// TODO: log a non-fatal warning to stderr
}
}
}
}
Arseniy Alekseyev
rhg: refactor to pass argv down, instead of caling args_os()...
r49961 fn format_cli_args<'a>(
mut args: impl Iterator<Item = &'a OsString>,
) -> Vec<u8> {
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 let _ = args.next(); // Skip the first (or zeroth) arg, the name of the `rhg` executable
let mut args = args.map(|arg| shell_quote(&get_bytes_from_os_str(arg)));
let mut formatted = Vec::new();
if let Some(arg) = args.next() {
formatted.extend(arg)
}
for arg in args {
formatted.push(b' ');
formatted.extend(arg)
}
formatted
}