Introduce CxxGObjectArray, use in lockfile code

cxx-rs only supports a few basic types in `Vec<T>`/`CxxVector<T>`
and we need to pass an array of GObjects in a few cases.
Add a wrapper class hack instead of using `u64` so we at least
have some basic safety here and have a convenient place to
grep for later when we want to improve this.
This commit is contained in:
Colin Walters 2021-03-02 18:20:22 +00:00 committed by OpenShift Merge Robot
parent 5c1911445c
commit 60e605b34e
9 changed files with 81 additions and 15 deletions

2
Cargo.lock generated
View File

@ -676,6 +676,7 @@ dependencies = [
"cmake",
"cxx",
"cxx-build",
"glib",
"system-deps 3.0.0",
]
@ -1236,6 +1237,7 @@ dependencies = [
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"indicatif",
"lazy_static",
"libc",

View File

@ -34,6 +34,7 @@ cxx = "1.0.32"
envsubst = "0.2.0"
gio = "0.9.1"
gio-sys = "0.10.1"
gobject-sys = "0.10.0"
glib = "0.10.3"
glib-sys = "0.10.1"
indicatif = "0.15.0"

View File

@ -7,6 +7,7 @@ links = "dnf"
[dependencies]
cxx = "1.0.32"
glib = "0.10.3"
[lib]
name = "libdnf_sys"

View File

@ -80,7 +80,7 @@ macro_rules! cxxrs_bind {
paste! {
$(
#[repr(transparent)]
pub struct [<FFI $ns $i>]($sys::[<$ns $i>]);
pub struct [<FFI $ns $i>](pub(crate) $sys::[<$ns $i>]);
unsafe impl ExternType for [<FFI $ns $i>] {
type Id = type_id!(rpmostreecxx::[<$ns $i>]);
@ -96,6 +96,7 @@ macro_rules! cxxrs_bind {
// This macro is special to ostree types currently.
cxxrs_bind!(Ostree, ostree, ostree_sys, [Sysroot, Repo, Deployment]);
cxxrs_bind!(G, gio, gio_sys, [Cancellable]);
cxxrs_bind!(G, glib, gobject_sys, [Object]);
cxxrs_bind!(G, glib, glib_sys, [VariantDict]);
// An error type helper; separate from the GObject bridging

View File

@ -35,6 +35,7 @@ pub mod ffi {
#[allow(dead_code)]
type OstreeRepo = crate::FFIOstreeRepo;
type OstreeDeployment = crate::FFIOstreeDeployment;
type GObject = crate::FFIGObject;
type GCancellable = crate::FFIGCancellable;
type GVariantDict = crate::FFIGVariantDict;
@ -258,8 +259,8 @@ pub mod ffi {
fn ror_lockfile_read(filenames: &Vec<String>) -> Result<Vec<StringMapping>>;
fn ror_lockfile_write(
filename: &str,
packages: Vec<u64>,
rpmmd_repos: Vec<u64>,
packages: Pin<&mut CxxGObjectArray>,
rpmmd_repos: Pin<&mut CxxGObjectArray>,
) -> Result<()>;
}
@ -268,6 +269,13 @@ pub mod ffi {
fn cache_branch_to_nevra(nevra: &str) -> String;
}
unsafe extern "C++" {
include!("rpmostree-cxxrsutil.hpp");
type CxxGObjectArray;
fn length(self: Pin<&mut CxxGObjectArray>) -> u32;
fn get(self: Pin<&mut CxxGObjectArray>, i: u32) -> &mut GObject;
}
unsafe extern "C++" {
include!("rpmostree-util.h");
// Currently only used in unit tests

View File

@ -21,6 +21,7 @@ use std::convert::TryInto;
use std::io;
use std::iter::Extend;
use std::path::Path;
use std::pin::Pin;
/// Given a lockfile filename, parse it
fn lockfile_parse<P: AsRef<Path>>(filename: P) -> Result<LockfileConfig> {
@ -208,8 +209,8 @@ pub(crate) fn ror_lockfile_read(filenames: &Vec<String>) -> CxxResult<Vec<String
pub(crate) fn ror_lockfile_write(
filename: &str,
packages: Vec<u64>,
rpmmd_repos: Vec<u64>,
mut packages: Pin<&mut crate::ffi::CxxGObjectArray>,
mut rpmmd_repos: Pin<&mut crate::ffi::CxxGObjectArray>,
) -> CxxResult<()> {
// get current time, but scrub nanoseconds; it's overkill to serialize that
let now = {
@ -225,8 +226,9 @@ pub(crate) fn ror_lockfile_write(
}),
};
for pkg in packages {
let pkg_ref = unsafe { &mut *(pkg as *mut libdnf_sys::DnfPackage) };
for i in 0..(packages.as_mut().length()) {
let pkg = packages.as_mut().get(i);
let pkg_ref = unsafe { &mut *(&mut pkg.0 as *mut _ as *mut libdnf_sys::DnfPackage) };
let name = dnf_package_get_name(pkg_ref).unwrap();
let evr = dnf_package_get_evr(pkg_ref).unwrap();
let arch = dnf_package_get_arch(pkg_ref).unwrap();
@ -250,8 +252,9 @@ pub(crate) fn ror_lockfile_write(
.as_mut()
.unwrap();
for rpmmd_repo in rpmmd_repos {
let repo_ref = unsafe { &mut *(rpmmd_repo as *mut libdnf_sys::DnfRepo) };
for i in 0..rpmmd_repos.as_mut().length() {
let repo_ref = rpmmd_repos.as_mut().get(i);
let repo_ref = unsafe { &mut *(&mut repo_ref.0 as *mut _ as *mut libdnf_sys::DnfRepo) };
let id = dnf_repo_get_id(repo_ref).unwrap();
let generated = dnf_repo_get_timestamp_generated(repo_ref).unwrap();
let generated: i64 = match generated.try_into() {

View File

@ -382,12 +382,8 @@ install_packages (RpmOstreeTreeComposeContext *self,
g_autoptr(GPtrArray) rpmmd_repos =
rpmostree_get_enabled_rpmmd_repos (rpmostree_context_get_dnf (self->corectx),
DNF_REPO_ENABLED_PACKAGES);
auto pkgs_v = rust::Vec<guint64>();
for (guint i = 0; i < pkgs->len; i++)
pkgs_v.push_back((guint64)pkgs->pdata[i]);
auto repos_v = rust::Vec<guint64>();
for (guint i = 0; i < rpmmd_repos->len; i++)
repos_v.push_back((guint64)rpmmd_repos->pdata[i]);
auto pkgs_v = rpmostreecxx::CxxGObjectArray(pkgs);
auto repos_v = rpmostreecxx::CxxGObjectArray(rpmmd_repos);
rpmostreecxx::ror_lockfile_write(opt_write_lockfile_to, pkgs_v, repos_v);
}

View File

@ -29,6 +29,7 @@ namespace rpmostreecxx {
typedef ::OstreeRepo OstreeRepo;
typedef ::OstreeDeployment OstreeDeployment;
typedef ::GCancellable GCancellable;
typedef ::GObject GObject;
typedef ::GVariantDict GVariantDict;
}

View File

@ -0,0 +1,53 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
#pragma once
#include <string>
#include <exception>
#include <sstream>
#include <gio/gio.h>
#include "rust/cxx.h"
// Helpers corresponding to cxxrsutil.rs
namespace rpmostreecxx {
// Wrapper for an array of GObjects. This is a hack until
// cxx-rs gains support for either std::vector<> or Vec<T>
// with nontrivial types.
class CxxGObjectArray final {
public:
CxxGObjectArray(GPtrArray *arr_p) : arr(arr_p) {
g_ptr_array_ref(arr);
};
~CxxGObjectArray() {
g_ptr_array_unref(arr);
}
unsigned int length() {
return (unsigned int)arr->len;
}
::GObject& get(unsigned int i) {
g_assert_cmpuint(i, <, arr->len);
return *(::GObject*)arr->pdata[i];
}
GPtrArray* arr;
};
} // namespace