diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..29eb5db --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "libzypp" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[package.metadata.docs.rs] +all-features = true +# For build.rs scripts +rustc-args = ["--cfg", "docsrs"] +# For rustdoc +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +libc = "0.2" +ffi = { package = "zypp-sys", path = "./zypp-sys" } +glib = { git = "https://github.com/gtk-rs/gtk-rs-core" } + +[[bin]] +name = "zypprs" +path = "src/bin.rs" diff --git a/Gir.toml b/Gir.toml new file mode 100644 index 0000000..0c1a46d --- /dev/null +++ b/Gir.toml @@ -0,0 +1,35 @@ +[options] +library = "Zypp" +version = "1.0" +min_cfg_version = "1.0" +target_path = "." +girs_directories = ["gir-files", "libzypp/build/zypp-glib"] +work_mode = "normal" +single_version_file = true +generate_safety_asserts = true +deprecate_by_min_version = true +generate_builder = true + +generate = [ + "Zypp.Context", + "Zypp.Exception", + "Zypp.Expected", + "Zypp.InfoBase", + "Zypp.ManagedFile", + "Zypp.ProgressObserver", + "Zypp.RepoInfo", + "Zypp.RepoInfoType", + "Zypp.RepoManager", + "Zypp.ServiceInfo", + "Zypp.RepoManagerOptions", + "Zypp.RepoManagerError", + "Zypp.RepoRefreshResult", + "Zypp.Repository", + "Zypp.*", +] + +manual = [ + "GLib.Error", + "GLib.Quark", + "GObject.Value" +] diff --git a/README.md b/README.md new file mode 100644 index 0000000..25f967f --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +## Experimental bindings for libzypp glib + +Goal of this crate is to provide direct rust bindings to libzypp to avoid long path over yast component system. + +### Code Organization + +- zypp-sys dir is low level unsafe libzypp bindings +- libzypp dir git submodule for glib branch of libzypp +- gir dir is gir submodule for gir tool on revision used for code generation +- gir-files dir is git submodule with directory with curated gir files ( see gir book for details ) +- ./ is high level libzypp bindings + +### Updating bindings + +In general follow gir book. Ideally update gir submodule to master. Then regenerate zypp-sys, +then high level bindings and do not forget to also update documentation with `rustdoc-stripper` + +### Resources + +- gir book: https://gtk-rs.org/gir/book/introduction.html +- git submodules: https://git-scm.com/book/en/v2/Git-Tools-Submodules diff --git a/setup_env.sh b/setup_env.sh new file mode 100755 index 0000000..6d658f8 --- /dev/null +++ b/setup_env.sh @@ -0,0 +1,108 @@ +#!/usr/bin/bash + +# Script that do initial setup for libzypp ng bindings development. +# To update git submodules use +# git submodule update --remote +# +# It needs TW as dev env. One of option is to use distrobox as shown: +# ```sh +# distrobox create --image tumbleweed --name zyppng +# distrobox enter zyppng # if stuck see https://github.com/89luca89/distrobox/issues/1530 and kill and run again +# # and now you are inside dev env where you run this script +# # to clean use distrobox stop zyppng and if no longer image is needed use distrobox rm zyppng +# ``` + +set -eu +BASEDIR=$(dirname "$0") + +# Helper: +# Ensure root privileges for the installation. +# In a testing container, we are root but there is no sudo. +if [ $(id --user) != 0 ]; then + SUDO=sudo + if [ "$($SUDO id --user)" != 0 ]; then + echo "We are not root and cannot sudo, cannot continue." + exit 1 + fi +else + SUDO="" +fi + +$SUDO zypper --non-interactive rm rust\* || true + +# install all required packages and only required as recommends are really huge +$SUDO zypper --non-interactive install --no-recommends \ + git \ + cmake \ + openssl \ + libudev1 \ + libboost_headers-devel \ + libboost_program_options-devel \ + libboost_test-devel \ + libboost_thread-devel \ + dejagnu \ + gcc-c++ \ + gettext-devel \ + graphviz \ + libxml2-devel \ + yaml-cpp-devel \ + gobject-introspection-devel \ + libproxy-devel \ + pkg-config \ + libsolv-devel \ + libsolv-tools-base \ + glib2-devel \ + libsigc++2-devel \ + readline-devel \ + nginx \ + vsftpd \ + rpm \ + rpm-devel \ + libgpgme-devel \ + FastCGI-devel \ + libcurl-devel \ + "rubygem(asciidoctor)" \ + libzck-devel \ + libzstd-devel \ + libbz2-devel \ + xz-devel \ + rustup + +cd "$BASEDIR" +# checkout submodules +git submodule init +git submodule update --checkout + +# lets build libzypp +( +cd libzypp +mkdir -p build +cd build +# With /usr/local, we have to set a path: LD_LIBRARY_PATH=/usr/local/lib64 zypprs +# but the plus side is that the /usr zypper keeps working :) +# +# cmake -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_GLIB_API=ON -D DISABLE_AUTODOCS=ON .. +cmake -D BUILD_GLIB_API=ON -D DISABLE_AUTODOCS=ON .. +make -j$(nproc) +$SUDO make install +) + +# now lets make rust working +rustup install stable +# lets install gir +cd gir +# workaround for badly working exclude in cargo see https://github.com/rust-lang/cargo/issues/6745 +if ! grep -q '\[workspace\]' Cargo.toml; then + printf '\n[workspace]' >> Cargo.toml +fi +cargo install --path . +cd - + +# to use gir follow https://gtk-rs.org/gir/book/tutorial/sys_library.html + +# install doc tool +cargo install rustdoc-stripper + +cargo build + +echo 'To test if everything work run `../target/debug/zypprs`' diff --git a/src/auto/context.rs b/src/auto/context.rs new file mode 100644 index 0000000..d61f531 --- /dev/null +++ b/src/auto/context.rs @@ -0,0 +1,120 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi}; +use glib::{prelude::*,signal::{connect_raw, SignalHandlerId},translate::*}; +use std::{boxed::Box as Box_}; + +glib::wrapper! { + /// This class is the basic building block for the zypp glib API. It defines the path of the + /// root filesystem we are operating on. This is usually "/" but to support chroot use cases it + /// can point to any directory in a filesystem where packages should be installed into. If the rootfs + /// is not defined as "/" then zypp will install packages using chroot into the directory. + /// + /// Settings for zypp are loaded from the rootfs directory and locks are also applied relative to it. + /// Meaning that one context can operate on "/" while another one can operate on "/tmp/rootfs". + /// + /// \note Currently only one ZyppContext is supported until we have refactored the underlying code to support + /// having multiple of them. Mixing them atm will not work due to locks and libsolv limitations + /// + /// ## Properties + /// + /// + /// #### `versionprop` + /// Readable + /// + /// + /// #### `zypp-cppObj` + /// Writeable | Construct Only + #[doc(alias = "ZyppContext")] + pub struct Context(Object); + + match fn { + type_ => || ffi::zypp_context_get_type(), + } +} + +impl Context { + // rustdoc-stripper-ignore-next + /// Creates a new builder-pattern struct instance to construct [`Context`] objects. + /// + /// This method returns an instance of [`ContextBuilder`](crate::builders::ContextBuilder) which can be used to create [`Context`] objects. + pub fn builder() -> ContextBuilder { + ContextBuilder::new() + } + + + /// Loads the system at the given sysroot, returns TRUE on success, otherwise FALSE + /// ## `sysRoot` + /// The system sysroot to load, if a nullptr is given "/" is used + #[doc(alias = "zypp_context_load_system")] + pub fn load_system(&self, sysRoot: Option<&str>) -> Result<(), glib::Error> { + unsafe { + let mut error = std::ptr::null_mut(); + let is_ok = ffi::zypp_context_load_system(self.to_glib_none().0, sysRoot.to_glib_none().0, &mut error); + debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null()); + if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } + } + } + + /// + /// # Returns + /// + /// The context root as requested when loading the system + #[doc(alias = "zypp_context_sysroot")] + pub fn sysroot(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_context_sysroot(self.to_glib_none().0)) + } + } + + #[doc(alias = "zypp_context_version")] + pub fn version(&self) -> Option { + unsafe { + from_glib_none(ffi::zypp_context_version(self.to_glib_none().0)) + } + } + + pub fn versionprop(&self) -> Option { + ObjectExt::property(self, "versionprop") + } + + #[doc(alias = "versionprop")] + pub fn connect_versionprop_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_versionprop_trampoline(this: *mut ffi::ZyppContext, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::versionprop\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_versionprop_trampoline:: as *const ())), Box_::into_raw(f)) + } + } +} + +// rustdoc-stripper-ignore-next + /// A [builder-pattern] type to construct [`Context`] objects. + /// + /// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html +#[must_use = "The builder must be built to be used"] +pub struct ContextBuilder { + builder: glib::object::ObjectBuilder<'static, Context>, + } + + impl ContextBuilder { + fn new() -> Self { + Self { builder: glib::object::Object::builder() } + } + + //pub fn zypp_cppObj(self, zypp_cppObj: /*Unimplemented*/Basic: Pointer) -> Self { + // Self { builder: self.builder.property("zypp-cppObj", zypp_cppObj), } + //} + + // rustdoc-stripper-ignore-next + /// Build the [`Context`]. + #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"] + pub fn build(self) -> Context { + self.builder.build() } +} diff --git a/src/auto/enums.rs b/src/auto/enums.rs new file mode 100644 index 0000000..1ae4341 --- /dev/null +++ b/src/auto/enums.rs @@ -0,0 +1,440 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi}; +use glib::{prelude::*,translate::*}; + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "ZyppException")] +pub enum Exception { + /// Error domain for the zypp exception handling. Errors in this domain will + /// be from the [`Exception`][crate::Exception] enumeration. See [`glib::Error`][crate::glib::Error] for information + /// on error domains. + #[doc(alias = "ZYPP_ERROR")] + Error, +#[doc(hidden)] + __Unknown(i32), +} + +impl Exception { + #[doc(alias = "zypp_exception_quark")] + pub fn quark() -> glib::Quark { + assert_initialized_main_thread!(); + unsafe { + from_glib(ffi::zypp_exception_quark()) + } + } +} + +#[doc(hidden)] +impl IntoGlib for Exception { + type GlibType = ffi::ZyppException; + + #[inline] +fn into_glib(self) -> ffi::ZyppException { +match self { + Self::Error => ffi::ZYPP_ERROR, + Self::__Unknown(value) => value, +} +} +} + +#[doc(hidden)] +impl FromGlib for Exception { + #[inline] +unsafe fn from_glib(value: ffi::ZyppException) -> Self { + skip_assert_initialized!(); + +match value { + ffi::ZYPP_ERROR => Self::Error, + value => Self::__Unknown(value), +} +} +} + +impl StaticType for Exception { + #[inline] + #[doc(alias = "zypp_exception_get_type")] + fn static_type() -> glib::Type { + unsafe { from_glib(ffi::zypp_exception_get_type()) } + } + } + +impl glib::HasParamSpec for Exception { + type ParamSpec = glib::ParamSpecEnum; + type SetValue = Self; + type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; + + fn param_spec_builder() -> Self::BuilderFn { + Self::ParamSpec::builder_with_default + } +} + +impl glib::value::ValueType for Exception { + type Type = Self; +} + +unsafe impl<'a> glib::value::FromValue<'a> for Exception { + type Checker = glib::value::GenericValueTypeChecker; + + #[inline] + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) + } +} + +impl ToValue for Exception { + #[inline] + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); + } + value + } + + #[inline] + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + +impl From for glib::Value { + #[inline] + fn from(v: Exception) -> Self { + skip_assert_initialized!(); + ToValue::to_value(&v) + } +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "ZyppRepoInfoType")] +pub enum RepoInfoType { + #[doc(alias = "ZYPP_REPO_NONE")] + None, + #[doc(alias = "ZYPP_REPO_RPMMD")] + Rpmmd, + #[doc(alias = "ZYPP_REPO_YAST2")] + Yast2, + #[doc(alias = "ZYPP_REPO_RPMPLAINDIR")] + Rpmplaindir, +#[doc(hidden)] + __Unknown(i32), +} + +#[doc(hidden)] +impl IntoGlib for RepoInfoType { + type GlibType = ffi::ZyppRepoInfoType; + + #[inline] +fn into_glib(self) -> ffi::ZyppRepoInfoType { +match self { + Self::None => ffi::ZYPP_REPO_NONE, + Self::Rpmmd => ffi::ZYPP_REPO_RPMMD, + Self::Yast2 => ffi::ZYPP_REPO_YAST2, + Self::Rpmplaindir => ffi::ZYPP_REPO_RPMPLAINDIR, + Self::__Unknown(value) => value, +} +} +} + +#[doc(hidden)] +impl FromGlib for RepoInfoType { + #[inline] +unsafe fn from_glib(value: ffi::ZyppRepoInfoType) -> Self { + skip_assert_initialized!(); + +match value { + ffi::ZYPP_REPO_NONE => Self::None, + ffi::ZYPP_REPO_RPMMD => Self::Rpmmd, + ffi::ZYPP_REPO_YAST2 => Self::Yast2, + ffi::ZYPP_REPO_RPMPLAINDIR => Self::Rpmplaindir, + value => Self::__Unknown(value), +} +} +} + +impl StaticType for RepoInfoType { + #[inline] + #[doc(alias = "zypp_repo_info_type_get_type")] + fn static_type() -> glib::Type { + unsafe { from_glib(ffi::zypp_repo_info_type_get_type()) } + } + } + +impl glib::HasParamSpec for RepoInfoType { + type ParamSpec = glib::ParamSpecEnum; + type SetValue = Self; + type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; + + fn param_spec_builder() -> Self::BuilderFn { + Self::ParamSpec::builder_with_default + } +} + +impl glib::value::ValueType for RepoInfoType { + type Type = Self; +} + +unsafe impl<'a> glib::value::FromValue<'a> for RepoInfoType { + type Checker = glib::value::GenericValueTypeChecker; + + #[inline] + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) + } +} + +impl ToValue for RepoInfoType { + #[inline] + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); + } + value + } + + #[inline] + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + +impl From for glib::Value { + #[inline] + fn from(v: RepoInfoType) -> Self { + skip_assert_initialized!(); + ToValue::to_value(&v) + } +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "ZyppRepoManagerError")] +pub enum RepoManagerError { + #[doc(alias = "ZYPP_REPO_MANAGER_ERROR_REF_FAILED")] + Failed, + #[doc(alias = "ZYPP_REPO_MANAGER_ERROR_REF_SKIPPED")] + Skipped, + #[doc(alias = "ZYPP_REPO_MANAGER_ERROR_REF_ABORTED")] + Aborted, +#[doc(hidden)] + __Unknown(i32), +} + +#[doc(hidden)] +impl IntoGlib for RepoManagerError { + type GlibType = ffi::ZyppRepoManagerError; + + #[inline] +fn into_glib(self) -> ffi::ZyppRepoManagerError { +match self { + Self::Failed => ffi::ZYPP_REPO_MANAGER_ERROR_REF_FAILED, + Self::Skipped => ffi::ZYPP_REPO_MANAGER_ERROR_REF_SKIPPED, + Self::Aborted => ffi::ZYPP_REPO_MANAGER_ERROR_REF_ABORTED, + Self::__Unknown(value) => value, +} +} +} + +#[doc(hidden)] +impl FromGlib for RepoManagerError { + #[inline] +unsafe fn from_glib(value: ffi::ZyppRepoManagerError) -> Self { + skip_assert_initialized!(); + +match value { + ffi::ZYPP_REPO_MANAGER_ERROR_REF_FAILED => Self::Failed, + ffi::ZYPP_REPO_MANAGER_ERROR_REF_SKIPPED => Self::Skipped, + ffi::ZYPP_REPO_MANAGER_ERROR_REF_ABORTED => Self::Aborted, + value => Self::__Unknown(value), +} +} +} + +impl glib::error::ErrorDomain for RepoManagerError { + #[inline] + fn domain() -> glib::Quark { + skip_assert_initialized!(); + + unsafe { from_glib(ffi::zypp_repo_manager_error_quark()) } + } + + #[inline] + fn code(self) -> i32 { + self.into_glib() + } + + #[inline] + #[allow(clippy::match_single_binding)] + fn from(code: i32) -> Option { + skip_assert_initialized!(); + match unsafe { from_glib(code) } { + Self::__Unknown(_) => Some(Self::Failed), + value => Some(value), +} + } +} + +impl StaticType for RepoManagerError { + #[inline] + #[doc(alias = "zypp_repo_manager_error_get_type")] + fn static_type() -> glib::Type { + unsafe { from_glib(ffi::zypp_repo_manager_error_get_type()) } + } + } + +impl glib::HasParamSpec for RepoManagerError { + type ParamSpec = glib::ParamSpecEnum; + type SetValue = Self; + type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; + + fn param_spec_builder() -> Self::BuilderFn { + Self::ParamSpec::builder_with_default + } +} + +impl glib::value::ValueType for RepoManagerError { + type Type = Self; +} + +unsafe impl<'a> glib::value::FromValue<'a> for RepoManagerError { + type Checker = glib::value::GenericValueTypeChecker; + + #[inline] + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) + } +} + +impl ToValue for RepoManagerError { + #[inline] + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); + } + value + } + + #[inline] + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + +impl From for glib::Value { + #[inline] + fn from(v: RepoManagerError) -> Self { + skip_assert_initialized!(); + ToValue::to_value(&v) + } +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "ZyppRepoRefreshResult")] +pub enum RepoRefreshResult { + #[doc(alias = "ZYPP_REPO_MANAGER_UP_TO_DATE")] + UpToDate, + #[doc(alias = "ZYPP_REPO_MANAGER_REFRESHED")] + Refreshed, +#[doc(hidden)] + __Unknown(i32), +} + +#[doc(hidden)] +impl IntoGlib for RepoRefreshResult { + type GlibType = ffi::ZyppRepoRefreshResult; + + #[inline] +fn into_glib(self) -> ffi::ZyppRepoRefreshResult { +match self { + Self::UpToDate => ffi::ZYPP_REPO_MANAGER_UP_TO_DATE, + Self::Refreshed => ffi::ZYPP_REPO_MANAGER_REFRESHED, + Self::__Unknown(value) => value, +} +} +} + +#[doc(hidden)] +impl FromGlib for RepoRefreshResult { + #[inline] +unsafe fn from_glib(value: ffi::ZyppRepoRefreshResult) -> Self { + skip_assert_initialized!(); + +match value { + ffi::ZYPP_REPO_MANAGER_UP_TO_DATE => Self::UpToDate, + ffi::ZYPP_REPO_MANAGER_REFRESHED => Self::Refreshed, + value => Self::__Unknown(value), +} +} +} + +impl StaticType for RepoRefreshResult { + #[inline] + #[doc(alias = "zypp_repo_refresh_result_get_type")] + fn static_type() -> glib::Type { + unsafe { from_glib(ffi::zypp_repo_refresh_result_get_type()) } + } + } + +impl glib::HasParamSpec for RepoRefreshResult { + type ParamSpec = glib::ParamSpecEnum; + type SetValue = Self; + type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; + + fn param_spec_builder() -> Self::BuilderFn { + Self::ParamSpec::builder_with_default + } +} + +impl glib::value::ValueType for RepoRefreshResult { + type Type = Self; +} + +unsafe impl<'a> glib::value::FromValue<'a> for RepoRefreshResult { + type Checker = glib::value::GenericValueTypeChecker; + + #[inline] + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) + } +} + +impl ToValue for RepoRefreshResult { + #[inline] + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); + } + value + } + + #[inline] + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + +impl From for glib::Value { + #[inline] + fn from(v: RepoRefreshResult) -> Self { + skip_assert_initialized!(); + ToValue::to_value(&v) + } +} + diff --git a/src/auto/expected.rs b/src/auto/expected.rs new file mode 100644 index 0000000..c5436a7 --- /dev/null +++ b/src/auto/expected.rs @@ -0,0 +1,76 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi}; +use glib::{translate::*}; + +glib::wrapper! { + /// + #[doc(alias = "ZyppExpected")] + pub struct Expected(Object); + + match fn { + type_ => || ffi::zypp_expected_get_type(), + } +} + +impl Expected { + /// Creates a new ZyppExcpected containing a error + #[doc(alias = "zypp_expected_new_error")] + pub fn new_error(error: &mut glib::Error) -> Expected { + assert_initialized_main_thread!(); + unsafe { + from_glib_full(ffi::zypp_expected_new_error(error.to_glib_none_mut().0)) + } + } + + /// Creates a new ZyppExcpected containing a value + #[doc(alias = "zypp_expected_new_value")] + pub fn new_value(value: &glib::Value) -> Expected { + assert_initialized_main_thread!(); + unsafe { + from_glib_full(ffi::zypp_expected_new_value(value.to_glib_none().0)) + } + } + + /// + /// # Returns + /// + /// The error or NULL if there is no error + #[doc(alias = "zypp_expected_get_error")] + #[doc(alias = "get_error")] + pub fn error(&self) -> Option { + unsafe { + from_glib_none(ffi::zypp_expected_get_error(self.to_glib_none().0)) + } + } + + /// + /// # Returns + /// + /// The value or NULL if there is none or a error + #[doc(alias = "zypp_expected_get_value")] + #[doc(alias = "get_value")] + pub fn value(&self) -> Result, glib::Error> { + unsafe { + let mut error = std::ptr::null_mut(); + let ret = ffi::zypp_expected_get_value(self.to_glib_none().0, &mut error); + if error.is_null() { Ok(from_glib_none(ret)) } else { Err(from_glib_full(error)) } + } + } + + #[doc(alias = "zypp_expected_has_error")] + pub fn has_error(&self) -> bool { + unsafe { + from_glib(ffi::zypp_expected_has_error(self.to_glib_none().0)) + } + } + + #[doc(alias = "zypp_expected_has_value")] + pub fn has_value(&self) -> bool { + unsafe { + from_glib(ffi::zypp_expected_has_value(self.to_glib_none().0)) + } + } +} diff --git a/src/auto/info_base.rs b/src/auto/info_base.rs new file mode 100644 index 0000000..1fb93bc --- /dev/null +++ b/src/auto/info_base.rs @@ -0,0 +1,132 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi}; +use glib::{prelude::*,translate::*}; + +glib::wrapper! { + #[doc(alias = "ZyppInfoBase")] + pub struct InfoBase(Interface); + + match fn { + type_ => || ffi::zypp_info_base_get_type(), + } +} + +impl InfoBase { + pub const NONE: Option<&'static InfoBase> = None; + +} + +mod sealed { + pub trait Sealed {} + impl> Sealed for T {} +} + +/// Trait containing all [`struct@InfoBase`] methods. +/// +/// # Implementors +/// +/// [`InfoBase`][struct@crate::InfoBase], [`RepoInfo`][struct@crate::RepoInfo], [`ServiceInfo`][struct@crate::ServiceInfo] +pub trait InfoBaseExt: IsA + sealed::Sealed + 'static { + #[doc(alias = "zypp_info_base_alias")] + fn alias(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_info_base_alias(self.as_ref().to_glib_none().0)) + } + } + + #[doc(alias = "zypp_info_base_as_user_string")] + fn as_user_string(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_info_base_as_user_string(self.as_ref().to_glib_none().0)) + } + } + + #[doc(alias = "zypp_info_base_autorefresh")] + fn autorefresh(&self) -> bool { + unsafe { + from_glib(ffi::zypp_info_base_autorefresh(self.as_ref().to_glib_none().0)) + } + } + + #[doc(alias = "zypp_info_base_enabled")] + fn enabled(&self) -> bool { + unsafe { + from_glib(ffi::zypp_info_base_enabled(self.as_ref().to_glib_none().0)) + } + } + + #[doc(alias = "zypp_info_base_escaped_alias")] + fn escaped_alias(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_info_base_escaped_alias(self.as_ref().to_glib_none().0)) + } + } + + #[doc(alias = "zypp_info_base_filepath")] + fn filepath(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_info_base_filepath(self.as_ref().to_glib_none().0)) + } + } + + #[doc(alias = "zypp_info_base_label")] + fn label(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_info_base_label(self.as_ref().to_glib_none().0)) + } + } + + #[doc(alias = "zypp_info_base_name")] + fn name(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_info_base_name(self.as_ref().to_glib_none().0)) + } + } + + #[doc(alias = "zypp_info_base_raw_name")] + fn raw_name(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_info_base_raw_name(self.as_ref().to_glib_none().0)) + } + } + + #[doc(alias = "zypp_info_base_set_alias")] + fn set_alias(&self, alias: &str) { + unsafe { + ffi::zypp_info_base_set_alias(self.as_ref().to_glib_none().0, alias.to_glib_none().0); + } + } + + #[doc(alias = "zypp_info_base_set_autorefresh")] + fn set_autorefresh(&self, enabled: bool) { + unsafe { + ffi::zypp_info_base_set_autorefresh(self.as_ref().to_glib_none().0, enabled.into_glib()); + } + } + + #[doc(alias = "zypp_info_base_set_enabled")] + fn set_enabled(&self, enabled: bool) { + unsafe { + ffi::zypp_info_base_set_enabled(self.as_ref().to_glib_none().0, enabled.into_glib()); + } + } + + #[doc(alias = "zypp_info_base_set_filepath")] + fn set_filepath(&self, filepath: &str) { + unsafe { + ffi::zypp_info_base_set_filepath(self.as_ref().to_glib_none().0, filepath.to_glib_none().0); + } + } + + #[doc(alias = "zypp_info_base_set_name")] + fn set_name(&self, name: &str) { + unsafe { + ffi::zypp_info_base_set_name(self.as_ref().to_glib_none().0, name.to_glib_none().0); + } + } +} + +impl> InfoBaseExt for O {} diff --git a/src/auto/managed_file.rs b/src/auto/managed_file.rs new file mode 100644 index 0000000..3349bbf --- /dev/null +++ b/src/auto/managed_file.rs @@ -0,0 +1,51 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi}; +use glib::{translate::*}; + +glib::wrapper! { + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct ManagedFile(Boxed); + + match fn { + copy => |ptr| ffi::zypp_managed_file_copy(mut_override(ptr)), + free => |ptr| ffi::zypp_managed_file_free(ptr), + type_ => || ffi::zypp_managed_file_get_type(), + } +} + +impl ManagedFile { + /// ## `path` + /// The path of the file we want to manage + /// ## `dispose` + /// If set to true the file is cleaned up when the [`ManagedFile`][crate::ManagedFile] gets out of scope + #[doc(alias = "zypp_managed_file_new")] + pub fn new(path: &str, dispose: bool) -> ManagedFile { + assert_initialized_main_thread!(); + unsafe { + from_glib_full(ffi::zypp_managed_file_new(path.to_glib_none().0, dispose.into_glib())) + } + } + + /// + /// # Returns + /// + /// The currently managed path + #[doc(alias = "zypp_managed_file_get_path")] + #[doc(alias = "get_path")] + pub fn path(&mut self) -> Option { + unsafe { + from_glib_full(ffi::zypp_managed_file_get_path(self.to_glib_none_mut().0)) + } + } + + /// Enables or disables dispose for this object + #[doc(alias = "zypp_managed_file_set_dispose_enabled")] + pub fn set_dispose_enabled(&mut self, enabled: bool) { + unsafe { + ffi::zypp_managed_file_set_dispose_enabled(self.to_glib_none_mut().0, enabled.into_glib()); + } + } +} diff --git a/src/auto/mod.rs b/src/auto/mod.rs new file mode 100644 index 0000000..74a8d5d --- /dev/null +++ b/src/auto/mod.rs @@ -0,0 +1,49 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +mod context; +pub use self::context::Context; + +mod expected; +pub use self::expected::Expected; + +mod info_base; +pub use self::info_base::InfoBase; + +mod progress_observer; +pub use self::progress_observer::ProgressObserver; + +mod repo_info; +pub use self::repo_info::RepoInfo; + +mod repo_manager; +pub use self::repo_manager::RepoManager; + +mod repository; +pub use self::repository::Repository; + +mod service_info; +pub use self::service_info::ServiceInfo; + +mod managed_file; +pub use self::managed_file::ManagedFile; + +mod repo_manager_options; +pub use self::repo_manager_options::RepoManagerOptions; + +mod enums; +pub use self::enums::Exception; +pub use self::enums::RepoInfoType; +pub use self::enums::RepoManagerError; +pub use self::enums::RepoRefreshResult; + +pub(crate) mod traits { + pub use super::info_base::InfoBaseExt; +} +pub(crate) mod builders { + pub use super::context::ContextBuilder; + pub use super::progress_observer::ProgressObserverBuilder; + pub use super::repo_info::RepoInfoBuilder; + pub use super::repo_manager::RepoManagerBuilder; +} diff --git a/src/auto/progress_observer.rs b/src/auto/progress_observer.rs new file mode 100644 index 0000000..7a2eaba --- /dev/null +++ b/src/auto/progress_observer.rs @@ -0,0 +1,333 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi}; +use glib::{prelude::*,signal::{connect_raw, SignalHandlerId},translate::*}; +use std::{boxed::Box as Box_}; + +glib::wrapper! { + /// + /// + /// ## Properties + /// + /// + /// #### `base-steps` + /// Readable | Writeable + /// + /// + /// #### `label` + /// Readable | Writeable + /// + /// + /// #### `progress` + /// Readable + /// + /// + /// #### `steps` + /// Readable + /// + /// + /// #### `value` + /// Readable | Writeable + /// + /// + /// #### `zypp-cppObj` + /// Writeable | Construct Only + /// + /// ## Signals + /// + /// + /// #### `finished` + /// + /// + /// + /// #### `new-subtask` + /// + #[doc(alias = "ZyppProgressObserver")] + pub struct ProgressObserver(Object); + + match fn { + type_ => || ffi::zypp_progress_observer_get_type(), + } +} + +impl ProgressObserver { + // rustdoc-stripper-ignore-next + /// Creates a new builder-pattern struct instance to construct [`ProgressObserver`] objects. + /// + /// This method returns an instance of [`ProgressObserverBuilder`](crate::builders::ProgressObserverBuilder) which can be used to create [`ProgressObserver`] objects. + pub fn builder() -> ProgressObserverBuilder { + ProgressObserverBuilder::new() + } + + + /// Registers a subtask as a child to the current one + /// ## `newChild` + /// A reference to the new subtask, the parent takes a reference to it + /// ## `weight` + /// The weight how the subtasks steps should be calculated into the parents percentage + #[doc(alias = "zypp_progress_observer_add_subtask")] + pub fn add_subtask(&self, newChild: &ProgressObserver, weight: f32) { + unsafe { + ffi::zypp_progress_observer_add_subtask(self.to_glib_none().0, newChild.to_glib_none().0, weight); + } + } + + /// + /// # Returns + /// + /// The number of steps for this `ZyppProgressObserver` excluding possible substasks + #[doc(alias = "zypp_progress_observer_get_base_steps")] + #[doc(alias = "get_base_steps")] + #[doc(alias = "base-steps")] + pub fn base_steps(&self) -> i32 { + unsafe { + ffi::zypp_progress_observer_get_base_steps(self.to_glib_none().0) + } + } + + /// + /// # Returns + /// + /// The direct children of this Task + #[doc(alias = "zypp_progress_observer_get_children")] + #[doc(alias = "get_children")] + pub fn children(&self) -> Vec { + unsafe { + FromGlibPtrContainer::from_glib_none(ffi::zypp_progress_observer_get_children(self.to_glib_none().0)) + } + } + + /// + /// # Returns + /// + /// The current effective value of the task progress including subtasks, by default this is 0 + #[doc(alias = "zypp_progress_observer_get_current")] + #[doc(alias = "get_current")] + pub fn current(&self) -> f64 { + unsafe { + ffi::zypp_progress_observer_get_current(self.to_glib_none().0) + } + } + + /// + /// # Returns + /// + /// The task label or NULL if none was set + #[doc(alias = "zypp_progress_observer_get_label")] + #[doc(alias = "get_label")] + pub fn label(&self) -> Option { + unsafe { + from_glib_none(ffi::zypp_progress_observer_get_label(self.to_glib_none().0)) + } + } + + /// + /// # Returns + /// + /// The current percentage value of the task progress including subtasks, by default this is 0 + #[doc(alias = "zypp_progress_observer_get_progress")] + #[doc(alias = "get_progress")] + pub fn progress(&self) -> f64 { + unsafe { + ffi::zypp_progress_observer_get_progress(self.to_glib_none().0) + } + } + + /// + /// # Returns + /// + /// The effective number of steps for this `ZyppProgressObserver` including possible substasks + #[doc(alias = "zypp_progress_observer_get_steps")] + #[doc(alias = "get_steps")] + pub fn steps(&self) -> f64 { + unsafe { + ffi::zypp_progress_observer_get_steps(self.to_glib_none().0) + } + } + + /// Increases the current progress value by the number of given steps + /// ## `increase` + /// Number of steps to increase the value + #[doc(alias = "zypp_progress_observer_inc")] + pub fn inc(&self, increase: i32) { + unsafe { + ffi::zypp_progress_observer_inc(self.to_glib_none().0, increase); + } + } + + /// Changes the currently used nr of expected steps for this `ZyppProgressObserver`, if the given value is less than + /// 0 nothing is changed. + /// ## `stepCount` + /// New number of steps + #[doc(alias = "zypp_progress_observer_set_base_steps")] + #[doc(alias = "base-steps")] + pub fn set_base_steps(&self, stepCount: i32) { + unsafe { + ffi::zypp_progress_observer_set_base_steps(self.to_glib_none().0, stepCount); + } + } + + #[doc(alias = "zypp_progress_observer_set_current")] + pub fn set_current(&self, value: f64) { + unsafe { + ffi::zypp_progress_observer_set_current(self.to_glib_none().0, value); + } + } + + /// Fills the progress and all its children up to 100% and emits the finished signal + #[doc(alias = "zypp_progress_observer_set_finished")] + pub fn set_finished(&self) { + unsafe { + ffi::zypp_progress_observer_set_finished(self.to_glib_none().0); + } + } + + /// Changes the currently used label + /// ## `label` + /// The new label + #[doc(alias = "zypp_progress_observer_set_label")] + #[doc(alias = "label")] + pub fn set_label(&self, label: &str) { + unsafe { + ffi::zypp_progress_observer_set_label(self.to_glib_none().0, label.to_glib_none().0); + } + } + + pub fn value(&self) -> f64 { + ObjectExt::property(self, "value") + } + + pub fn set_value(&self, value: f64) { + ObjectExt::set_property(self,"value", value) + } + + #[doc(alias = "finished")] + pub fn connect_finished(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn finished_trampoline(this: *mut ffi::ZyppProgressObserver, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"finished\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(finished_trampoline:: as *const ())), Box_::into_raw(f)) + } + } + + #[doc(alias = "new-subtask")] + pub fn connect_new_subtask(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn new_subtask_trampoline(this: *mut ffi::ZyppProgressObserver, object: *mut ffi::ZyppProgressObserver, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this), &from_glib_borrow(object)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"new-subtask\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(new_subtask_trampoline:: as *const ())), Box_::into_raw(f)) + } + } + + #[doc(alias = "base-steps")] + pub fn connect_base_steps_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_base_steps_trampoline(this: *mut ffi::ZyppProgressObserver, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::base-steps\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_base_steps_trampoline:: as *const ())), Box_::into_raw(f)) + } + } + + #[doc(alias = "label")] + pub fn connect_label_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_label_trampoline(this: *mut ffi::ZyppProgressObserver, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::label\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_label_trampoline:: as *const ())), Box_::into_raw(f)) + } + } + + #[doc(alias = "progress")] + pub fn connect_progress_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_progress_trampoline(this: *mut ffi::ZyppProgressObserver, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::progress\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_progress_trampoline:: as *const ())), Box_::into_raw(f)) + } + } + + #[doc(alias = "steps")] + pub fn connect_steps_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_steps_trampoline(this: *mut ffi::ZyppProgressObserver, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::steps\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_steps_trampoline:: as *const ())), Box_::into_raw(f)) + } + } + + #[doc(alias = "value")] + pub fn connect_value_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_value_trampoline(this: *mut ffi::ZyppProgressObserver, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::value\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_value_trampoline:: as *const ())), Box_::into_raw(f)) + } + } +} + +// rustdoc-stripper-ignore-next + /// A [builder-pattern] type to construct [`ProgressObserver`] objects. + /// + /// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html +#[must_use = "The builder must be built to be used"] +pub struct ProgressObserverBuilder { + builder: glib::object::ObjectBuilder<'static, ProgressObserver>, + } + + impl ProgressObserverBuilder { + fn new() -> Self { + Self { builder: glib::object::Object::builder() } + } + + pub fn base_steps(self, base_steps: i32) -> Self { + Self { builder: self.builder.property("base-steps", base_steps), } + } + + pub fn label(self, label: impl Into) -> Self { + Self { builder: self.builder.property("label", label.into()), } + } + + pub fn value(self, value: f64) -> Self { + Self { builder: self.builder.property("value", value), } + } + + //pub fn zypp_cppObj(self, zypp_cppObj: /*Unimplemented*/Basic: Pointer) -> Self { + // Self { builder: self.builder.property("zypp-cppObj", zypp_cppObj), } + //} + + // rustdoc-stripper-ignore-next + /// Build the [`ProgressObserver`]. + #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"] + pub fn build(self) -> ProgressObserver { + self.builder.build() } +} diff --git a/src/auto/repo_info.rs b/src/auto/repo_info.rs new file mode 100644 index 0000000..7a284f4 --- /dev/null +++ b/src/auto/repo_info.rs @@ -0,0 +1,160 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi,Context,InfoBase,RepoInfoType}; +use glib::{prelude::*,signal::{connect_raw, SignalHandlerId},translate::*}; +use std::{boxed::Box as Box_}; + +glib::wrapper! { + /// + /// + /// ## Properties + /// + /// + /// #### `alias` + /// Readable | Writeable + /// + /// + /// #### `enabled` + /// Readable | Writeable + /// + /// + /// #### `name` + /// Readable | Writeable + /// + /// + /// #### `zypp-cppObj` + /// Writeable | Construct Only + /// + /// + /// #### `zyppcontext` + /// Writeable | Construct Only + /// + /// # Implements + /// + /// [`InfoBaseExt`][trait@crate::prelude::InfoBaseExt] + #[doc(alias = "ZyppRepoInfo")] + pub struct RepoInfo(Object) @implements InfoBase; + + match fn { + type_ => || ffi::zypp_repo_info_get_type(), + } +} + +impl RepoInfo { + #[doc(alias = "zypp_repo_info_new")] + pub fn new(context: &Context) -> RepoInfo { + skip_assert_initialized!(); + unsafe { + from_glib_full(ffi::zypp_repo_info_new(context.to_glib_none().0)) + } + } + + // rustdoc-stripper-ignore-next + /// Creates a new builder-pattern struct instance to construct [`RepoInfo`] objects. + /// + /// This method returns an instance of [`RepoInfoBuilder`](crate::builders::RepoInfoBuilder) which can be used to create [`RepoInfo`] objects. + pub fn builder() -> RepoInfoBuilder { + RepoInfoBuilder::new() + } + + + /// + /// # Returns + /// + /// The type of repository + #[doc(alias = "zypp_repo_info_get_repo_type")] + #[doc(alias = "get_repo_type")] + pub fn repo_type(&self) -> RepoInfoType { + unsafe { + from_glib(ffi::zypp_repo_info_get_repo_type(self.to_glib_none().0)) + } + } + + #[doc(alias = "alias")] + pub fn connect_alias_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_alias_trampoline(this: *mut ffi::ZyppRepoInfo, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::alias\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_alias_trampoline:: as *const ())), Box_::into_raw(f)) + } + } + + #[doc(alias = "enabled")] + pub fn connect_enabled_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_enabled_trampoline(this: *mut ffi::ZyppRepoInfo, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::enabled\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_enabled_trampoline:: as *const ())), Box_::into_raw(f)) + } + } + + #[doc(alias = "name")] + pub fn connect_name_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_name_trampoline(this: *mut ffi::ZyppRepoInfo, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::name\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_name_trampoline:: as *const ())), Box_::into_raw(f)) + } + } +} + +impl Default for RepoInfo { + fn default() -> Self { + glib::object::Object::new::() + } + } + +// rustdoc-stripper-ignore-next + /// A [builder-pattern] type to construct [`RepoInfo`] objects. + /// + /// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html +#[must_use = "The builder must be built to be used"] +pub struct RepoInfoBuilder { + builder: glib::object::ObjectBuilder<'static, RepoInfo>, + } + + impl RepoInfoBuilder { + fn new() -> Self { + Self { builder: glib::object::Object::builder() } + } + + pub fn alias(self, alias: impl Into) -> Self { + Self { builder: self.builder.property("alias", alias.into()), } + } + + pub fn enabled(self, enabled: bool) -> Self { + Self { builder: self.builder.property("enabled", enabled), } + } + + pub fn name(self, name: impl Into) -> Self { + Self { builder: self.builder.property("name", name.into()), } + } + + //pub fn zypp_cppObj(self, zypp_cppObj: /*Unimplemented*/Basic: Pointer) -> Self { + // Self { builder: self.builder.property("zypp-cppObj", zypp_cppObj), } + //} + + pub fn zyppcontext(self, zyppcontext: &Context) -> Self { + Self { builder: self.builder.property("zyppcontext", zyppcontext.clone()), } + } + + // rustdoc-stripper-ignore-next + /// Build the [`RepoInfo`]. + #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"] + pub fn build(self) -> RepoInfo { + self.builder.build() } +} diff --git a/src/auto/repo_manager.rs b/src/auto/repo_manager.rs new file mode 100644 index 0000000..6f880b1 --- /dev/null +++ b/src/auto/repo_manager.rs @@ -0,0 +1,174 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi,Context,Expected,ProgressObserver,RepoInfo,RepoManagerOptions,ServiceInfo}; +use glib::{prelude::*,signal::{connect_raw, SignalHandlerId},translate::*}; +use std::{boxed::Box as Box_}; + +glib::wrapper! { + /// + /// + /// ## Properties + /// + /// + /// #### `options` + /// Readable | Writeable | Construct + /// + /// + /// #### `zypp-cppObj` + /// Writeable | Construct Only + /// + /// + /// #### `zyppcontext` + /// Writeable | Construct Only + #[doc(alias = "ZyppRepoManager")] + pub struct RepoManager(Object); + + match fn { + type_ => || ffi::zypp_repo_manager_get_type(), + } +} + +impl RepoManager { + /// ## `ctx` + /// The [`Context`][crate::Context] the RepoManager should operate on + /// + /// # Returns + /// + /// newly created [`RepoManager`][crate::RepoManager] + #[doc(alias = "zypp_repo_manager_new")] + pub fn new(ctx: &Context) -> RepoManager { + skip_assert_initialized!(); + unsafe { + from_glib_full(ffi::zypp_repo_manager_new(ctx.to_glib_none().0)) + } + } + + // rustdoc-stripper-ignore-next + /// Creates a new builder-pattern struct instance to construct [`RepoManager`] objects. + /// + /// This method returns an instance of [`RepoManagerBuilder`](crate::builders::RepoManagerBuilder) which can be used to create [`RepoManager`] objects. + pub fn builder() -> RepoManagerBuilder { + RepoManagerBuilder::new() + } + + + /// + /// # Returns + /// + /// list of repositories, + /// free the list with g_list_free and the elements with gobject_unref when done. + #[doc(alias = "zypp_repo_manager_get_known_repos")] + #[doc(alias = "get_known_repos")] + pub fn known_repos(&self) -> Vec { + unsafe { + FromGlibPtrContainer::from_glib_full(ffi::zypp_repo_manager_get_known_repos(self.to_glib_none().0)) + } + } + + /// + /// # Returns + /// + /// list of existing services, + /// free the list with g_list_free and the elements with gobject_unref when done. + #[doc(alias = "zypp_repo_manager_get_known_services")] + #[doc(alias = "get_known_services")] + pub fn known_services(&self) -> Vec { + unsafe { + FromGlibPtrContainer::from_glib_full(ffi::zypp_repo_manager_get_known_services(self.to_glib_none().0)) + } + } + + /// Loads the known repositories and services. + /// + /// # Returns + /// + /// True if init was successful, otherwise returns false and sets the error + #[doc(alias = "zypp_repo_manager_initialize")] + pub fn initialize(&self) -> Result<(), glib::Error> { + unsafe { + let mut error = std::ptr::null_mut(); + let is_ok = ffi::zypp_repo_manager_initialize(self.to_glib_none().0, &mut error); + debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null()); + if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } + } + } + + /// ## `repos` + /// the repositories to refresh + /// ## `forceDownload` + /// Force downloading the repository even if its up 2 date + /// ## `statusTracker` + /// Progress tracker + /// + /// # Returns + /// + /// list of results for the refreshed repos + #[doc(alias = "zypp_repo_manager_refresh_repos")] + pub fn refresh_repos(&self, repos: &[RepoInfo], forceDownload: bool, statusTracker: Option) -> Vec { + unsafe { + FromGlibPtrContainer::from_glib_full(ffi::zypp_repo_manager_refresh_repos(self.to_glib_none().0, repos.to_glib_none().0, forceDownload.into_glib(), statusTracker.into_glib_ptr())) + } + } + + pub fn options(&self) -> Option { + ObjectExt::property(self, "options") + } + + pub fn set_options(&self, options: Option<&RepoManagerOptions>) { + ObjectExt::set_property(self,"options", options) + } + + #[doc(alias = "options")] + pub fn connect_options_notify(&self, f: F) -> SignalHandlerId { + unsafe extern "C" fn notify_options_trampoline(this: *mut ffi::ZyppRepoManager, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer) { + let f: &F = &*(f as *const F); + f(&from_glib_borrow(this)) + } + unsafe { + let f: Box_ = Box_::new(f); + connect_raw(self.as_ptr() as *mut _, b"notify::options\0".as_ptr() as *const _, + Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(notify_options_trampoline:: as *const ())), Box_::into_raw(f)) + } + } +} + +impl Default for RepoManager { + fn default() -> Self { + glib::object::Object::new::() + } + } + +// rustdoc-stripper-ignore-next + /// A [builder-pattern] type to construct [`RepoManager`] objects. + /// + /// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html +#[must_use = "The builder must be built to be used"] +pub struct RepoManagerBuilder { + builder: glib::object::ObjectBuilder<'static, RepoManager>, + } + + impl RepoManagerBuilder { + fn new() -> Self { + Self { builder: glib::object::Object::builder() } + } + + pub fn options(self, options: &RepoManagerOptions) -> Self { + Self { builder: self.builder.property("options", options), } + } + + //pub fn zypp_cppObj(self, zypp_cppObj: /*Unimplemented*/Basic: Pointer) -> Self { + // Self { builder: self.builder.property("zypp-cppObj", zypp_cppObj), } + //} + + pub fn zyppcontext(self, zyppcontext: &Context) -> Self { + Self { builder: self.builder.property("zyppcontext", zyppcontext.clone()), } + } + + // rustdoc-stripper-ignore-next + /// Build the [`RepoManager`]. + #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"] + pub fn build(self) -> RepoManager { + self.builder.build() } +} diff --git a/src/auto/repo_manager_options.rs b/src/auto/repo_manager_options.rs new file mode 100644 index 0000000..38a69ed --- /dev/null +++ b/src/auto/repo_manager_options.rs @@ -0,0 +1,45 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi}; +use glib::{translate::*}; + +glib::wrapper! { + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct RepoManagerOptions(Boxed); + + match fn { + copy => |ptr| ffi::zypp_repo_manager_options_copy(mut_override(ptr)), + free => |ptr| ffi::zypp_repo_manager_options_free(ptr), + type_ => || ffi::zypp_repo_manager_options_get_type(), + } +} + +impl RepoManagerOptions { + /// ## `root` + /// The prefix for all paths + /// + /// # Returns + /// + /// newly created [`RepoManagerOptions`][crate::RepoManagerOptions] + #[doc(alias = "zypp_repo_manager_options_new")] + pub fn new(root: &str) -> RepoManagerOptions { + assert_initialized_main_thread!(); + unsafe { + from_glib_full(ffi::zypp_repo_manager_options_new(root.to_glib_none().0)) + } + } + + /// + /// # Returns + /// + /// The currently managed path + #[doc(alias = "zypp_repo_manager_options_get_root")] + #[doc(alias = "get_root")] + pub fn root(&mut self) -> Option { + unsafe { + from_glib_full(ffi::zypp_repo_manager_options_get_root(self.to_glib_none_mut().0)) + } + } +} diff --git a/src/auto/repository.rs b/src/auto/repository.rs new file mode 100644 index 0000000..3c81afe --- /dev/null +++ b/src/auto/repository.rs @@ -0,0 +1,42 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi,RepoInfo}; +use glib::{translate::*}; + +glib::wrapper! { + /// + #[doc(alias = "ZyppRepository")] + pub struct Repository(Object); + + match fn { + type_ => || ffi::zypp_repository_get_type(), + } +} + +impl Repository { + /// + /// # Returns + /// + /// Name of the repository + #[doc(alias = "zypp_repository_get_name")] + #[doc(alias = "get_name")] + pub fn name(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_repository_get_name(self.to_glib_none().0)) + } + } + + /// + /// # Returns + /// + /// The corresponding ZyppRepoInfo + #[doc(alias = "zypp_repository_get_repoinfo")] + #[doc(alias = "get_repoinfo")] + pub fn repoinfo(&self) -> Option { + unsafe { + from_glib_full(ffi::zypp_repository_get_repoinfo(self.to_glib_none().0)) + } + } +} diff --git a/src/auto/service_info.rs b/src/auto/service_info.rs new file mode 100644 index 0000000..49c7833 --- /dev/null +++ b/src/auto/service_info.rs @@ -0,0 +1,30 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files +// DO NOT EDIT + +use crate::{ffi,Context,InfoBase}; +use glib::{translate::*}; + +glib::wrapper! { + /// + /// + /// # Implements + /// + /// [`InfoBaseExt`][trait@crate::prelude::InfoBaseExt] + #[doc(alias = "ZyppServiceInfo")] + pub struct ServiceInfo(Object) @implements InfoBase; + + match fn { + type_ => || ffi::zypp_service_info_get_type(), + } +} + +impl ServiceInfo { + #[doc(alias = "zypp_service_info_new")] + pub fn new(context: &Context) -> ServiceInfo { + skip_assert_initialized!(); + unsafe { + from_glib_full(ffi::zypp_service_info_new(context.to_glib_none().0)) + } + } +} diff --git a/src/auto/versions.txt b/src/auto/versions.txt new file mode 100644 index 0000000..c88a14e --- /dev/null +++ b/src/auto/versions.txt @@ -0,0 +1,2 @@ +Generated by gir (https://github.com/gtk-rs/gir @ 06c4f1963c55+) +from gir-files (@ ???) diff --git a/src/bin.rs b/src/bin.rs new file mode 100644 index 0000000..d7c3c37 --- /dev/null +++ b/src/bin.rs @@ -0,0 +1,44 @@ +use std::process::exit; + +use glib::Error; +use libzypp::InfoBaseExt; + +fn print_system() -> Result<(), Error> { + println!("System repos:"); + print_with_root("/")?; + println!(""); + Ok(()) +} + +fn print_host() -> Result<(), Error> { + println!("Host repos:"); + print_with_root("/run/host")?; + println!(""); + Ok(()) +} + +fn print_with_root(root: &str) -> Result<(), Error> { + let context = libzypp::Context::builder().build(); + context.load_system(Some(root))?; + + let repo_manager = libzypp::RepoManager::new(&context); + repo_manager.initialize()?; + + for repo in repo_manager.known_repos() { + println!("{:?}", repo.name()); + } + + Ok(()) +} + +fn main() -> () { + if let Err(err) = print_system() { + println!("Failed to system: {}", err.to_string()); + exit(1); + } + + if let Err(err) = print_host() { + println!("Failed to system: {}", err.to_string()); + exit(1); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2913e2b --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,18 @@ +#![cfg_attr(docsrs, feature(doc_cfg))] + +use ffi; + +/// No-op. +macro_rules! skip_assert_initialized { + () => {}; +} + +macro_rules! assert_initialized_main_thread { + () => { + // TODO: check how to verify that library is initialized + }; +} + +pub use auto::*; +mod auto; +pub use auto::traits::*; diff --git a/zypp-sys/Cargo.toml b/zypp-sys/Cargo.toml new file mode 100644 index 0000000..d9e752b --- /dev/null +++ b/zypp-sys/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "zypp-sys" +version = "0.0.1" +edition = "2021" +build = "build.rs" + +[package.metadata.system-deps.glib_2_0] +name = "glib-2.0" +version = "1" + +[package.metadata.docs.rs] +rustc-args = ["--cfg", "docsrs"] +rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] +all-features = true + +[lib] +name = "zypp_sys" + +[dependencies] +libc = "0.2" + +[dependencies.glib-sys] +git = "https://github.com/gtk-rs/gtk-rs-core" + +[dependencies.gobject-sys] +git = "https://github.com/gtk-rs/gtk-rs-core" + +[build-dependencies] +system-deps = "7" + +[dev-dependencies] +shell-words = "1.0.0" +tempfile = "3" + +[features] diff --git a/zypp-sys/Gir.toml b/zypp-sys/Gir.toml new file mode 100644 index 0000000..ceddcc4 --- /dev/null +++ b/zypp-sys/Gir.toml @@ -0,0 +1,13 @@ +[options] +library = "Zypp" +version = "1.0" +min_cfg_version = "1.0" +target_path = "." +girs_directories = ["../gir-files/", "../libzypp/build/zypp-glib"] +work_mode = "sys" +single_version_file = true + +external_libraries = [ + "GLib", + "GObject", +] diff --git a/zypp-sys/build.rs b/zypp-sys/build.rs new file mode 100644 index 0000000..122c811 --- /dev/null +++ b/zypp-sys/build.rs @@ -0,0 +1,18 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from ../gir-files +// from ../libzypp/build/zypp-glib +// DO NOT EDIT + +#[cfg(not(docsrs))] +use std::process; + +#[cfg(docsrs)] +fn main() {} // prevent linking libraries to avoid documentation failure + +#[cfg(not(docsrs))] +fn main() { + if let Err(s) = system_deps::Config::new().probe() { + println!("cargo:warning={s}"); + process::exit(1); + } +} diff --git a/zypp-sys/src/auto/versions.txt b/zypp-sys/src/auto/versions.txt new file mode 100644 index 0000000..b396a2b --- /dev/null +++ b/zypp-sys/src/auto/versions.txt @@ -0,0 +1,2 @@ +Generated by gir (https://github.com/gtk-rs/gir @ 06c4f1963c55+) +from ../gir-files (@ ???) diff --git a/zypp-sys/src/lib.rs b/zypp-sys/src/lib.rs new file mode 100644 index 0000000..8231ca1 --- /dev/null +++ b/zypp-sys/src/lib.rs @@ -0,0 +1,454 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from ../gir-files +// DO NOT EDIT + +#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] +#![allow(clippy::approx_constant, clippy::type_complexity, clippy::unreadable_literal, clippy::upper_case_acronyms)] +#![cfg_attr(docsrs, feature(doc_cfg))] + +use glib_sys as glib; +use gobject_sys as gobject; + +#[allow(unused_imports)] +use libc::{c_int, c_char, c_uchar, c_float, c_uint, c_double, + c_short, c_ushort, c_long, c_ulong, + c_void, size_t, ssize_t, time_t, off_t, intptr_t, uintptr_t, FILE}; +#[cfg(unix)] +#[allow(unused_imports)] +use libc::{dev_t, gid_t, pid_t, socklen_t, uid_t}; + +#[allow(unused_imports)] +use glib::{gboolean, gconstpointer, gpointer, GType}; + +// Enums +pub type ZyppException = c_int; +pub const ZYPP_ERROR: ZyppException = 0; + +pub type ZyppRepoInfoType = c_int; +pub const ZYPP_REPO_NONE: ZyppRepoInfoType = 0; +pub const ZYPP_REPO_RPMMD: ZyppRepoInfoType = 1; +pub const ZYPP_REPO_YAST2: ZyppRepoInfoType = 2; +pub const ZYPP_REPO_RPMPLAINDIR: ZyppRepoInfoType = 3; + +pub type ZyppRepoManagerError = c_int; +pub const ZYPP_REPO_MANAGER_ERROR_REF_FAILED: ZyppRepoManagerError = 0; +pub const ZYPP_REPO_MANAGER_ERROR_REF_SKIPPED: ZyppRepoManagerError = 1; +pub const ZYPP_REPO_MANAGER_ERROR_REF_ABORTED: ZyppRepoManagerError = 2; + +pub type ZyppRepoRefreshResult = c_int; +pub const ZYPP_REPO_MANAGER_UP_TO_DATE: ZyppRepoRefreshResult = 0; +pub const ZYPP_REPO_MANAGER_REFRESHED: ZyppRepoRefreshResult = 1; + +// Records +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ZyppContextClass { + pub parent_class: gobject::GObjectClass, +} + +impl ::std::fmt::Debug for ZyppContextClass { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppContextClass @ {self:p}")) + .field("parent_class", &self.parent_class) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ZyppExpectedClass { + pub parent_class: gobject::GObjectClass, +} + +impl ::std::fmt::Debug for ZyppExpectedClass { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppExpectedClass @ {self:p}")) + .field("parent_class", &self.parent_class) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ZyppInfoBaseInterface { + pub parent_iface: gobject::GTypeInterface, + pub alias: Option *mut c_char>, + pub escaped_alias: Option *mut c_char>, + pub name: Option *mut c_char>, + pub raw_name: Option *mut c_char>, + pub label: Option *mut c_char>, + pub as_user_string: Option *mut c_char>, + pub enabled: Option gboolean>, + pub autorefresh: Option gboolean>, + pub filepath: Option *mut c_char>, + pub set_alias: Option, + pub set_name: Option, + pub set_enabled: Option, + pub set_autorefresh: Option, + pub set_filepath: Option, +} + +impl ::std::fmt::Debug for ZyppInfoBaseInterface { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppInfoBaseInterface @ {self:p}")) + .field("parent_iface", &self.parent_iface) + .field("alias", &self.alias) + .field("escaped_alias", &self.escaped_alias) + .field("name", &self.name) + .field("raw_name", &self.raw_name) + .field("label", &self.label) + .field("as_user_string", &self.as_user_string) + .field("enabled", &self.enabled) + .field("autorefresh", &self.autorefresh) + .field("filepath", &self.filepath) + .field("set_alias", &self.set_alias) + .field("set_name", &self.set_name) + .field("set_enabled", &self.set_enabled) + .field("set_autorefresh", &self.set_autorefresh) + .field("set_filepath", &self.set_filepath) + .finish() + } +} + +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppManagedFile { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppManagedFile { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppManagedFile @ {self:p}")) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ZyppProgressObserverClass { + pub parent_class: gobject::GObjectClass, +} + +impl ::std::fmt::Debug for ZyppProgressObserverClass { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppProgressObserverClass @ {self:p}")) + .field("parent_class", &self.parent_class) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ZyppRepoInfoClass { + pub parent_class: gobject::GObjectClass, +} + +impl ::std::fmt::Debug for ZyppRepoInfoClass { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppRepoInfoClass @ {self:p}")) + .field("parent_class", &self.parent_class) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ZyppRepoManagerClass { + pub parent_class: gobject::GObjectClass, +} + +impl ::std::fmt::Debug for ZyppRepoManagerClass { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppRepoManagerClass @ {self:p}")) + .field("parent_class", &self.parent_class) + .finish() + } +} + +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppRepoManagerOptions { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppRepoManagerOptions { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppRepoManagerOptions @ {self:p}")) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ZyppRepositoryClass { + pub parent_class: gobject::GObjectClass, +} + +impl ::std::fmt::Debug for ZyppRepositoryClass { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppRepositoryClass @ {self:p}")) + .field("parent_class", &self.parent_class) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct ZyppServiceInfoClass { + pub parent_class: gobject::GObjectClass, +} + +impl ::std::fmt::Debug for ZyppServiceInfoClass { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppServiceInfoClass @ {self:p}")) + .field("parent_class", &self.parent_class) + .finish() + } +} + +// Classes +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppContext { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppContext { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppContext @ {self:p}")) + .finish() + } +} + +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppExpected { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppExpected { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppExpected @ {self:p}")) + .finish() + } +} + +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppProgressObserver { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppProgressObserver { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppProgressObserver @ {self:p}")) + .finish() + } +} + +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppRepoInfo { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppRepoInfo { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppRepoInfo @ {self:p}")) + .finish() + } +} + +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppRepoManager { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppRepoManager { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppRepoManager @ {self:p}")) + .finish() + } +} + +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppRepository { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppRepository { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppRepository @ {self:p}")) + .finish() + } +} + +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppServiceInfo { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppServiceInfo { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("ZyppServiceInfo @ {self:p}")) + .finish() + } +} + +// Interfaces +#[repr(C)] +#[allow(dead_code)] +pub struct ZyppInfoBase { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +impl ::std::fmt::Debug for ZyppInfoBase { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "ZyppInfoBase @ {self:p}") + } +} + + +#[link(name = "zypp-glib")] +extern "C" { + + //========================================================================= + // ZyppException + //========================================================================= + pub fn zypp_exception_get_type() -> GType; + pub fn zypp_exception_quark() -> glib::GQuark; + + //========================================================================= + // ZyppRepoInfoType + //========================================================================= + pub fn zypp_repo_info_type_get_type() -> GType; + + //========================================================================= + // ZyppRepoManagerError + //========================================================================= + pub fn zypp_repo_manager_error_get_type() -> GType; + pub fn zypp_repo_manager_error_quark() -> glib::GQuark; + + //========================================================================= + // ZyppRepoRefreshResult + //========================================================================= + pub fn zypp_repo_refresh_result_get_type() -> GType; + + //========================================================================= + // ZyppManagedFile + //========================================================================= + pub fn zypp_managed_file_get_type() -> GType; + pub fn zypp_managed_file_new(path: *const c_char, dispose: gboolean) -> *mut ZyppManagedFile; + pub fn zypp_managed_file_copy(r: *mut ZyppManagedFile) -> *mut ZyppManagedFile; + pub fn zypp_managed_file_free(r: *mut ZyppManagedFile); + pub fn zypp_managed_file_get_path(self_: *mut ZyppManagedFile) -> *mut c_char; + pub fn zypp_managed_file_set_dispose_enabled(self_: *mut ZyppManagedFile, enabled: gboolean); + + //========================================================================= + // ZyppRepoManagerOptions + //========================================================================= + pub fn zypp_repo_manager_options_get_type() -> GType; + pub fn zypp_repo_manager_options_new(root: *const c_char) -> *mut ZyppRepoManagerOptions; + pub fn zypp_repo_manager_options_copy(self_: *mut ZyppRepoManagerOptions) -> *mut ZyppRepoManagerOptions; + pub fn zypp_repo_manager_options_free(self_: *mut ZyppRepoManagerOptions); + pub fn zypp_repo_manager_options_get_root(self_: *mut ZyppRepoManagerOptions) -> *mut c_char; + + //========================================================================= + // ZyppContext + //========================================================================= + pub fn zypp_context_get_type() -> GType; + pub fn zypp_context_load_system(self_: *mut ZyppContext, sysRoot: *const c_char, error: *mut *mut glib::GError) -> gboolean; + pub fn zypp_context_sysroot(self_: *mut ZyppContext) -> *mut c_char; + pub fn zypp_context_version(self_: *mut ZyppContext) -> *const c_char; + + //========================================================================= + // ZyppExpected + //========================================================================= + pub fn zypp_expected_get_type() -> GType; + pub fn zypp_expected_new_error(error: *mut glib::GError) -> *mut ZyppExpected; + pub fn zypp_expected_new_value(value: *const gobject::GValue) -> *mut ZyppExpected; + pub fn zypp_expected_get_error(self_: *mut ZyppExpected) -> *const glib::GError; + pub fn zypp_expected_get_value(self_: *mut ZyppExpected, error: *mut *mut glib::GError) -> *const gobject::GValue; + pub fn zypp_expected_has_error(self_: *mut ZyppExpected) -> gboolean; + pub fn zypp_expected_has_value(self_: *mut ZyppExpected) -> gboolean; + + //========================================================================= + // ZyppProgressObserver + //========================================================================= + pub fn zypp_progress_observer_get_type() -> GType; + pub fn zypp_progress_observer_add_subtask(self_: *mut ZyppProgressObserver, newChild: *mut ZyppProgressObserver, weight: c_float); + pub fn zypp_progress_observer_get_base_steps(self_: *mut ZyppProgressObserver) -> c_int; + pub fn zypp_progress_observer_get_children(self_: *mut ZyppProgressObserver) -> *const glib::GList; + pub fn zypp_progress_observer_get_current(self_: *mut ZyppProgressObserver) -> c_double; + pub fn zypp_progress_observer_get_label(self_: *mut ZyppProgressObserver) -> *const c_char; + pub fn zypp_progress_observer_get_progress(self_: *mut ZyppProgressObserver) -> c_double; + pub fn zypp_progress_observer_get_steps(self_: *mut ZyppProgressObserver) -> c_double; + pub fn zypp_progress_observer_inc(self_: *mut ZyppProgressObserver, increase: c_int); + pub fn zypp_progress_observer_set_base_steps(self_: *mut ZyppProgressObserver, stepCount: c_int); + pub fn zypp_progress_observer_set_current(self_: *mut ZyppProgressObserver, value: c_double); + pub fn zypp_progress_observer_set_finished(self_: *mut ZyppProgressObserver); + pub fn zypp_progress_observer_set_label(self_: *mut ZyppProgressObserver, label: *const c_char); + + //========================================================================= + // ZyppRepoInfo + //========================================================================= + pub fn zypp_repo_info_get_type() -> GType; + pub fn zypp_repo_info_new(context: *mut ZyppContext) -> *mut ZyppRepoInfo; + pub fn zypp_repo_info_get_repo_type(self_: *mut ZyppRepoInfo) -> ZyppRepoInfoType; + + //========================================================================= + // ZyppRepoManager + //========================================================================= + pub fn zypp_repo_manager_get_type() -> GType; + pub fn zypp_repo_manager_new(ctx: *mut ZyppContext) -> *mut ZyppRepoManager; + pub fn zypp_repo_manager_get_known_repos(self_: *mut ZyppRepoManager) -> *mut glib::GList; + pub fn zypp_repo_manager_get_known_services(self_: *mut ZyppRepoManager) -> *mut glib::GList; + pub fn zypp_repo_manager_initialize(self_: *mut ZyppRepoManager, error: *mut *mut glib::GError) -> gboolean; + pub fn zypp_repo_manager_refresh_repos(self_: *mut ZyppRepoManager, repos: *mut glib::GList, forceDownload: gboolean, statusTracker: *mut ZyppProgressObserver) -> *mut glib::GList; + + //========================================================================= + // ZyppRepository + //========================================================================= + pub fn zypp_repository_get_type() -> GType; + pub fn zypp_repository_get_name(self_: *mut ZyppRepository) -> *mut c_char; + pub fn zypp_repository_get_repoinfo(self_: *mut ZyppRepository) -> *mut ZyppRepoInfo; + + //========================================================================= + // ZyppServiceInfo + //========================================================================= + pub fn zypp_service_info_get_type() -> GType; + pub fn zypp_service_info_new(context: *mut ZyppContext) -> *mut ZyppServiceInfo; + + //========================================================================= + // ZyppInfoBase + //========================================================================= + pub fn zypp_info_base_get_type() -> GType; + pub fn zypp_info_base_alias(self_: *mut ZyppInfoBase) -> *mut c_char; + pub fn zypp_info_base_as_user_string(self_: *mut ZyppInfoBase) -> *mut c_char; + pub fn zypp_info_base_autorefresh(self_: *mut ZyppInfoBase) -> gboolean; + pub fn zypp_info_base_enabled(self_: *mut ZyppInfoBase) -> gboolean; + pub fn zypp_info_base_escaped_alias(self_: *mut ZyppInfoBase) -> *mut c_char; + pub fn zypp_info_base_filepath(self_: *mut ZyppInfoBase) -> *mut c_char; + pub fn zypp_info_base_label(self_: *mut ZyppInfoBase) -> *mut c_char; + pub fn zypp_info_base_name(self_: *mut ZyppInfoBase) -> *mut c_char; + pub fn zypp_info_base_raw_name(self_: *mut ZyppInfoBase) -> *mut c_char; + pub fn zypp_info_base_set_alias(self_: *mut ZyppInfoBase, alias: *const c_char); + pub fn zypp_info_base_set_autorefresh(self_: *mut ZyppInfoBase, enabled: gboolean); + pub fn zypp_info_base_set_enabled(self_: *mut ZyppInfoBase, enabled: gboolean); + pub fn zypp_info_base_set_filepath(self_: *mut ZyppInfoBase, filepath: *const c_char); + pub fn zypp_info_base_set_name(self_: *mut ZyppInfoBase, name: *const c_char); + +} diff --git a/zypp-sys/tests/abi.rs b/zypp-sys/tests/abi.rs new file mode 100644 index 0000000..87665b7 --- /dev/null +++ b/zypp-sys/tests/abi.rs @@ -0,0 +1,236 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from ../gir-files +// DO NOT EDIT + +#![cfg(unix)] + +use zypp_sys::*; +use std::mem::{align_of, size_of}; +use std::env; +use std::error::Error; +use std::ffi::OsString; +use std::path::Path; +use std::process::{Command, Stdio}; +use std::str; +use tempfile::Builder; + +static PACKAGES: &[&str] = &["glib-2.0", "gobject-2.0"]; + +#[derive(Clone, Debug)] +struct Compiler { + pub args: Vec, +} + +impl Compiler { + pub fn new() -> Result> { + let mut args = get_var("CC", "cc")?; + args.push("-Wno-deprecated-declarations".to_owned()); + // For _Generic + args.push("-std=c11".to_owned()); + // For %z support in printf when using MinGW. + args.push("-D__USE_MINGW_ANSI_STDIO".to_owned()); + args.extend(get_var("CFLAGS", "")?); + args.extend(get_var("CPPFLAGS", "")?); + args.extend(pkg_config_cflags(PACKAGES)?); + Ok(Self { args }) + } + + pub fn compile(&self, src: &Path, out: &Path) -> Result<(), Box> { + let mut cmd = self.to_command(); + cmd.arg(src); + cmd.arg("-o"); + cmd.arg(out); + let status = cmd.spawn()?.wait()?; + if !status.success() { + return Err(format!("compilation command {cmd:?} failed, {status}").into()); + } + Ok(()) + } + + fn to_command(&self) -> Command { + let mut cmd = Command::new(&self.args[0]); + cmd.args(&self.args[1..]); + cmd + } +} + +fn get_var(name: &str, default: &str) -> Result, Box> { + match env::var(name) { + Ok(value) => Ok(shell_words::split(&value)?), + Err(env::VarError::NotPresent) => Ok(shell_words::split(default)?), + Err(err) => Err(format!("{name} {err}").into()), + } +} + +fn pkg_config_cflags(packages: &[&str]) -> Result, Box> { + if packages.is_empty() { + return Ok(Vec::new()); + } + let pkg_config = env::var_os("PKG_CONFIG") + .unwrap_or_else(|| OsString::from("pkg-config")); + let mut cmd = Command::new(pkg_config); + cmd.arg("--cflags"); + cmd.args(packages); + cmd.stderr(Stdio::inherit()); + let out = cmd.output()?; + if !out.status.success() { + let (status, stdout) = (out.status, String::from_utf8_lossy(&out.stdout)); + return Err(format!("command {cmd:?} failed, {status:?}\nstdout: {stdout}").into()); + } + let stdout = str::from_utf8(&out.stdout)?; + Ok(shell_words::split(stdout.trim())?) +} + + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +struct Layout { + size: usize, + alignment: usize, +} + +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +struct Results { + /// Number of successfully completed tests. + passed: usize, + /// Total number of failed tests (including those that failed to compile). + failed: usize, +} + +impl Results { + fn record_passed(&mut self) { + self.passed += 1; + } + fn record_failed(&mut self) { + self.failed += 1; + } + fn summary(&self) -> String { + format!("{} passed; {} failed", self.passed, self.failed) + } + fn expect_total_success(&self) { + if self.failed == 0 { + println!("OK: {}", self.summary()); + } else { + panic!("FAILED: {}", self.summary()); + }; + } +} + +#[test] +fn cross_validate_constants_with_c() { + let mut c_constants: Vec<(String, String)> = Vec::new(); + + for l in get_c_output("constant").unwrap().lines() { + let (name, value) = l.split_once(';').expect("Missing ';' separator"); + c_constants.push((name.to_owned(), value.to_owned())); + } + + let mut results = Results::default(); + + for ((rust_name, rust_value), (c_name, c_value)) in + RUST_CONSTANTS.iter().zip(c_constants.iter()) + { + if rust_name != c_name { + results.record_failed(); + eprintln!("Name mismatch:\nRust: {rust_name:?}\nC: {c_name:?}"); + continue; + } + + if rust_value != c_value { + results.record_failed(); + eprintln!( + "Constant value mismatch for {rust_name}\nRust: {rust_value:?}\nC: {c_value:?}", + ); + continue; + } + + results.record_passed(); + } + + results.expect_total_success(); +} + +#[test] +fn cross_validate_layout_with_c() { + let mut c_layouts = Vec::new(); + + for l in get_c_output("layout").unwrap().lines() { + let (name, value) = l.split_once(';').expect("Missing first ';' separator"); + let (size, alignment) = value.split_once(';').expect("Missing second ';' separator"); + let size = size.parse().expect("Failed to parse size"); + let alignment = alignment.parse().expect("Failed to parse alignment"); + c_layouts.push((name.to_owned(), Layout { size, alignment })); + } + + let mut results = Results::default(); + + for ((rust_name, rust_layout), (c_name, c_layout)) in + RUST_LAYOUTS.iter().zip(c_layouts.iter()) + { + if rust_name != c_name { + results.record_failed(); + eprintln!("Name mismatch:\nRust: {rust_name:?}\nC: {c_name:?}"); + continue; + } + + if rust_layout != c_layout { + results.record_failed(); + eprintln!( + "Layout mismatch for {rust_name}\nRust: {rust_layout:?}\nC: {c_layout:?}", + ); + continue; + } + + results.record_passed(); + } + + results.expect_total_success(); +} + +fn get_c_output(name: &str) -> Result> { + let tmpdir = Builder::new().prefix("abi").tempdir()?; + let exe = tmpdir.path().join(name); + let c_file = Path::new("tests").join(name).with_extension("c"); + + let cc = Compiler::new().expect("configured compiler"); + cc.compile(&c_file, &exe)?; + + let mut cmd = Command::new(exe); + cmd.stderr(Stdio::inherit()); + let out = cmd.output()?; + if !out.status.success() { + let (status, stdout) = (out.status, String::from_utf8_lossy(&out.stdout)); + return Err(format!("command {cmd:?} failed, {status:?}\nstdout: {stdout}").into()); + } + + Ok(String::from_utf8(out.stdout)?) +} + +const RUST_LAYOUTS: &[(&str, Layout)] = &[ + ("ZyppContextClass", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppException", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppExpectedClass", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppInfoBaseInterface", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppProgressObserverClass", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppRepoInfoClass", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppRepoInfoType", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppRepoManagerClass", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppRepoManagerError", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppRepoRefreshResult", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppRepositoryClass", Layout {size: size_of::(), alignment: align_of::()}), + ("ZyppServiceInfoClass", Layout {size: size_of::(), alignment: align_of::()}), +]; + +const RUST_CONSTANTS: &[(&str, &str)] = &[ + ("(gint) ZYPP_ERROR", "0"), + ("(gint) ZYPP_REPO_MANAGER_ERROR_REF_ABORTED", "2"), + ("(gint) ZYPP_REPO_MANAGER_ERROR_REF_FAILED", "0"), + ("(gint) ZYPP_REPO_MANAGER_ERROR_REF_SKIPPED", "1"), + ("(gint) ZYPP_REPO_MANAGER_REFRESHED", "1"), + ("(gint) ZYPP_REPO_MANAGER_UP_TO_DATE", "0"), + ("(gint) ZYPP_REPO_NONE", "0"), + ("(gint) ZYPP_REPO_RPMMD", "1"), + ("(gint) ZYPP_REPO_RPMPLAINDIR", "3"), + ("(gint) ZYPP_REPO_YAST2", "2"), +]; + + diff --git a/zypp-sys/tests/constant.c b/zypp-sys/tests/constant.c new file mode 100644 index 0000000..9dc0daf --- /dev/null +++ b/zypp-sys/tests/constant.c @@ -0,0 +1,42 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from ../gir-files +// DO NOT EDIT + +#include "manual.h" +#include + +#define PRINT_CONSTANT(CONSTANT_NAME) \ + printf("%s;", #CONSTANT_NAME); \ + printf(_Generic((CONSTANT_NAME), \ + char *: "%s", \ + const char *: "%s", \ + char: "%c", \ + signed char: "%hhd", \ + unsigned char: "%hhu", \ + short int: "%hd", \ + unsigned short int: "%hu", \ + int: "%d", \ + unsigned int: "%u", \ + long: "%ld", \ + unsigned long: "%lu", \ + long long: "%lld", \ + unsigned long long: "%llu", \ + float: "%f", \ + double: "%f", \ + long double: "%ld"), \ + CONSTANT_NAME); \ + printf("\n"); + +int main() { + PRINT_CONSTANT((gint) ZYPP_ERROR); + PRINT_CONSTANT((gint) ZYPP_REPO_MANAGER_ERROR_REF_ABORTED); + PRINT_CONSTANT((gint) ZYPP_REPO_MANAGER_ERROR_REF_FAILED); + PRINT_CONSTANT((gint) ZYPP_REPO_MANAGER_ERROR_REF_SKIPPED); + PRINT_CONSTANT((gint) ZYPP_REPO_MANAGER_REFRESHED); + PRINT_CONSTANT((gint) ZYPP_REPO_MANAGER_UP_TO_DATE); + PRINT_CONSTANT((gint) ZYPP_REPO_NONE); + PRINT_CONSTANT((gint) ZYPP_REPO_RPMMD); + PRINT_CONSTANT((gint) ZYPP_REPO_RPMPLAINDIR); + PRINT_CONSTANT((gint) ZYPP_REPO_YAST2); + return 0; +} diff --git a/zypp-sys/tests/layout.c b/zypp-sys/tests/layout.c new file mode 100644 index 0000000..f966a70 --- /dev/null +++ b/zypp-sys/tests/layout.c @@ -0,0 +1,23 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from ../gir-files +// DO NOT EDIT + +#include "manual.h" +#include +#include + +int main() { + printf("%s;%zu;%zu\n", "ZyppContextClass", sizeof(ZyppContextClass), alignof(ZyppContextClass)); + printf("%s;%zu;%zu\n", "ZyppException", sizeof(ZyppException), alignof(ZyppException)); + printf("%s;%zu;%zu\n", "ZyppExpectedClass", sizeof(ZyppExpectedClass), alignof(ZyppExpectedClass)); + printf("%s;%zu;%zu\n", "ZyppInfoBaseInterface", sizeof(ZyppInfoBaseInterface), alignof(ZyppInfoBaseInterface)); + printf("%s;%zu;%zu\n", "ZyppProgressObserverClass", sizeof(ZyppProgressObserverClass), alignof(ZyppProgressObserverClass)); + printf("%s;%zu;%zu\n", "ZyppRepoInfoClass", sizeof(ZyppRepoInfoClass), alignof(ZyppRepoInfoClass)); + printf("%s;%zu;%zu\n", "ZyppRepoInfoType", sizeof(ZyppRepoInfoType), alignof(ZyppRepoInfoType)); + printf("%s;%zu;%zu\n", "ZyppRepoManagerClass", sizeof(ZyppRepoManagerClass), alignof(ZyppRepoManagerClass)); + printf("%s;%zu;%zu\n", "ZyppRepoManagerError", sizeof(ZyppRepoManagerError), alignof(ZyppRepoManagerError)); + printf("%s;%zu;%zu\n", "ZyppRepoRefreshResult", sizeof(ZyppRepoRefreshResult), alignof(ZyppRepoRefreshResult)); + printf("%s;%zu;%zu\n", "ZyppRepositoryClass", sizeof(ZyppRepositoryClass), alignof(ZyppRepositoryClass)); + printf("%s;%zu;%zu\n", "ZyppServiceInfoClass", sizeof(ZyppServiceInfoClass), alignof(ZyppServiceInfoClass)); + return 0; +} diff --git a/zypp-sys/tests/manual.h b/zypp-sys/tests/manual.h new file mode 100644 index 0000000..5848353 --- /dev/null +++ b/zypp-sys/tests/manual.h @@ -0,0 +1,3 @@ +// Feel free to edit this file, it won't be regenerated by gir generator unless removed. + +#include