lib: implement CheckoutOptions::filter (hackishly)
This commit is contained in:
parent
a521c838f5
commit
19fdf706d5
|
|
@ -24,6 +24,7 @@ generate = [
|
||||||
"OSTree.MutableTree",
|
"OSTree.MutableTree",
|
||||||
"OSTree.ObjectType",
|
"OSTree.ObjectType",
|
||||||
"OSTree.Remote",
|
"OSTree.Remote",
|
||||||
|
"OSTree.RepoCheckoutFilterResult",
|
||||||
"OSTree.RepoCheckoutMode",
|
"OSTree.RepoCheckoutMode",
|
||||||
"OSTree.RepoCheckoutOverwriteMode",
|
"OSTree.RepoCheckoutOverwriteMode",
|
||||||
"OSTree.RepoCommitModifier",
|
"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(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum RepoCheckoutMode {
|
pub enum RepoCheckoutMode {
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,8 @@ pub use self::enums::DeploymentUnlockedState;
|
||||||
pub use self::enums::GpgSignatureAttr;
|
pub use self::enums::GpgSignatureAttr;
|
||||||
pub use self::enums::GpgSignatureFormatFlags;
|
pub use self::enums::GpgSignatureFormatFlags;
|
||||||
pub use self::enums::ObjectType;
|
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::RepoCheckoutMode;
|
||||||
pub use self::enums::RepoCheckoutOverwriteMode;
|
pub use self::enums::RepoCheckoutOverwriteMode;
|
||||||
pub use self::enums::RepoMode;
|
pub use self::enums::RepoMode;
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,13 @@ pub use crate::auto::*;
|
||||||
mod collection_ref;
|
mod collection_ref;
|
||||||
mod object_name;
|
mod object_name;
|
||||||
mod repo;
|
mod repo;
|
||||||
|
#[cfg(any(feature = "v2018_2", feature = "dox"))]
|
||||||
mod repo_checkout_at_options;
|
mod repo_checkout_at_options;
|
||||||
#[cfg(any(feature = "v2018_6", feature = "dox"))]
|
#[cfg(any(feature = "v2018_6", feature = "dox"))]
|
||||||
pub use crate::collection_ref::*;
|
pub use crate::collection_ref::*;
|
||||||
pub use crate::object_name::*;
|
pub use crate::object_name::*;
|
||||||
pub use crate::repo::*;
|
pub use crate::repo::*;
|
||||||
|
#[cfg(any(feature = "v2018_2", feature = "dox"))]
|
||||||
pub use crate::repo_checkout_at_options::*;
|
pub use crate::repo_checkout_at_options::*;
|
||||||
|
|
||||||
// tests
|
// 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 libc::c_char;
|
||||||
use ostree_sys::OstreeRepoCheckoutAtOptions;
|
use ostree_sys::{OstreeRepo, OstreeRepoCheckoutAtOptions, OstreeRepoCheckoutFilterResult};
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
use {Repo, RepoCheckoutFilterResult};
|
||||||
use {RepoCheckoutMode, RepoCheckoutOverwriteMode};
|
use {RepoCheckoutMode, RepoCheckoutOverwriteMode};
|
||||||
use {RepoDevInoCache, SePolicy};
|
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 struct RepoCheckoutAtOptions {
|
||||||
pub mode: RepoCheckoutMode,
|
pub mode: RepoCheckoutMode,
|
||||||
pub overwrite_mode: RepoCheckoutOverwriteMode,
|
pub overwrite_mode: RepoCheckoutOverwriteMode,
|
||||||
|
|
@ -18,9 +22,8 @@ pub struct RepoCheckoutAtOptions {
|
||||||
pub force_copy_zerosized: bool,
|
pub force_copy_zerosized: bool,
|
||||||
pub subpath: Option<PathBuf>,
|
pub subpath: Option<PathBuf>,
|
||||||
pub devino_to_csum_cache: Option<RepoDevInoCache>,
|
pub devino_to_csum_cache: Option<RepoDevInoCache>,
|
||||||
// TODO: those thingamajigs
|
// TODO: might be interesting to turn this into a type parameter
|
||||||
// pub filter: OstreeRepoCheckoutFilter,
|
pub filter: RepoCheckoutFilter,
|
||||||
// pub filter_user_data: gpointer,
|
|
||||||
pub sepolicy: Option<SePolicy>,
|
pub sepolicy: Option<SePolicy>,
|
||||||
pub sepolicy_prefix: Option<String>,
|
pub sepolicy_prefix: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
@ -39,6 +42,7 @@ impl Default for RepoCheckoutAtOptions {
|
||||||
force_copy_zerosized: false,
|
force_copy_zerosized: false,
|
||||||
subpath: None,
|
subpath: None,
|
||||||
devino_to_csum_cache: None,
|
devino_to_csum_cache: None,
|
||||||
|
filter: None,
|
||||||
sepolicy: None,
|
sepolicy: None,
|
||||||
sepolicy_prefix: None,
|
sepolicy_prefix: None,
|
||||||
}
|
}
|
||||||
|
|
@ -47,6 +51,21 @@ impl Default for RepoCheckoutAtOptions {
|
||||||
|
|
||||||
type StringStash<'a, T> = Stash<'a, *const c_char, Option<T>>;
|
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 {
|
impl<'a> ToGlibPtr<'a, *const OstreeRepoCheckoutAtOptions> for RepoCheckoutAtOptions {
|
||||||
type Storage = (
|
type Storage = (
|
||||||
Box<OstreeRepoCheckoutAtOptions>,
|
Box<OstreeRepoCheckoutAtOptions>,
|
||||||
|
|
@ -75,6 +94,21 @@ impl<'a> ToGlibPtr<'a, *const OstreeRepoCheckoutAtOptions> for RepoCheckoutAtOpt
|
||||||
let sepolicy = self.sepolicy.to_glib_none();
|
let sepolicy = self.sepolicy.to_glib_none();
|
||||||
options.sepolicy = sepolicy.0;
|
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))
|
Stash(options.as_ref(), (options, subpath, sepolicy_prefix))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +117,7 @@ impl<'a> ToGlibPtr<'a, *const OstreeRepoCheckoutAtOptions> for RepoCheckoutAtOpt
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use gio::{File, NONE_CANCELLABLE};
|
use gio::{File, NONE_CANCELLABLE};
|
||||||
use glib_sys::{GFALSE, GTRUE};
|
use glib_sys::{gpointer, GFALSE, GTRUE};
|
||||||
use ostree_sys::{
|
use ostree_sys::{
|
||||||
OSTREE_REPO_CHECKOUT_MODE_NONE, OSTREE_REPO_CHECKOUT_MODE_USER,
|
OSTREE_REPO_CHECKOUT_MODE_NONE, OSTREE_REPO_CHECKOUT_MODE_USER,
|
||||||
OSTREE_REPO_CHECKOUT_OVERWRITE_NONE, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL,
|
OSTREE_REPO_CHECKOUT_OVERWRITE_NONE, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL,
|
||||||
|
|
@ -132,6 +166,9 @@ mod tests {
|
||||||
force_copy_zerosized: true,
|
force_copy_zerosized: true,
|
||||||
subpath: Some("sub/path".into()),
|
subpath: Some("sub/path".into()),
|
||||||
devino_to_csum_cache: Some(RepoDevInoCache::new()),
|
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: Some(SePolicy::new(&File::new_for_path("a/b"), NONE_CANCELLABLE).unwrap()),
|
||||||
sepolicy_prefix: Some("prefix".into()),
|
sepolicy_prefix: Some("prefix".into()),
|
||||||
};
|
};
|
||||||
|
|
@ -161,8 +198,25 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!((*ptr).unused_ints, [0; 6]);
|
assert_eq!((*ptr).unused_ints, [0; 6]);
|
||||||
assert_eq!((*ptr).unused_ptrs, [ptr::null_mut(); 3]);
|
assert_eq!((*ptr).unused_ptrs, [ptr::null_mut(); 3]);
|
||||||
assert_eq!((*ptr).filter, None);
|
assert_eq!(
|
||||||
assert_eq!((*ptr).filter_user_data, ptr::null_mut());
|
(*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!((*ptr).sepolicy, options.sepolicy.to_glib_none().0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CStr::from_ptr((*ptr).sepolicy_prefix),
|
CStr::from_ptr((*ptr).sepolicy_prefix),
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ use gio::prelude::*;
|
||||||
use gio::NONE_CANCELLABLE;
|
use gio::NONE_CANCELLABLE;
|
||||||
use glib::prelude::*;
|
use glib::prelude::*;
|
||||||
use ostree::{
|
use ostree::{
|
||||||
ObjectName, ObjectType, RepoCheckoutAtOptions, RepoCheckoutMode, RepoCheckoutOverwriteMode,
|
ObjectName, ObjectType, RepoCheckoutAtOptions, RepoCheckoutFilterResult, RepoCheckoutMode,
|
||||||
RepoDevInoCache,
|
RepoCheckoutOverwriteMode, RepoDevInoCache,
|
||||||
};
|
};
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
|
|
@ -161,6 +161,9 @@ fn should_checkout_at_with_options() {
|
||||||
force_copy: true,
|
force_copy: true,
|
||||||
force_copy_zerosized: true,
|
force_copy_zerosized: true,
|
||||||
devino_to_csum_cache: Some(RepoDevInoCache::new()),
|
devino_to_csum_cache: Some(RepoDevInoCache::new()),
|
||||||
|
filter: Some(Box::new(|_repo, _path, _stat| {
|
||||||
|
RepoCheckoutFilterResult::Allow
|
||||||
|
})),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
dirfd.as_raw_fd(),
|
dirfd.as_raw_fd(),
|
||||||
|
|
@ -172,3 +175,36 @@ fn should_checkout_at_with_options() {
|
||||||
|
|
||||||
assert_test_file(checkout_dir.path());
|
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