mirror of
https://github.com/ostreedev/ostree.git
synced 2025-01-09 01:18:35 +03:00
lib: implement CheckoutOptions::filter (hackishly)
This commit is contained in:
parent
a521c838f5
commit
19fdf706d5
@ -24,6 +24,7 @@ generate = [
|
||||
"OSTree.MutableTree",
|
||||
"OSTree.ObjectType",
|
||||
"OSTree.Remote",
|
||||
"OSTree.RepoCheckoutFilterResult",
|
||||
"OSTree.RepoCheckoutMode",
|
||||
"OSTree.RepoCheckoutOverwriteMode",
|
||||
"OSTree.RepoCommitModifier",
|
||||
|
@ -242,6 +242,53 @@ impl FromGlib<ostree_sys::OstreeObjectType> for ObjectType {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v2018_2", feature = "dox"))]
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum RepoCheckoutFilterResult {
|
||||
Allow,
|
||||
Skip,
|
||||
#[doc(hidden)]
|
||||
__Unknown(i32),
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v2018_2", feature = "dox"))]
|
||||
impl fmt::Display for RepoCheckoutFilterResult {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "RepoCheckoutFilterResult::{}", match *self {
|
||||
RepoCheckoutFilterResult::Allow => "Allow",
|
||||
RepoCheckoutFilterResult::Skip => "Skip",
|
||||
_ => "Unknown",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v2018_2", feature = "dox"))]
|
||||
#[doc(hidden)]
|
||||
impl ToGlib for RepoCheckoutFilterResult {
|
||||
type GlibType = ostree_sys::OstreeRepoCheckoutFilterResult;
|
||||
|
||||
fn to_glib(&self) -> ostree_sys::OstreeRepoCheckoutFilterResult {
|
||||
match *self {
|
||||
RepoCheckoutFilterResult::Allow => ostree_sys::OSTREE_REPO_CHECKOUT_FILTER_ALLOW,
|
||||
RepoCheckoutFilterResult::Skip => ostree_sys::OSTREE_REPO_CHECKOUT_FILTER_SKIP,
|
||||
RepoCheckoutFilterResult::__Unknown(value) => value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "v2018_2", feature = "dox"))]
|
||||
#[doc(hidden)]
|
||||
impl FromGlib<ostree_sys::OstreeRepoCheckoutFilterResult> for RepoCheckoutFilterResult {
|
||||
fn from_glib(value: ostree_sys::OstreeRepoCheckoutFilterResult) -> Self {
|
||||
match value {
|
||||
0 => RepoCheckoutFilterResult::Allow,
|
||||
1 => RepoCheckoutFilterResult::Skip,
|
||||
value => RepoCheckoutFilterResult::__Unknown(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum RepoCheckoutMode {
|
||||
|
@ -71,6 +71,8 @@ pub use self::enums::DeploymentUnlockedState;
|
||||
pub use self::enums::GpgSignatureAttr;
|
||||
pub use self::enums::GpgSignatureFormatFlags;
|
||||
pub use self::enums::ObjectType;
|
||||
#[cfg(any(feature = "v2018_2", feature = "dox"))]
|
||||
pub use self::enums::RepoCheckoutFilterResult;
|
||||
pub use self::enums::RepoCheckoutMode;
|
||||
pub use self::enums::RepoCheckoutOverwriteMode;
|
||||
pub use self::enums::RepoMode;
|
||||
|
@ -34,11 +34,13 @@ pub use crate::auto::*;
|
||||
mod collection_ref;
|
||||
mod object_name;
|
||||
mod repo;
|
||||
#[cfg(any(feature = "v2018_2", feature = "dox"))]
|
||||
mod repo_checkout_at_options;
|
||||
#[cfg(any(feature = "v2018_6", feature = "dox"))]
|
||||
pub use crate::collection_ref::*;
|
||||
pub use crate::object_name::*;
|
||||
pub use crate::repo::*;
|
||||
#[cfg(any(feature = "v2018_2", feature = "dox"))]
|
||||
pub use crate::repo_checkout_at_options::*;
|
||||
|
||||
// tests
|
||||
|
@ -1,11 +1,15 @@
|
||||
use glib::translate::{Stash, ToGlib, ToGlibPtr};
|
||||
use glib::translate::{FromGlibPtrNone, Stash, ToGlib, ToGlibPtr};
|
||||
use glib_sys::gpointer;
|
||||
use libc::c_char;
|
||||
use ostree_sys::OstreeRepoCheckoutAtOptions;
|
||||
use std::path::PathBuf;
|
||||
use ostree_sys::{OstreeRepo, OstreeRepoCheckoutAtOptions, OstreeRepoCheckoutFilterResult};
|
||||
use std::path::{Path, PathBuf};
|
||||
use {Repo, RepoCheckoutFilterResult};
|
||||
use {RepoCheckoutMode, RepoCheckoutOverwriteMode};
|
||||
use {RepoDevInoCache, SePolicy};
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
|
||||
pub type RepoCheckoutFilter =
|
||||
Option<Box<dyn Fn(&Repo, &Path, &libc::stat) -> RepoCheckoutFilterResult>>;
|
||||
|
||||
pub struct RepoCheckoutAtOptions {
|
||||
pub mode: RepoCheckoutMode,
|
||||
pub overwrite_mode: RepoCheckoutOverwriteMode,
|
||||
@ -18,9 +22,8 @@ pub struct RepoCheckoutAtOptions {
|
||||
pub force_copy_zerosized: bool,
|
||||
pub subpath: Option<PathBuf>,
|
||||
pub devino_to_csum_cache: Option<RepoDevInoCache>,
|
||||
// TODO: those thingamajigs
|
||||
// pub filter: OstreeRepoCheckoutFilter,
|
||||
// pub filter_user_data: gpointer,
|
||||
// TODO: might be interesting to turn this into a type parameter
|
||||
pub filter: RepoCheckoutFilter,
|
||||
pub sepolicy: Option<SePolicy>,
|
||||
pub sepolicy_prefix: Option<String>,
|
||||
}
|
||||
@ -39,6 +42,7 @@ impl Default for RepoCheckoutAtOptions {
|
||||
force_copy_zerosized: false,
|
||||
subpath: None,
|
||||
devino_to_csum_cache: None,
|
||||
filter: None,
|
||||
sepolicy: None,
|
||||
sepolicy_prefix: None,
|
||||
}
|
||||
@ -47,6 +51,21 @@ impl Default for RepoCheckoutAtOptions {
|
||||
|
||||
type StringStash<'a, T> = Stash<'a, *const c_char, Option<T>>;
|
||||
|
||||
unsafe extern "C" fn filter_trampoline(
|
||||
repo: *mut OstreeRepo,
|
||||
path: *const c_char,
|
||||
stat: *mut libc::stat,
|
||||
user_data: gpointer,
|
||||
) -> OstreeRepoCheckoutFilterResult {
|
||||
// TODO: handle unwinding
|
||||
let closure =
|
||||
user_data as *const Box<dyn Fn(&Repo, &Path, &libc::stat) -> RepoCheckoutFilterResult>;
|
||||
let repo = FromGlibPtrNone::from_glib_none(repo);
|
||||
let path: PathBuf = FromGlibPtrNone::from_glib_none(path);
|
||||
let result = (*closure)(&repo, &path, &*stat);
|
||||
result.to_glib()
|
||||
}
|
||||
|
||||
impl<'a> ToGlibPtr<'a, *const OstreeRepoCheckoutAtOptions> for RepoCheckoutAtOptions {
|
||||
type Storage = (
|
||||
Box<OstreeRepoCheckoutAtOptions>,
|
||||
@ -75,6 +94,21 @@ impl<'a> ToGlibPtr<'a, *const OstreeRepoCheckoutAtOptions> for RepoCheckoutAtOpt
|
||||
let sepolicy = self.sepolicy.to_glib_none();
|
||||
options.sepolicy = sepolicy.0;
|
||||
|
||||
if let Some(filter) = &self.filter {
|
||||
options.filter_user_data = filter
|
||||
as *const Box<dyn Fn(&Repo, &Path, &libc::stat) -> RepoCheckoutFilterResult>
|
||||
as gpointer;
|
||||
options.filter = Some(
|
||||
filter_trampoline
|
||||
as unsafe extern "C" fn(
|
||||
*mut OstreeRepo,
|
||||
*const c_char,
|
||||
*mut libc::stat,
|
||||
gpointer,
|
||||
) -> OstreeRepoCheckoutFilterResult,
|
||||
);
|
||||
}
|
||||
|
||||
Stash(options.as_ref(), (options, subpath, sepolicy_prefix))
|
||||
}
|
||||
}
|
||||
@ -83,7 +117,7 @@ impl<'a> ToGlibPtr<'a, *const OstreeRepoCheckoutAtOptions> for RepoCheckoutAtOpt
|
||||
mod tests {
|
||||
use super::*;
|
||||
use gio::{File, NONE_CANCELLABLE};
|
||||
use glib_sys::{GFALSE, GTRUE};
|
||||
use glib_sys::{gpointer, GFALSE, GTRUE};
|
||||
use ostree_sys::{
|
||||
OSTREE_REPO_CHECKOUT_MODE_NONE, OSTREE_REPO_CHECKOUT_MODE_USER,
|
||||
OSTREE_REPO_CHECKOUT_OVERWRITE_NONE, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL,
|
||||
@ -132,6 +166,9 @@ mod tests {
|
||||
force_copy_zerosized: true,
|
||||
subpath: Some("sub/path".into()),
|
||||
devino_to_csum_cache: Some(RepoDevInoCache::new()),
|
||||
filter: Some(Box::new(|_repo, _path, _stat| {
|
||||
RepoCheckoutFilterResult::Skip
|
||||
})),
|
||||
sepolicy: Some(SePolicy::new(&File::new_for_path("a/b"), NONE_CANCELLABLE).unwrap()),
|
||||
sepolicy_prefix: Some("prefix".into()),
|
||||
};
|
||||
@ -161,8 +198,25 @@ mod tests {
|
||||
);
|
||||
assert_eq!((*ptr).unused_ints, [0; 6]);
|
||||
assert_eq!((*ptr).unused_ptrs, [ptr::null_mut(); 3]);
|
||||
assert_eq!((*ptr).filter, None);
|
||||
assert_eq!((*ptr).filter_user_data, ptr::null_mut());
|
||||
assert_eq!(
|
||||
(*ptr).filter,
|
||||
Some(
|
||||
filter_trampoline
|
||||
as unsafe extern "C" fn(
|
||||
*mut OstreeRepo,
|
||||
*const c_char,
|
||||
*mut libc::stat,
|
||||
gpointer,
|
||||
)
|
||||
-> OstreeRepoCheckoutFilterResult
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
(*ptr).filter_user_data,
|
||||
options.filter.as_ref().unwrap()
|
||||
as *const Box<dyn Fn(&Repo, &Path, &libc::stat) -> RepoCheckoutFilterResult>
|
||||
as gpointer
|
||||
);
|
||||
assert_eq!((*ptr).sepolicy, options.sepolicy.to_glib_none().0);
|
||||
assert_eq!(
|
||||
CStr::from_ptr((*ptr).sepolicy_prefix),
|
||||
|
@ -13,8 +13,8 @@ use gio::prelude::*;
|
||||
use gio::NONE_CANCELLABLE;
|
||||
use glib::prelude::*;
|
||||
use ostree::{
|
||||
ObjectName, ObjectType, RepoCheckoutAtOptions, RepoCheckoutMode, RepoCheckoutOverwriteMode,
|
||||
RepoDevInoCache,
|
||||
ObjectName, ObjectType, RepoCheckoutAtOptions, RepoCheckoutFilterResult, RepoCheckoutMode,
|
||||
RepoCheckoutOverwriteMode, RepoDevInoCache,
|
||||
};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
@ -161,6 +161,9 @@ fn should_checkout_at_with_options() {
|
||||
force_copy: true,
|
||||
force_copy_zerosized: true,
|
||||
devino_to_csum_cache: Some(RepoDevInoCache::new()),
|
||||
filter: Some(Box::new(|_repo, _path, _stat| {
|
||||
RepoCheckoutFilterResult::Allow
|
||||
})),
|
||||
..Default::default()
|
||||
}),
|
||||
dirfd.as_raw_fd(),
|
||||
@ -172,3 +175,36 @@ fn should_checkout_at_with_options() {
|
||||
|
||||
assert_test_file(checkout_dir.path());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "v2016_8")]
|
||||
fn should_checkout_at_with_filter() {
|
||||
let test_repo = TestRepo::new();
|
||||
let checksum = test_repo.test_commit("test");
|
||||
let checkout_dir = tempfile::tempdir().expect("checkout dir");
|
||||
|
||||
let dirfd = openat::Dir::open(checkout_dir.path()).expect("openat");
|
||||
test_repo
|
||||
.repo
|
||||
.checkout_at(
|
||||
Some(&RepoCheckoutAtOptions {
|
||||
filter: Some(Box::new(|_repo, path, _stat| {
|
||||
if let Some("testfile") = path.file_name().map(|s| s.to_str().unwrap()) {
|
||||
RepoCheckoutFilterResult::Skip
|
||||
} else {
|
||||
RepoCheckoutFilterResult::Allow
|
||||
}
|
||||
})),
|
||||
..Default::default()
|
||||
}),
|
||||
dirfd.as_raw_fd(),
|
||||
"test-checkout",
|
||||
&checksum,
|
||||
NONE_CANCELLABLE,
|
||||
)
|
||||
.expect("checkout at");
|
||||
|
||||
let testdir = checkout_dir.path().join("test-checkout").join("testdir");
|
||||
assert!(std::fs::read_dir(&testdir).is_ok());
|
||||
assert!(std::fs::File::open(&testdir.join("testfile")).is_err());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user