Merge pull request #22 from DeterminateSystems/tristanross/dsp-204
Build / Build (map[runner:UbuntuLatest32Cores128GArm system:aarch64-linux]) (push) Has been cancelled
Build / Build (map[runner:namespace-profile-linuxamd32c64g-cache system:x86_64-linux]) (push) Has been cancelled
Build / Build (map[runner:namespace-profile-mac-m2-12c28g system:aarch64-darwin]) (push) Has been cancelled
Build / success (push) Has been cancelled
Build / Build (map[runner:UbuntuLatest32Cores128GArm system:aarch64-linux]) (push) Has been cancelled
Build / Build (map[runner:namespace-profile-linuxamd32c64g-cache system:x86_64-linux]) (push) Has been cancelled
Build / Build (map[runner:namespace-profile-mac-m2-12c28g system:aarch64-darwin]) (push) Has been cancelled
Build / success (push) Has been cancelled
Add logger bindings, fix bindgen-gcc.sh
This commit is contained in:
+3
-5
@@ -7,12 +7,10 @@ echo "Extending BINDGEN_EXTRA_CLANG_ARGS with system include paths..." 2>&1
|
||||
BINDGEN_EXTRA_CLANG_ARGS="${BINDGEN_EXTRA_CLANG_ARGS:-}"
|
||||
export BINDGEN_EXTRA_CLANG_ARGS
|
||||
include_paths=$(
|
||||
echo | $NIX_CC_UNWRAPPED -v -E -x c - 2>&1 \
|
||||
LC_ALL=C $NIX_CC_UNWRAPPED -v -E -x c - </dev/null 2>&1 \
|
||||
| awk '/#include <...> search starts here:/{flag=1;next} \
|
||||
/End of search list./{flag=0} \
|
||||
flag==1 {print $1}'
|
||||
)
|
||||
for path in $include_paths; do
|
||||
echo " - $path" 2>&1
|
||||
BINDGEN_EXTRA_CLANG_ARGS="$BINDGEN_EXTRA_CLANG_ARGS -I$path"
|
||||
done
|
||||
include_args=$(printf '%s\n' "$include_paths" | awk 'NF {printf " -I%s", $1; printf " - %s\n", $1 > "/dev/stderr"}')
|
||||
BINDGEN_EXTRA_CLANG_ARGS="$BINDGEN_EXTRA_CLANG_ARGS$include_args"
|
||||
|
||||
Generated
+21
-21
@@ -77,11 +77,11 @@
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1775087534,
|
||||
"narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
|
||||
"lastModified": 1777988971,
|
||||
"narHash": "sha256-qIoWPDs+0/8JecyYgE3gpKQxW/4bLW/gp45vow9ioCQ=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
|
||||
"rev": "0678d8986be1661af6bb555f3489f2fdfc31f6ff",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -159,11 +159,11 @@
|
||||
"nixpkgs-regression": "nixpkgs-regression"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777402229,
|
||||
"narHash": "sha256-h6WzecM2+aBt0rrcvG5+8d11q+nZoDm60na/48NcJ6w=",
|
||||
"lastModified": 1778096718,
|
||||
"narHash": "sha256-RnGxdnwhrEpLIqkRnXeb9caVLsKOboOMjMifEz+RaOk=",
|
||||
"owner": "DeterminateSystems",
|
||||
"repo": "nix-src",
|
||||
"rev": "5ab3bee6fa77196de319a0b7669def091fc82253",
|
||||
"rev": "8fb8ad7b69f5715c66720106c8b3a6dd8d0a51d8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -185,11 +185,11 @@
|
||||
"treefmt": "treefmt"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777363774,
|
||||
"narHash": "sha256-huAKxsrlMBzo1YxuKWwndoGv4K7FTfZ7azZeWtw7iNA=",
|
||||
"lastModified": 1778141945,
|
||||
"narHash": "sha256-unLKBy8SaNxEXaqMmXDUZyZIzf3K1H46azxFJDMq1jU=",
|
||||
"owner": "90-008",
|
||||
"repo": "nix-cargo-integration",
|
||||
"rev": "fa3881a64ad9a04f1434494fc46cbf48dd9bef11",
|
||||
"rev": "aceca529e10a880594b11c31a0e98d70d4a9c975",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -230,11 +230,11 @@
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1774748309,
|
||||
"narHash": "sha256-+U7gF3qxzwD5TZuANzZPeJTZRHS29OFQgkQ2kiTJBIQ=",
|
||||
"lastModified": 1777168982,
|
||||
"narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "333c4e0545a6da976206c74db8773a1645b5870a",
|
||||
"rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -261,11 +261,11 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1777268161,
|
||||
"narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=",
|
||||
"lastModified": 1777954456,
|
||||
"narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76",
|
||||
"rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -283,11 +283,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1775087534,
|
||||
"narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
|
||||
"lastModified": 1777988971,
|
||||
"narHash": "sha256-qIoWPDs+0/8JecyYgE3gpKQxW/4bLW/gp45vow9ioCQ=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
|
||||
"rev": "0678d8986be1661af6bb555f3489f2fdfc31f6ff",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -358,11 +358,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1777346187,
|
||||
"narHash": "sha256-oVxyGjpiIsrXhWTJVUOs38fZQkLjd0nZGOY9K7Kfot8=",
|
||||
"lastModified": 1778123869,
|
||||
"narHash": "sha256-hV9D8ET33kXjdoMXBT2bwM/j8WQM1SP/dVKZtjQKhAQ=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "146e7bf7569b8288f24d41d806b9f584f7cfd5b5",
|
||||
"rev": "592e5dedf04f0eaff1ed0f01ce5db7407d9fc7be",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -6,6 +6,7 @@ use std::{ffi::NulError, str::Utf8Error, string::FromUtf8Error};
|
||||
use thiserror::Error;
|
||||
|
||||
pub mod context;
|
||||
pub mod logger;
|
||||
pub mod settings;
|
||||
#[macro_use]
|
||||
pub mod string_return;
|
||||
|
||||
@@ -0,0 +1,382 @@
|
||||
//! Custom Nix logger.
|
||||
//!
|
||||
//! Replace Nix's global logger with a Rust callback-based one that
|
||||
//! receives log messages, activities, and string-valued results from
|
||||
//! anywhere in libnixutil, libnixstore, and libnixexpr.
|
||||
//!
|
||||
//! See the [`Logger`] trait and [`set_logger`].
|
||||
|
||||
use crate::raw_sys as raw;
|
||||
use crate::{check_call, context, Result};
|
||||
use std::ffi::{c_char, c_void, CStr};
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// Verbosity level of a log message.
|
||||
///
|
||||
/// Mirrors the C `nix_verbosity` enum.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
pub enum Verbosity {
|
||||
Error,
|
||||
Warn,
|
||||
Notice,
|
||||
Info,
|
||||
Talkative,
|
||||
Chatty,
|
||||
Debug,
|
||||
Vomit,
|
||||
/// A verbosity level not (yet) modelled by this crate.
|
||||
Unknown(u32),
|
||||
}
|
||||
|
||||
impl Verbosity {
|
||||
fn from_raw(v: raw::verbosity) -> Self {
|
||||
match v {
|
||||
raw::verbosity_NIX_LVL_ERROR => Verbosity::Error,
|
||||
raw::verbosity_NIX_LVL_WARN => Verbosity::Warn,
|
||||
raw::verbosity_NIX_LVL_NOTICE => Verbosity::Notice,
|
||||
raw::verbosity_NIX_LVL_INFO => Verbosity::Info,
|
||||
raw::verbosity_NIX_LVL_TALKATIVE => Verbosity::Talkative,
|
||||
raw::verbosity_NIX_LVL_CHATTY => Verbosity::Chatty,
|
||||
raw::verbosity_NIX_LVL_DEBUG => Verbosity::Debug,
|
||||
raw::verbosity_NIX_LVL_VOMIT => Verbosity::Vomit,
|
||||
other => Verbosity::Unknown(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Identifier for a logger activity. `0` is the implicit root.
|
||||
pub type ActivityId = u64;
|
||||
|
||||
/// Type of an activity.
|
||||
///
|
||||
/// Mirrors the C `nix_activity_type` enum.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
pub enum ActivityType {
|
||||
Unknown,
|
||||
CopyPath,
|
||||
FileTransfer,
|
||||
Realise,
|
||||
CopyPaths,
|
||||
Builds,
|
||||
Build,
|
||||
OptimiseStore,
|
||||
VerifyPaths,
|
||||
Substitute,
|
||||
QueryPathInfo,
|
||||
PostBuildHook,
|
||||
BuildWaiting,
|
||||
FetchTree,
|
||||
/// An activity type not (yet) modelled by this crate.
|
||||
Other(u32),
|
||||
}
|
||||
|
||||
impl ActivityType {
|
||||
fn from_raw(t: raw::activity_type) -> Self {
|
||||
match t {
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_UNKNOWN => ActivityType::Unknown,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_COPY_PATH => ActivityType::CopyPath,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_FILE_TRANSFER => ActivityType::FileTransfer,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_REALISE => ActivityType::Realise,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_COPY_PATHS => ActivityType::CopyPaths,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_BUILDS => ActivityType::Builds,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_BUILD => ActivityType::Build,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_OPTIMISE_STORE => ActivityType::OptimiseStore,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_VERIFY_PATHS => ActivityType::VerifyPaths,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_SUBSTITUTE => ActivityType::Substitute,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_QUERY_PATH_INFO => ActivityType::QueryPathInfo,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_POST_BUILD_HOOK => ActivityType::PostBuildHook,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_BUILD_WAITING => ActivityType::BuildWaiting,
|
||||
raw::activity_type_NIX_ACTIVITY_TYPE_FETCH_TREE => ActivityType::FetchTree,
|
||||
other => ActivityType::Other(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of a result reported by an activity.
|
||||
///
|
||||
/// Only string-valued result types are delivered to
|
||||
/// [`Logger::result_string`]; other variants exist for forward
|
||||
/// compatibility.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
pub enum ResultType {
|
||||
FileLinked,
|
||||
BuildLogLine,
|
||||
UntrustedPath,
|
||||
CorruptedPath,
|
||||
SetPhase,
|
||||
Progress,
|
||||
SetExpected,
|
||||
PostBuildLogLine,
|
||||
FetchStatus,
|
||||
HashMismatch,
|
||||
BuildResult,
|
||||
/// A result type not (yet) modelled by this crate.
|
||||
Other(u32),
|
||||
}
|
||||
|
||||
impl ResultType {
|
||||
fn from_raw(t: raw::result_type) -> Self {
|
||||
match t {
|
||||
raw::result_type_NIX_RESULT_TYPE_FILE_LINKED => ResultType::FileLinked,
|
||||
raw::result_type_NIX_RESULT_TYPE_BUILD_LOG_LINE => ResultType::BuildLogLine,
|
||||
raw::result_type_NIX_RESULT_TYPE_UNTRUSTED_PATH => ResultType::UntrustedPath,
|
||||
raw::result_type_NIX_RESULT_TYPE_CORRUPTED_PATH => ResultType::CorruptedPath,
|
||||
raw::result_type_NIX_RESULT_TYPE_SET_PHASE => ResultType::SetPhase,
|
||||
raw::result_type_NIX_RESULT_TYPE_PROGRESS => ResultType::Progress,
|
||||
raw::result_type_NIX_RESULT_TYPE_SET_EXPECTED => ResultType::SetExpected,
|
||||
raw::result_type_NIX_RESULT_TYPE_POST_BUILD_LOG_LINE => ResultType::PostBuildLogLine,
|
||||
raw::result_type_NIX_RESULT_TYPE_FETCH_STATUS => ResultType::FetchStatus,
|
||||
raw::result_type_NIX_RESULT_TYPE_HASH_MISMATCH => ResultType::HashMismatch,
|
||||
raw::result_type_NIX_RESULT_TYPE_BUILD_RESULT => ResultType::BuildResult,
|
||||
other => ResultType::Other(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A logger that receives messages from Nix.
|
||||
///
|
||||
/// Implementations must be [`Send`] and [`Sync`] because Nix may
|
||||
/// invoke the callbacks from arbitrary threads (e.g. during parallel
|
||||
/// builds).
|
||||
///
|
||||
/// All methods have empty default implementations, so an
|
||||
/// implementation only needs to override the events it cares about.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Callback methods must not unwind across the FFI boundary.
|
||||
/// Panics from any of these methods are caught and silently
|
||||
/// discarded; if your implementation may panic, prefer to handle
|
||||
/// it yourself.
|
||||
pub trait Logger: Send + Sync {
|
||||
/// An ordinary log message.
|
||||
///
|
||||
/// Receives `builtins.trace` output, formatted warnings/errors,
|
||||
/// and messages produced through the C++ `printError` /
|
||||
/// `printInfo` / `debug` macros.
|
||||
///
|
||||
/// `msg` is decoded with [`String::from_utf8_lossy`] to keep the
|
||||
/// signature ergonomic.
|
||||
fn log(&self, _level: Verbosity, _msg: &str) {}
|
||||
|
||||
/// An activity (build, substitution, ...) has started.
|
||||
///
|
||||
/// `parent_id` is `0` for top-level activities.
|
||||
fn start_activity(
|
||||
&self,
|
||||
_activity_id: ActivityId,
|
||||
_level: Verbosity,
|
||||
_type_: ActivityType,
|
||||
_description: &str,
|
||||
_parent_id: ActivityId,
|
||||
) {
|
||||
}
|
||||
|
||||
/// An activity has stopped.
|
||||
fn stop_activity(&self, _activity_id: ActivityId) {}
|
||||
|
||||
/// An activity reported a string-valued result.
|
||||
///
|
||||
/// Result types that carry non-string fields (such as
|
||||
/// [`ResultType::Progress`]) are not delivered through this
|
||||
/// method.
|
||||
fn result_string(&self, _activity_id: ActivityId, _type_: ResultType, _msg: &str) {}
|
||||
}
|
||||
|
||||
/// Erased trait object passed across the FFI boundary as `userdata`.
|
||||
type LoggerObj = Box<dyn Logger + Send + Sync>;
|
||||
|
||||
/// Serializes calls to [`set_logger`] from the Rust side.
|
||||
///
|
||||
/// Note this does *not* protect against C++ code (or other clients of
|
||||
/// the C API) replacing the global logger concurrently — it only
|
||||
/// avoids racing with ourselves.
|
||||
static SET_LOGGER_MUTEX: Mutex<()> = Mutex::new(());
|
||||
|
||||
unsafe extern "C" fn thunk_log(userdata: *mut c_void, level: raw::verbosity, msg: *const c_char) {
|
||||
assert!(!userdata.is_null());
|
||||
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||
let logger = &*(userdata as *const LoggerObj);
|
||||
let msg_str = if msg.is_null() {
|
||||
std::borrow::Cow::Borrowed("")
|
||||
} else {
|
||||
CStr::from_ptr(msg).to_string_lossy()
|
||||
};
|
||||
logger.log(Verbosity::from_raw(level), msg_str.as_ref());
|
||||
}));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn thunk_start_activity(
|
||||
userdata: *mut c_void,
|
||||
activity_id: raw::activity_id,
|
||||
level: raw::verbosity,
|
||||
type_: raw::activity_type,
|
||||
s: *const c_char,
|
||||
parent_id: raw::activity_id,
|
||||
) {
|
||||
assert!(!userdata.is_null());
|
||||
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||
let logger = &*(userdata as *const LoggerObj);
|
||||
let s_str = if s.is_null() {
|
||||
std::borrow::Cow::Borrowed("")
|
||||
} else {
|
||||
CStr::from_ptr(s).to_string_lossy()
|
||||
};
|
||||
logger.start_activity(
|
||||
activity_id,
|
||||
Verbosity::from_raw(level),
|
||||
ActivityType::from_raw(type_),
|
||||
s_str.as_ref(),
|
||||
parent_id,
|
||||
);
|
||||
}));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn thunk_stop_activity(userdata: *mut c_void, activity_id: raw::activity_id) {
|
||||
assert!(!userdata.is_null());
|
||||
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||
let logger = &*(userdata as *const LoggerObj);
|
||||
logger.stop_activity(activity_id);
|
||||
}));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn thunk_result_string(
|
||||
userdata: *mut c_void,
|
||||
activity_id: raw::activity_id,
|
||||
type_: raw::result_type,
|
||||
msg: *const c_char,
|
||||
) {
|
||||
assert!(!userdata.is_null());
|
||||
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||
let logger = &*(userdata as *const LoggerObj);
|
||||
let msg_str = if msg.is_null() {
|
||||
std::borrow::Cow::Borrowed("")
|
||||
} else {
|
||||
CStr::from_ptr(msg).to_string_lossy()
|
||||
};
|
||||
logger.result_string(activity_id, ResultType::from_raw(type_), msg_str.as_ref());
|
||||
}));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn thunk_destroy(userdata: *mut c_void) {
|
||||
if userdata.is_null() {
|
||||
return;
|
||||
}
|
||||
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||
drop(Box::from_raw(userdata as *mut LoggerObj));
|
||||
}));
|
||||
}
|
||||
|
||||
static VTABLE: raw::logger = raw::logger {
|
||||
log: Some(thunk_log),
|
||||
start_activity: Some(thunk_start_activity),
|
||||
stop_activity: Some(thunk_stop_activity),
|
||||
result_string: Some(thunk_result_string),
|
||||
destroy: Some(thunk_destroy),
|
||||
};
|
||||
|
||||
/// Replace Nix's global logger with `logger`.
|
||||
///
|
||||
/// `logger` is moved into a heap allocation owned by Nix; it is
|
||||
/// dropped when this function is called again (replacing the logger)
|
||||
/// or at process shutdown.
|
||||
///
|
||||
/// # Thread safety
|
||||
///
|
||||
/// This function serializes concurrent Rust callers via an internal
|
||||
/// mutex. It does **not** protect against C++ code mutating
|
||||
/// `nix::logger` directly. Like [`crate::settings::set`], prefer to
|
||||
/// install a logger during single-threaded initialization.
|
||||
#[doc(alias = "nix_set_logger")]
|
||||
pub fn set_logger<L: Logger + 'static>(logger: L) -> Result<()> {
|
||||
let _guard = SET_LOGGER_MUTEX.lock().unwrap();
|
||||
|
||||
let boxed: Box<LoggerObj> = Box::new(Box::new(logger));
|
||||
let userdata = Box::into_raw(boxed) as *mut c_void;
|
||||
|
||||
let mut ctx = context::Context::new();
|
||||
let res = unsafe { check_call!(raw::set_logger(&mut ctx, &VTABLE, userdata)) };
|
||||
|
||||
if let Err(e) = res {
|
||||
// The C side did not accept the logger, so it will not invoke
|
||||
// the destroy callback. Reclaim the box ourselves to avoid
|
||||
// leaking the user-supplied logger.
|
||||
unsafe {
|
||||
drop(Box::from_raw(userdata as *mut LoggerObj));
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[ctor::ctor]
|
||||
fn setup() {
|
||||
crate::init().unwrap();
|
||||
}
|
||||
|
||||
/// Logger that records when it's dropped, so tests can observe the
|
||||
/// destroy callback firing on replacement.
|
||||
struct DropFlag {
|
||||
dropped: Arc<AtomicBool>,
|
||||
log_count: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl Logger for DropFlag {
|
||||
fn log(&self, _level: Verbosity, _msg: &str) {
|
||||
self.log_count.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DropFlag {
|
||||
fn drop(&mut self) {
|
||||
self.dropped.store(true, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_and_replace_calls_destroy() {
|
||||
let dropped = Arc::new(AtomicBool::new(false));
|
||||
let log_count = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
set_logger(DropFlag {
|
||||
dropped: dropped.clone(),
|
||||
log_count: log_count.clone(),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert!(!dropped.load(Ordering::SeqCst));
|
||||
|
||||
// Replace with a fresh logger; this should drop the previous one.
|
||||
set_logger(DropFlag {
|
||||
dropped: Arc::new(AtomicBool::new(false)),
|
||||
log_count: Arc::new(AtomicUsize::new(0)),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
dropped.load(Ordering::SeqCst),
|
||||
"previous logger should be dropped when the logger is replaced"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verbosity_round_trips_known_values() {
|
||||
assert_eq!(
|
||||
Verbosity::from_raw(raw::verbosity_NIX_LVL_ERROR),
|
||||
Verbosity::Error
|
||||
);
|
||||
assert_eq!(
|
||||
Verbosity::from_raw(raw::verbosity_NIX_LVL_VOMIT),
|
||||
Verbosity::Vomit
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user