lib: RepoCheckoutAtOptions

This commit is contained in:
Felix Krull 2019-05-26 19:18:12 +02:00 committed by Colin Walters
parent 16718eb155
commit eec4a2287d
7 changed files with 254 additions and 13 deletions

View File

@ -41,6 +41,7 @@ ostree-sys = { version = "0.3.0", path = "sys" }
[dev-dependencies]
maplit = "1.0.1"
openat = "0.1.17"
tempfile = "3"
[features]

View File

@ -49,7 +49,6 @@ generate = [
#"OSTree.RepoPruneOptions",
#"OSTree.RepoExportArchiveOptions",
#"OSTree.RepoCheckoutAtOptions",
]
manual = [
@ -63,6 +62,8 @@ manual = [
"GLib.KeyFile",
"GLib.String",
"GLib.Variant",
"OSTree.RepoCheckoutAtOptions",
]
[crate_name_overrides]
@ -94,6 +95,16 @@ status = "generate"
name = "checkout_tree_at"
ignore = true
[[object.function]]
# TODO: see which of these annotations I can upstream
name = "checkout_at"
[[object.function.parameter]]
name = "options"
const = true
[[object.function.parameter]]
name = "destination_path"
string_type = "filename"
[[object]]
name = "OSTree.RepoFinderResult"
status = "generate"

View File

@ -11,6 +11,8 @@ use MutableTree;
use ObjectType;
#[cfg(any(feature = "v2018_6", feature = "dox"))]
use Remote;
#[cfg(any(feature = "v2016_8", feature = "dox"))]
use RepoCheckoutAtOptions;
use RepoCheckoutMode;
use RepoCheckoutOverwriteMode;
use RepoCommitModifier;
@ -39,6 +41,7 @@ use glib_sys;
use gobject_sys;
use libc;
use ostree_sys;
use std;
use std::boxed::Box as Box_;
use std::fmt;
use std::mem;
@ -96,10 +99,14 @@ impl Repo {
}
}
//#[cfg(any(feature = "v2016_8", feature = "dox"))]
//pub fn checkout_at<P: IsA<gio::Cancellable>>(&self, options: /*Ignored*/Option<&mut RepoCheckoutAtOptions>, destination_dfd: i32, destination_path: &str, commit: &str, cancellable: Option<&P>) -> Result<(), Error> {
// unsafe { TODO: call ostree_sys:ostree_repo_checkout_at() }
//}
#[cfg(any(feature = "v2016_8", feature = "dox"))]
pub fn checkout_at<P: AsRef<std::path::Path>, Q: IsA<gio::Cancellable>>(&self, options: Option<&RepoCheckoutAtOptions>, destination_dfd: i32, destination_path: P, commit: &str, cancellable: Option<&Q>) -> Result<(), Error> {
unsafe {
let mut error = ptr::null_mut();
let _ = ostree_sys::ostree_repo_checkout_at(self.to_glib_none().0, mut_override(options.to_glib_none().0), destination_dfd, destination_path.as_ref().to_glib_none().0, commit.to_glib_none().0, cancellable.map(|p| p.as_ref()).to_glib_none().0, &mut error);
if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) }
}
}
pub fn checkout_gc<P: IsA<gio::Cancellable>>(&self, cancellable: Option<&P>) -> Result<(), Error> {
unsafe {

View File

@ -34,10 +34,12 @@ pub use crate::auto::*;
mod collection_ref;
mod object_name;
mod repo;
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::*;
pub use crate::repo_checkout_at_options::*;
// tests
#[cfg(test)]

View File

@ -0,0 +1,167 @@
use glib::translate::{Stash, ToGlib, ToGlibPtr};
use ostree_sys::OstreeRepoCheckoutAtOptions;
use std::os::raw::c_char;
use std::path::PathBuf;
use {RepoCheckoutMode, RepoCheckoutOverwriteMode};
use {RepoDevInoCache, SePolicy};
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub struct RepoCheckoutAtOptions {
pub mode: RepoCheckoutMode,
pub overwrite_mode: RepoCheckoutOverwriteMode,
pub enable_uncompressed_cache: bool,
pub enable_fsync: bool,
pub process_whiteouts: bool,
pub no_copy_fallback: bool,
pub force_copy: bool,
pub bareuseronly_dirs: bool,
pub force_copy_zerosized: bool,
pub subpath: Option<PathBuf>,
pub devino_to_csum_cache: Option<RepoDevInoCache>,
// pub filter: OstreeRepoCheckoutFilter,
// pub filter_user_data: gpointer,
pub sepolicy: Option<SePolicy>,
pub sepolicy_prefix: Option<String>,
}
impl Default for RepoCheckoutAtOptions {
fn default() -> Self {
RepoCheckoutAtOptions {
mode: RepoCheckoutMode::None,
overwrite_mode: RepoCheckoutOverwriteMode::None,
enable_uncompressed_cache: false,
enable_fsync: false,
process_whiteouts: false,
no_copy_fallback: false,
force_copy: false,
bareuseronly_dirs: false,
force_copy_zerosized: false,
subpath: None,
devino_to_csum_cache: None,
sepolicy: None,
sepolicy_prefix: None,
}
}
}
impl<'a> ToGlibPtr<'a, *const OstreeRepoCheckoutAtOptions> for RepoCheckoutAtOptions {
type Storage = (
Box<OstreeRepoCheckoutAtOptions>,
Stash<'a, *const c_char, Option<PathBuf>>,
Stash<'a, *const c_char, Option<String>>,
);
fn to_glib_none(&'a self) -> Stash<*const OstreeRepoCheckoutAtOptions, Self> {
let mut options = Box::new(unsafe { std::mem::zeroed::<OstreeRepoCheckoutAtOptions>() });
options.mode = self.mode.to_glib();
options.overwrite_mode = self.overwrite_mode.to_glib();
options.enable_uncompressed_cache = self.enable_uncompressed_cache.to_glib();
options.enable_fsync = self.enable_fsync.to_glib();
options.process_whiteouts = self.process_whiteouts.to_glib();
options.no_copy_fallback = self.no_copy_fallback.to_glib();
options.force_copy = self.force_copy.to_glib();
options.bareuseronly_dirs = self.bareuseronly_dirs.to_glib();
options.force_copy_zerosized = self.force_copy_zerosized.to_glib();
let subpath = self.subpath.to_glib_none();
options.subpath = subpath.0;
let sepolicy_prefix = self.sepolicy_prefix.to_glib_none();
options.sepolicy_prefix = sepolicy_prefix.0;
/*
devino_to_csum_cache: None,
sepolicy: None,
*/
Stash(options.as_ref(), (options, subpath, sepolicy_prefix))
}
}
#[cfg(test)]
mod tests {
use super::*;
use gio::{File, NONE_CANCELLABLE};
use glib_sys::{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,
};
use std::ffi::{CStr, CString};
use std::ptr;
#[test]
fn should_convert_default_options() {
let options = RepoCheckoutAtOptions::default();
let stash = options.to_glib_none();
let ptr = stash.0;
unsafe {
assert_eq!((*ptr).mode, OSTREE_REPO_CHECKOUT_MODE_NONE);
assert_eq!((*ptr).overwrite_mode, OSTREE_REPO_CHECKOUT_OVERWRITE_NONE);
assert_eq!((*ptr).enable_uncompressed_cache, GFALSE);
assert_eq!((*ptr).enable_fsync, GFALSE);
assert_eq!((*ptr).process_whiteouts, GFALSE);
assert_eq!((*ptr).no_copy_fallback, GFALSE);
assert_eq!((*ptr).force_copy, GFALSE);
assert_eq!((*ptr).bareuseronly_dirs, GFALSE);
assert_eq!((*ptr).force_copy_zerosized, GFALSE);
assert_eq!((*ptr).unused_bools, [GFALSE; 4]);
assert_eq!((*ptr).subpath, ptr::null());
assert_eq!((*ptr).devino_to_csum_cache, ptr::null_mut());
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).sepolicy, ptr::null_mut());
assert_eq!((*ptr).sepolicy_prefix, ptr::null());
}
}
#[test]
fn should_convert_non_default_options() {
let options = RepoCheckoutAtOptions {
mode: RepoCheckoutMode::User,
overwrite_mode: RepoCheckoutOverwriteMode::UnionIdentical,
enable_uncompressed_cache: true,
enable_fsync: true,
process_whiteouts: true,
no_copy_fallback: true,
force_copy: true,
bareuseronly_dirs: true,
force_copy_zerosized: true,
subpath: Some("sub/path".into()),
devino_to_csum_cache: Some(RepoDevInoCache::new()),
sepolicy: Some(SePolicy::new(&File::new_for_path("a/b"), NONE_CANCELLABLE).unwrap()),
sepolicy_prefix: Some("prefix".into()),
};
let stash = options.to_glib_none();
let ptr = stash.0;
unsafe {
assert_eq!((*ptr).mode, OSTREE_REPO_CHECKOUT_MODE_USER);
assert_eq!(
(*ptr).overwrite_mode,
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL
);
assert_eq!((*ptr).enable_uncompressed_cache, GTRUE);
assert_eq!((*ptr).enable_fsync, GTRUE);
assert_eq!((*ptr).process_whiteouts, GTRUE);
assert_eq!((*ptr).no_copy_fallback, GTRUE);
assert_eq!((*ptr).force_copy, GTRUE);
assert_eq!((*ptr).bareuseronly_dirs, GTRUE);
assert_eq!((*ptr).force_copy_zerosized, GTRUE);
assert_eq!((*ptr).unused_bools, [GFALSE; 4]);
assert_eq!(
CStr::from_ptr((*ptr).subpath),
CString::new("sub/path").unwrap().as_c_str()
);
assert_ne!((*ptr).devino_to_csum_cache, ptr::null_mut());
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_ne!((*ptr).sepolicy, ptr::null_mut());
assert_eq!(
CStr::from_ptr((*ptr).sepolicy_prefix),
CString::new("prefix").unwrap().as_c_str()
);
}
}
}

