Skip to content

Commit

Permalink
Implemented builtin search function
Browse files Browse the repository at this point in the history
  • Loading branch information
lukewarmtemp committed Jun 20, 2023
1 parent 7ad41b6 commit 9405e9c
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/app/libmain.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ static RpmOstreeCommand commands[] = {
"Overlay additional packages", rpmostree_builtin_install },
{ "uninstall", static_cast<RpmOstreeBuiltinFlags> (RPM_OSTREE_BUILTIN_FLAG_CONTAINER_CAPABLE),
"Remove overlayed additional packages", rpmostree_builtin_uninstall },
{ "search", static_cast<RpmOstreeBuiltinFlags> (RPM_OSTREE_BUILTIN_FLAG_CONTAINER_CAPABLE),
"Search for packages", rpmostree_builtin_search },
{ "override", static_cast<RpmOstreeBuiltinFlags> (RPM_OSTREE_BUILTIN_FLAG_LOCAL_CMD),
"Manage base package overrides", rpmostree_builtin_override },
{ "reset", static_cast<RpmOstreeBuiltinFlags> (RPM_OSTREE_BUILTIN_FLAG_SUPPORTS_PKG_INSTALLS),
Expand Down
1 change: 1 addition & 0 deletions src/app/rpmostree-builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ BUILTINPROTO (internals);
BUILTINPROTO (container);
BUILTINPROTO (install);
BUILTINPROTO (uninstall);
BUILTINPROTO (search);
BUILTINPROTO (override);
BUILTINPROTO (kargs);
BUILTINPROTO (reset);
Expand Down
106 changes: 106 additions & 0 deletions src/app/rpmostree-pkg-builtins.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

#include <gio/gunixfdlist.h>

#include <set>

static char *opt_osname;
static gboolean opt_reboot;
static gboolean opt_dry_run;
Expand Down Expand Up @@ -310,3 +312,107 @@ rpmostree_builtin_uninstall (int argc, char **argv, RpmOstreeCommandInvocation *
return pkg_change (invocation, sysroot_proxy, FALSE, (const char *const *)opt_install,
(const char *const *)argv, cancellable, error);
}

struct cstrless
{
bool
operator() (const gchar *a, const gchar *b) const
{
return strcmp (a, b) < 0;
}
};

gboolean
rpmostree_builtin_search (int argc, char **argv, RpmOstreeCommandInvocation *invocation,
GCancellable *cancellable, GError **error)
{
GOptionContext *context;
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;

context = g_option_context_new ("PACKAGE [PACKAGE...]");
g_option_context_add_main_entries (context, install_option_entry, NULL);
g_option_context_add_main_entries (context, uninstall_option_entry, NULL);

if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, invocation,
cancellable, NULL, NULL, &sysroot_proxy, error))
return FALSE;

if (argc < 2)
{
rpmostree_usage_error (context, "At least one PACKAGE must be specified", error);
return FALSE;
}

glnx_unref_object RPMOSTreeOS *os_proxy = NULL;

if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname, cancellable, &os_proxy, error))
return FALSE;

argv++;
g_autoptr (GPtrArray) arg_names = g_ptr_array_new ();
for (guint i = 1; i <= argc; i++)
{
if (i != argc)
{
g_ptr_array_add (arg_names, (char *)*argv);
*argv++;
}
else
{
g_ptr_array_add (arg_names, NULL);
}
}

GVariant *out_packages = NULL;

if (!rpmostree_os_call_search_sync (os_proxy, (const char *const *)arg_names->pdata,
&out_packages, cancellable, error))
return FALSE;

g_autoptr (GVariantIter) iter1 = NULL;
g_variant_get (out_packages, "aa{sv}", &iter1);

g_autoptr (GVariantIter) iter2 = NULL;
std::set<const gchar *, cstrless> query_set;
std::set<const gchar *, cstrless> result_set;

while (g_variant_iter_loop (iter1, "a{sv}", &iter2))
{
const gchar *key;
const gchar *name;
const gchar *summary;
const gchar *query;

g_autoptr (GVariant) value = NULL;

while (g_variant_iter_loop (iter2, "{sv}", &key, &value))
{
if (strcmp (key, "key") == 0)
g_variant_get (value, "s", &query);
if (strcmp (key, "name") == 0)
g_variant_get (value, "s", &name);
if (strcmp (key, "summary") == 0)
g_variant_get (value, "s", &summary);
}

if (!query_set.count (query))
{
query_set.insert (query);
g_print ("\n===== %s Matched =====\n", query);
result_set.clear ();
}

if (!result_set.count (name))
{
result_set.insert (name);
g_print ("%s : %s\n", name, summary);
}
}

if (query_set.size () == 0)
{
g_print ("No matches found.");
}

return TRUE;
}
6 changes: 6 additions & 0 deletions src/daemon/org.projectatomic.rpmostree1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,12 @@
<arg type="aa{sv}" name="packages" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantList"/>
</method>

<method name="Search">
<arg type="as" name="names" direction="in"/>
<arg type="aa{sv}" name="packages" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantList"/>
</method>
</interface>

<interface name="org.projectatomic.rpmostree1.OSExperimental">
Expand Down
91 changes: 90 additions & 1 deletion src/daemon/rpmostreed-os.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "rpmostreed-transaction.h"
#include "rpmostreed-utils.h"

#include <../libdnf/libdnf/hy-util.cpp>

typedef struct _RpmostreedOSClass RpmostreedOSClass;

struct _RpmostreedOS
Expand Down Expand Up @@ -141,7 +143,7 @@ os_authorize_method (GDBusInterfaceSkeleton *interface, GDBusMethodInvocation *i
else if (g_strcmp0 (method_name, "GetDeploymentBootConfig") == 0
|| g_strcmp0 (method_name, "ListRepos") == 0
|| g_strcmp0 (method_name, "WhatProvides") == 0
|| g_strcmp0 (method_name, "GetPackages") == 0)
|| g_strcmp0 (method_name, "GetPackages") == 0 || g_strcmp0 (method_name, "Search") == 0)
{
/* Note: early return here because no need authentication
* for these methods
Expand Down Expand Up @@ -1138,6 +1140,92 @@ os_handle_get_packages (RPMOSTreeOS *interface, GDBusMethodInvocation *invocatio
return TRUE;
}

static void
query_results_to_builder (HyQuery query, GVariantBuilder *builder, const gchar *id)
{
g_autoptr (GPtrArray) pkglist = NULL;
pkglist = hy_query_run (query);
for (guint i = 0; i < pkglist->len; i++)
{
auto pkg = static_cast<DnfPackage *> (g_ptr_array_index (pkglist, i));
os_add_package_info_to_builder (pkg, builder, id);
}
}

static void
search_packages_by_filter (HyQuery query, GVariantBuilder *builder, const gchar *const *names,
int *keynames, const gchar *id)
{
hy_query_clear (query);
for (guint j = 0; keynames[j] != NULL; j++)
{
for (guint i = 0; names[i] != NULL; i++)
{
if (!hy_is_glob_pattern (names[i]))
{
hy_query_filter (query, keynames[j], HY_EQ | HY_ICASE, names[i]);
}
else
{
hy_query_filter (query, keynames[j], HY_GLOB | HY_ICASE, names[i]);
}
}
}
query_results_to_builder (query, builder, id);

hy_query_clear (query);
for (guint j = 0; keynames[j] != NULL; j++)
{
for (guint i = 0; names[i] != NULL; i++)
{
if (!hy_is_glob_pattern (names[i]))
{
hy_query_filter (query, keynames[j], HY_SUBSTR | HY_ICASE, names[i]);
}
else
{
hy_query_filter (query, keynames[j], HY_GLOB | HY_ICASE, names[i]);
}
}
}
query_results_to_builder (query, builder, id);
}

static gboolean
os_handle_search (RPMOSTreeOS *interface, GDBusMethodInvocation *invocation,
const gchar *const *names)
{
GError *local_error = NULL;
g_autoptr (GCancellable) cancellable = NULL;
g_autoptr (DnfContext) dnfctx = NULL;

sd_journal_print (LOG_INFO, "Handling Search for caller %s",
g_dbus_method_invocation_get_sender (invocation));

dnfctx = os_create_dnf_context_simple (interface, TRUE, cancellable, &local_error);
if (dnfctx == NULL)
return os_throw_dbus_invocation_error (invocation, &local_error);

hy_autoquery HyQuery query = hy_query_create (dnf_context_get_sack (dnfctx));

GVariantBuilder builder;
g_variant_builder_init (&builder, (const GVariantType *)"aa{sv}");

int keynames_a[3] = { HY_PKG_NAME, HY_PKG_SUMMARY, NULL };
search_packages_by_filter (query, &builder, names, keynames_a, "Name & Summary");

int keynames_b[2] = { HY_PKG_NAME, NULL };
search_packages_by_filter (query, &builder, names, keynames_b, "Name");

int keynames_c[2] = { HY_PKG_SUMMARY, NULL };
search_packages_by_filter (query, &builder, names, keynames_c, "Summary");

GVariant *pkgs_result = g_variant_builder_end (&builder);
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@aa{sv})", pkgs_result));

return TRUE;
}

/* This is an older variant of Cleanup, kept for backcompat */
static gboolean
os_handle_clear_rollback_target (RPMOSTreeOS *interface, GDBusMethodInvocation *invocation,
Expand Down Expand Up @@ -1813,6 +1901,7 @@ rpmostreed_os_iface_init (RPMOSTreeOSIface *iface)
iface->handle_finalize_deployment = os_handle_finalize_deployment;
iface->handle_what_provides = os_handle_what_provides;
iface->handle_get_packages = os_handle_get_packages;
iface->handle_search = os_handle_search;
/* legacy cleanup API; superseded by Cleanup() */
iface->handle_clear_rollback_target = os_handle_clear_rollback_target;
/* legacy deployment change API; superseded by UpdateDeployment() */
Expand Down

0 comments on commit 9405e9c

Please sign in to comment.