View File

@ -1,5 +1,6 @@
extern crate gio;
extern crate glib;
extern crate openat;
extern crate ostree;
extern crate tempfile;
#[macro_use]
@ -11,7 +12,10 @@ use util::*;
use gio::prelude::*;
use gio::NONE_CANCELLABLE;
use glib::prelude::*;
use ostree::{ObjectName, ObjectType};
use ostree::{
ObjectName, ObjectType, RepoCheckoutAtOptions, RepoCheckoutMode, RepoCheckoutOverwriteMode,
};
use std::os::unix::io::AsRawFd;
#[test]
fn should_commit_content_to_repo_and_list_refs_again() {
@ -91,11 +95,51 @@ fn should_checkout_tree() {
)
.expect("checkout tree");
let testfile_path = checkout_dir
.path()
.join("test-checkout")
.join("testdir")
.join("testfile");
let testfile_contents = std::fs::read_to_string(testfile_path).expect("test file");
assert_eq!("test\n", testfile_contents);
assert_test_file(checkout_dir.path());
}
#[test]
fn should_checkout_at_with_none_options() {
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(
None,
dirfd.as_raw_fd(),
"test-checkout",
&checksum,
NONE_CANCELLABLE,
)
.expect("checkout at");
assert_test_file(checkout_dir.path());
}
#[test]
fn should_checkout_at_with_options() {
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 {
mode: RepoCheckoutMode::User,
overwrite_mode: RepoCheckoutOverwriteMode::UnionIdentical,
..Default::default()
}),
dirfd.as_raw_fd(),
"test-checkout",
&checksum,
NONE_CANCELLABLE,
)
.expect("checkout at");
assert_test_file(checkout_dir.path());
}

View File

@ -64,3 +64,12 @@ pub fn commit(repo: &ostree::Repo, mtree: &ostree::MutableTree, ref_: &str) -> G
.expect("commit transaction");
checksum
}
pub fn assert_test_file(checkout: &Path) {
let testfile_path = checkout
.join("test-checkout")
.join("testdir")
.join("testfile");
let testfile_contents = std::fs::read_to_string(testfile_path).expect("test file");
assert_eq!("test\n", testfile_contents);
}