daemon: Start implementing transaction methods

This commit is contained in:
petervo 2015-06-10 19:17:49 -07:00 committed by Matthew Barnes
parent 075d6bdad0
commit 0114507865
13 changed files with 1065 additions and 541 deletions

View File

@ -30,6 +30,8 @@ librpmostreed_la_SOURCES = \
src/daemon/auth.c \
src/daemon/deployment-utils.h \
src/daemon/deployment-utils.c \
src/daemon/transactions.h \
src/daemon/transactions.c \
src/daemon/rpmostree-package-variants.h \
src/daemon/rpmostree-package-variants.c \
src/daemon/os.h \

View File

@ -196,8 +196,6 @@ daemon_constructed (GObject *_object)
G_OBJECT_CLASS (daemon_parent_class)->constructed (_object);
g_dbus_connection_start_message_processing (self->connection);
path = utils_generate_object_path (BASE_DBUS_PATH, "Sysroot", NULL);
self->sysroot = g_object_new (TYPE_SYSROOT,
"sysroot-path", self->sysroot_path,
@ -210,6 +208,8 @@ daemon_constructed (GObject *_object)
}
daemon_publish (self, path, FALSE, self->sysroot);
g_dbus_connection_start_message_processing (self->connection);
g_debug ("daemon constructed");
out:

View File

@ -36,6 +36,31 @@ deployment_generate_id (OstreeDeployment *deployment)
return g_strdup_printf ("%s_%u", osname, hash);
}
OstreeDeployment *
deployment_get_for_id (OstreeSysroot *sysroot,
const gchar *deploy_id)
{
g_autoptr (GPtrArray) deployments = NULL;
guint i;
OstreeDeployment *deployment = NULL;
deployments = ostree_sysroot_get_deployments (sysroot);
if (deployments == NULL)
goto out;
for (i=0; i<deployments->len; i++)
{
g_autofree gchar *id = deployment_generate_id (deployments->pdata[i]);
if (g_strcmp0 (deploy_id, id) == 0) {
deployment = g_object_ref (deployments->pdata[i]);
}
}
out:
return deployment;
}
static GVariant *
deployment_gpg_results (OstreeRepo *repo,
const gchar *origin_refspec,
@ -180,3 +205,60 @@ deployment_generate_variant (OstreeDeployment *deployment,
return g_variant_builder_end (&builder);
}
gint
rollback_deployment_index (const gchar *name,
OstreeSysroot *ot_sysroot,
GError **error)
{
g_autoptr (GPtrArray) deployments = NULL;
glnx_unref_object OstreeDeployment *merge_deployment = NULL;
gint index_to_prepend = -1;
gint merge_index = -1;
gint previous_index = -1;
guint i;
merge_deployment = ostree_sysroot_get_merge_deployment (ot_sysroot, name);
if (merge_deployment == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No deployments found for os %s", name);
goto out;
}
deployments = ostree_sysroot_get_deployments (ot_sysroot);
if (deployments->len < 2)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Found %u deployments, at least 2 required for rollback",
deployments->len);
goto out;
}
g_assert (merge_deployment != NULL);
for (i = 0; i < deployments->len; i++)
{
if (deployments->pdata[i] == merge_deployment)
merge_index = i;
if (g_strcmp0 (ostree_deployment_get_osname (deployments->pdata[i]), name) == 0 &&
deployments->pdata[i] != merge_deployment &&
previous_index < 0)
{
previous_index = i;
}
}
g_assert (merge_index < deployments->len);
g_assert (deployments->pdata[merge_index] == merge_deployment);
/* If merge deployment is not booted assume we are using it. */
if (merge_index == 0 && previous_index > 0)
index_to_prepend = previous_index;
else
index_to_prepend = merge_index;
out:
return index_to_prepend;
}

View File

@ -24,8 +24,16 @@
char * deployment_generate_id (OstreeDeployment *deployment);
OstreeDeployment * deployment_get_for_id (OstreeSysroot *sysroot,
const gchar *deploy_id);
char * deployment_get_refspec (OstreeDeployment *deployment);
GVariant * deployment_generate_blank_variant (void);
GVariant * deployment_generate_variant (OstreeDeployment *deployment,
OstreeRepo *repo);
gint rollback_deployment_index (const gchar *name,
OstreeSysroot *ot_sysroot,
GError **error);

View File

@ -37,6 +37,7 @@
<property name="BootedDeployment" type="(ssisstsav)" access="read"/>
<property name="DefaultDeployment" type="(ssisstsav)" access="read"/>
<property name="RollbackDeployment" type="(ssisstsav)" access="read"/>
<property name="UpgradeOrigin" type="s" access="read"/>
<property name="HasCachedUpdateRpmDiff" type="b" access="read"/>
<!-- NONE, DIFF, PREPARE, REBOOT -->
@ -50,11 +51,11 @@
</method>
<method name="GetCachedUpdateRpmDiff">
<arg type="s" name="deployid"/>
<arg type="a(sua{sv})" name="result" direction="out"/>
</method>
<method name="DownloadUpdateRpmDiff">
<arg type="s" name="deployid"/>
<arg type="o" name="transaction" direction="out"/>
</method>
@ -74,9 +75,14 @@
<arg type="o" name="transaction" direction="out"/>
</method>
<!-- Available options:
"skip-purge" (type 'b')
-->
<method name="Rebase">
<arg type="a{sv}" name="options" direction="in"/>
<arg type="s" name="refspec"/>
<arg type="as" name="packages"/>
<arg type="o" name="transaction" direction="out"/>
</method>
<method name="GetCachedRebaseRpmDiff">
@ -96,17 +102,14 @@
<interface name="org.projectatomic.rpmostree1.Transaction">
<property name="Method" type="s" access="read"/>
<property name="InitiatingOwner" type="s" access="read"/>
<property name="Complete" type="b" access="read"/>
<property name="Success" type="b" access="read"/>
<property name="ResultMessage" type="s" access="read"/>
<!-- Yes, we can. -->
<method name="Cancel">
</method>
<!-- XXX Blindly mimicing UDisks2.Job for now. -->
<signal name="Completed">
<arg name="success" type="b" direction="out"/>
<arg name="message" type="s" direction="out"/>
</signal>
<!-- For miscellaneous messages. -->
<signal name="Message">
<arg name="text" type="s" direction="out"/>

File diff suppressed because it is too large Load Diff

View File

@ -86,7 +86,7 @@ static guint64 UPDATED_THROTTLE_SECONDS = 2;
static guint sysroot_signals[NUM_SIGNALS] = { 0, };
static void sysroot_iface_init (RPMOSTreeSysrootIface *iface);
static gboolean _throttle_refresh (gpointer user_data);
G_DEFINE_TYPE_WITH_CODE (Sysroot, sysroot, RPMOSTREE_TYPE_SYSROOT_SKELETON,
G_IMPLEMENT_INTERFACE (RPMOSTREE_TYPE_SYSROOT,
@ -131,6 +131,8 @@ handle_create_osname (RPMOSTreeSysroot *object,
GError *error = NULL;
g_autofree gchar *dbus_path = NULL;
gboolean needs_refresh = FALSE;
Sysroot *self = SYSROOT (object);
if (!ostree_sysroot_ensure_initialized (self->ot_sysroot,
@ -194,7 +196,13 @@ handle_create_osname (RPMOSTreeSysroot *object,
dbus_path = utils_generate_object_path (BASE_DBUS_PATH,
osname, NULL);
sysroot_ensure_refresh (SYSROOT (self));
g_rw_lock_reader_lock (&self->children_lock);
needs_refresh = self->last_monitor_event == 0;
g_rw_lock_reader_unlock (&self->children_lock);
if (needs_refresh)
_throttle_refresh (self);
rpmostree_sysroot_complete_create_osname (RPMOSTREE_SYSROOT (self),
invocation,
g_strdup (dbus_path));
@ -213,6 +221,14 @@ handle_get_os (RPMOSTreeSysroot *object,
Sysroot *self = SYSROOT (object);
glnx_unref_object GDBusInterfaceSkeleton *os_interface = NULL;
if (arg_name[0] == '\0')
{
rpmostree_sysroot_complete_get_os (object,
invocation,
rpmostree_sysroot_dup_booted (object));
goto out;
}
g_rw_lock_reader_lock (&self->children_lock);
os_interface = g_hash_table_lookup (self->os_interfaces, arg_name);
@ -236,6 +252,7 @@ handle_get_os (RPMOSTreeSysroot *object,
arg_name);
}
out:
return TRUE;
}
@ -530,9 +547,6 @@ out:
return ret;
}
static gboolean _throttle_refresh (gpointer user_data);
static void
_do_reload_data (GTask *task,
gpointer object,
@ -564,7 +578,7 @@ _reload_callback (GObject *source_object,
if (error)
{
// this was valid once, make sure it is tried again
// TODO, should we bail at some point?
// TODO: should we bail at some point?
g_message ("Error refreshing sysroot data: %s", error->message);
g_timeout_add_seconds (UPDATED_THROTTLE_SECONDS,
_throttle_refresh,
@ -635,22 +649,16 @@ sysroot_iface_init (RPMOSTreeSysrootIface *iface)
/**
* sysroot_ensure_refresh:
* sysroot_emit_update:
*
* Ensures that the sysroot will reload it's
* internal data.
* Emits an sysroot-updated signal
* requires a known up to date sysroot
*/
void
sysroot_ensure_refresh (Sysroot *self)
sysroot_emit_update (Sysroot *self,
OstreeSysroot *ot_sysroot)
{
gboolean needs_run;
g_rw_lock_reader_lock (&self->children_lock);
needs_run = self->last_monitor_event == 0;
g_rw_lock_reader_unlock (&self->children_lock);
if (needs_run)
_throttle_refresh (self);
g_signal_emit (self, sysroot_signals[UPDATED], 0, ot_sysroot);
}
/**

View File

@ -20,6 +20,7 @@
#define RPM_OSTREED_SYSROOT_H__
#include "types.h"
#include "ostree.h"
G_BEGIN_DECLS
@ -38,7 +39,9 @@ gchar * sysroot_get_sysroot_path (Sysroot *self);
gboolean sysroot_populate (Sysroot *self,
GError **error);
void sysroot_ensure_refresh (Sysroot *self);
void sysroot_emit_update (Sysroot *self,
OstreeSysroot *ot_sysroot);
G_END_DECLS
#endif /* RPM_OSTREED_SYSROOT_H__ */

267
src/daemon/transactions.c Normal file
View File

@ -0,0 +1,267 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "transactions.h"
#include "errors.h"
#include "daemon.h"
static guint TRANSACTION_KEEP_SECONDS = 300;
static gboolean
ensure_same_caller (RPMOSTreeTransaction *transaction,
GDBusMethodInvocation *invocation)
{
gboolean ret = FALSE;
const char *known_sender;
const char *sender;
sender = g_dbus_method_invocation_get_sender (invocation);
known_sender = rpmostree_transaction_get_initiating_owner (transaction);
if (g_strcmp0(sender, known_sender) != 0)
{
GError *error = g_error_new_literal (RPM_OSTREED_ERROR, RPM_OSTREED_ERROR_FAILED,
"You are not allowed to cancel this transaction.");
g_dbus_method_invocation_take_error (invocation, error);
goto out;
}
ret = TRUE;
out:
return ret;
}
static gboolean
handle_cancel_cb (RPMOSTreeTransaction *transaction,
GDBusMethodInvocation *invocation,
GCancellable *method_cancellable)
{
if (!ensure_same_caller (transaction, invocation))
goto out;
g_cancellable_cancel (method_cancellable);
rpmostree_transaction_complete_cancel (transaction, invocation);
out:
return TRUE;
}
static void
progress_changed_cb (OstreeAsyncProgress *progress,
RPMOSTreeTransaction *transaction)
{
guint64 start_time = ostree_async_progress_get_uint64 (progress, "start-time");
guint64 elapsed_secs = 0;
guint outstanding_fetches = ostree_async_progress_get_uint (progress, "outstanding-fetches");
guint outstanding_writes = ostree_async_progress_get_uint (progress, "outstanding-writes");
guint n_scanned_metadata = ostree_async_progress_get_uint (progress, "scanned-metadata");
guint metadata_fetched = ostree_async_progress_get_uint (progress, "metadata-fetched");
guint outstanding_metadata_fetches = ostree_async_progress_get_uint (progress, "outstanding-metadata-fetches");
guint total_delta_parts = ostree_async_progress_get_uint (progress, "total-delta-parts");
guint fetched_delta_parts = ostree_async_progress_get_uint (progress, "fetched-delta-parts");
guint total_delta_superblocks = ostree_async_progress_get_uint (progress, "total-delta-superblocks");
guint64 total_delta_part_size = ostree_async_progress_get_uint64 (progress, "total-delta-part-size");
guint fetched = ostree_async_progress_get_uint (progress, "fetched");
guint requested = ostree_async_progress_get_uint (progress, "requested");
guint64 bytes_sec = 0;
guint64 bytes_transferred = ostree_async_progress_get_uint64 (progress, "bytes-transferred");
GVariant *arg_time;
GVariant *arg_outstanding;
GVariant *arg_metadata;
GVariant *arg_delta;
GVariant *arg_content;
GVariant *arg_transfer;
g_autofree gchar *status;
/* If there is a status that is all we output */
status = ostree_async_progress_get_status (progress);
if (status) {
rpmostree_transaction_emit_message (transaction, g_strdup (status));
return;
}
if (start_time)
{
guint64 elapsed_secs = (g_get_monotonic_time () - start_time) / G_USEC_PER_SEC;
if (elapsed_secs)
bytes_sec = bytes_transferred / elapsed_secs;
}
arg_time = g_variant_new ("(tt)",
start_time,
elapsed_secs);
arg_outstanding = g_variant_new ("(uu)",
outstanding_fetches,
outstanding_writes);
arg_metadata = g_variant_new ("(uuu)",
n_scanned_metadata,
metadata_fetched,
outstanding_metadata_fetches);
arg_delta = g_variant_new ("(uuut)",
total_delta_parts,
fetched_delta_parts,
total_delta_superblocks,
total_delta_part_size);
arg_content = g_variant_new ("(uu)",
fetched,
requested);
arg_transfer = g_variant_new ("(tt)",
bytes_transferred,
bytes_sec);
/* This sinks the floating GVariant refs (I think...). */
rpmostree_transaction_emit_download_progress (transaction,
arg_time,
arg_outstanding,
arg_metadata,
arg_delta,
arg_content,
arg_transfer);
}
static void
gpg_verify_result_cb (OstreeRepo *repo,
const char *checksum,
OstreeGpgVerifyResult *result,
RPMOSTreeTransaction *transaction)
{
guint n, i;
GVariantBuilder builder;
if (rpmostree_transaction_get_complete (transaction))
return;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
n = ostree_gpg_verify_result_count_all (result);
for (i = 0; i < n; i++)
{
g_variant_builder_add (&builder, "v",
ostree_gpg_verify_result_get_all (result, i));
}
rpmostree_transaction_emit_signature_progress (transaction,
g_variant_builder_end (&builder),
g_strdup (checksum));
}
void
transaction_connect_download_progress (RPMOSTreeTransaction *transaction,
OstreeAsyncProgress *progress)
{
g_signal_connect_object (progress,
"changed",
G_CALLBACK (progress_changed_cb),
transaction, 0);
}
void
transaction_connect_signature_progress (RPMOSTreeTransaction *transaction,
OstreeRepo *repo)
{
g_signal_connect_object (repo, "gpg-verify-result",
G_CALLBACK (gpg_verify_result_cb),
transaction, 0);
}
static gboolean
close_transaction (gpointer user_data)
{
RPMOSTreeTransaction *transaction = RPMOSTREE_TRANSACTION (user_data);
const char *object_path;
object_path = g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON(transaction));
if (object_path)
{
daemon_unpublish (daemon_get (),
object_path,
transaction);
}
g_clear_object (&transaction);
return FALSE;
}
RPMOSTreeTransaction *
new_transaction (GDBusMethodInvocation *invocation,
GCancellable *method_cancellable,
GError **error)
{
RPMOSTreeTransaction *transaction;
const char *method_name;
const char *object_path;
const char *sender;
g_autofree gchar *child_object_path = NULL;
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), FALSE);
method_name = g_dbus_method_invocation_get_method_name (invocation);
object_path = g_dbus_method_invocation_get_object_path (invocation);
sender = g_dbus_method_invocation_get_sender (invocation);
child_object_path = g_build_path ("/", object_path, "Transaction", NULL);
transaction = rpmostree_transaction_skeleton_new ();
rpmostree_transaction_set_method (transaction, method_name);
rpmostree_transaction_set_initiating_owner (transaction, sender);
if (G_IS_CANCELLABLE (method_cancellable))
{
g_signal_connect_object (transaction,
"handle-cancel",
G_CALLBACK (handle_cancel_cb),
method_cancellable, 0);
}
/* Published uniquely */
daemon_publish (daemon_get (), child_object_path, TRUE, transaction);
return transaction;
}
void
complete_transaction (RPMOSTreeTransaction *transaction,
gboolean success,
const gchar *message)
{
if (message != NULL)
rpmostree_transaction_set_result_message (transaction, message);
rpmostree_transaction_set_success (transaction, success);
rpmostree_transaction_set_complete (transaction, TRUE);
g_timeout_add_seconds (TRANSACTION_KEEP_SECONDS,
close_transaction,
g_object_ref (transaction));
}

39
src/daemon/transactions.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <ostree.h>
#include "types.h"
RPMOSTreeTransaction * new_transaction (GDBusMethodInvocation *invocation,
GCancellable *method_cancellable,
GError **error);
void complete_transaction (RPMOSTreeTransaction *transaction,
gboolean success,
const gchar *message);
void
transaction_connect_download_progress (RPMOSTreeTransaction *transaction,
OstreeAsyncProgress *progress);
void
transaction_connect_signature_progress (RPMOSTreeTransaction *transaction,
OstreeRepo *repo);

View File

@ -36,4 +36,7 @@ typedef struct _Sysroot Sysroot;
struct _OSStub;
typedef struct _OSStub OSStub;
struct _Transaction;
typedef struct _Transaction Transaction;
#endif /* RPM_OSTREED_TYPES_H__ */

View File

@ -18,158 +18,10 @@
#include "config.h"
#include "utils.h"
#include "errors.h"
#include "libgsystem.h"
#include <libglnx.h>
static gboolean
handle_cancel_cb (RPMOSTreeTransaction *transaction,
GDBusMethodInvocation *invocation,
GCancellable *method_cancellable)
{
g_cancellable_cancel (method_cancellable);
rpmostree_transaction_complete_cancel (transaction, invocation);
return TRUE;
}
static void
progress_changed_cb (OstreeAsyncProgress *progress,
RPMOSTreeTransaction *transaction)
{
guint64 start_time = ostree_async_progress_get_uint64 (progress, "start-time");
guint64 elapsed_secs = 0;
guint outstanding_fetches = ostree_async_progress_get_uint (progress, "outstanding-fetches");
guint outstanding_writes = ostree_async_progress_get_uint (progress, "outstanding-writes");
guint n_scanned_metadata = ostree_async_progress_get_uint (progress, "scanned-metadata");
guint metadata_fetched = ostree_async_progress_get_uint (progress, "metadata-fetched");
guint outstanding_metadata_fetches = ostree_async_progress_get_uint (progress, "outstanding-metadata-fetches");
guint total_delta_parts = ostree_async_progress_get_uint (progress, "total-delta-parts");
guint fetched_delta_parts = ostree_async_progress_get_uint (progress, "fetched-delta-parts");
guint total_delta_superblocks = ostree_async_progress_get_uint (progress, "total-delta-superblocks");
guint64 total_delta_part_size = ostree_async_progress_get_uint64 (progress, "total-delta-part-size");
guint fetched = ostree_async_progress_get_uint (progress, "fetched");
guint requested = ostree_async_progress_get_uint (progress, "requested");
guint64 bytes_sec = 0;
guint64 bytes_transferred = ostree_async_progress_get_uint64 (progress, "bytes-transferred");
GVariant *arg_time;
GVariant *arg_outstanding;
GVariant *arg_metadata;
GVariant *arg_delta;
GVariant *arg_content;
GVariant *arg_transfer;
if (start_time)
{
guint64 elapsed_secs = (g_get_monotonic_time () - start_time) / G_USEC_PER_SEC;
if (elapsed_secs)
bytes_sec = bytes_transferred / elapsed_secs;
}
arg_time = g_variant_new ("(tt)",
start_time,
elapsed_secs);
arg_outstanding = g_variant_new ("(uu)",
outstanding_fetches,
outstanding_writes);
arg_metadata = g_variant_new ("(uuu)",
n_scanned_metadata,
metadata_fetched,
outstanding_metadata_fetches);
arg_delta = g_variant_new ("(uuut)",
total_delta_parts,
fetched_delta_parts,
total_delta_superblocks,
total_delta_part_size);
arg_content = g_variant_new ("(uu)",
fetched,
requested);
arg_transfer = g_variant_new ("(tt)",
bytes_transferred,
bytes_sec);
/* This sinks the floating GVariant refs (I think...). */
rpmostree_transaction_emit_download_progress (transaction,
arg_time,
arg_outstanding,
arg_metadata,
arg_delta,
arg_content,
arg_transfer);
}
RPMOSTreeTransaction *
new_transaction (GDBusMethodInvocation *invocation,
GCancellable *method_cancellable,
OstreeAsyncProgress **out_progress,
GError **error)
{
RPMOSTreeTransaction *transaction;
GDBusConnection *connection;
const char *method_name;
const char *object_path;
const char *sender;
g_autofree gchar *child_object_path = NULL;
g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation), FALSE);
connection = g_dbus_method_invocation_get_connection (invocation);
method_name = g_dbus_method_invocation_get_method_name (invocation);
object_path = g_dbus_method_invocation_get_object_path (invocation);
sender = g_dbus_method_invocation_get_sender (invocation);
child_object_path = g_build_path ("/", object_path, "Transaction", NULL);
transaction = rpmostree_transaction_skeleton_new ();
rpmostree_transaction_set_method (transaction, method_name);
rpmostree_transaction_set_initiating_owner (transaction, sender);
if (G_IS_CANCELLABLE (method_cancellable))
{
g_signal_connect_object (transaction,
"handle-cancel",
G_CALLBACK (handle_cancel_cb),
method_cancellable, 0);
}
if (out_progress != NULL)
{
OstreeAsyncProgress *progress;
progress = ostree_async_progress_new ();
g_signal_connect_object (progress,
"changed",
G_CALLBACK (progress_changed_cb),
transaction, 0);
*out_progress = g_steal_pointer (&progress);
}
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (transaction),
connection,
child_object_path,
error))
{
g_clear_object (&transaction);
}
return transaction;
}
static void
append_to_object_path (GString *str,
const gchar *s)
@ -298,7 +150,111 @@ utils_load_sysroot_and_repo (gchar *path,
error))
goto out;
gs_transfer_out_value (out_sysroot, &ot_sysroot);
if (out_sysroot != NULL)
*out_sysroot = g_steal_pointer (&ot_sysroot);
ret = TRUE;
out:
return ret;
}
/**
* refspec_parse_partial:
* @new_provided_refspec: The provided refspec
* @base_refspec: The refspec string to base on.
* @out_refspec: Pointer to the new refspec
* @error: Pointer to an error pointer.
*
* Takes a refspec string and adds any missing bits based on the
* base_refspec argument. Errors if a full valid refspec can't
* be derived.
*
* Returns: True on sucess.
*/
gboolean
refspec_parse_partial (const gchar *new_provided_refspec,
gchar *base_refspec,
gchar **out_refspec,
GError **error)
{
g_autofree gchar *ref = NULL;
g_autofree gchar *remote = NULL;
g_autofree gchar *origin_ref = NULL;
g_autofree gchar *origin_remote = NULL;
GError *parse_error = NULL;
gboolean ret = FALSE;
/* Allow just switching remotes */
if (g_str_has_suffix (new_provided_refspec, ":"))
{
remote = g_strdup (new_provided_refspec);
remote[strlen (remote) - 1] = '\0';
}
else
{
if (!ostree_parse_refspec (new_provided_refspec, &remote,
&ref, &parse_error))
{
g_set_error_literal (error, RPM_OSTREED_ERROR,
RPM_OSTREED_ERROR_INVALID_REFSPEC,
parse_error->message);
g_clear_error (&parse_error);
goto out;
}
}
if (base_refspec != NULL)
{
if (!ostree_parse_refspec (base_refspec, &origin_remote,
&origin_ref, &parse_error))
goto out;
}
if (ref == NULL)
{
if (origin_ref)
{
ref = g_strdup (origin_ref);
}
else
{
g_set_error (error, RPM_OSTREED_ERROR,
RPM_OSTREED_ERROR_INVALID_REFSPEC,
"Could not determine default ref to pull.");
goto out;
}
}
else if (remote == NULL)
{
if (origin_remote)
{
remote = g_strdup (origin_remote);
}
else
{
g_set_error (error, RPM_OSTREED_ERROR,
RPM_OSTREED_ERROR_INVALID_REFSPEC,
"Could not determine default remote to pull.");
goto out;
}
}
if (g_strcmp0 (origin_remote, remote) == 0 &&
g_strcmp0 (origin_ref, ref) == 0)
{
g_set_error (error, RPM_OSTREED_ERROR,
RPM_OSTREED_ERROR_INVALID_REFSPEC,
"Old and new refs are equal: %s:%s",
remote, ref);
goto out;
}
*out_refspec = g_strconcat (remote, ":", ref, NULL);
ret = TRUE;
out:

View File

@ -22,11 +22,6 @@
#include "types.h"
RPMOSTreeTransaction * new_transaction (GDBusMethodInvocation *invocation,
GCancellable *method_cancellable,
OstreeAsyncProgress **out_progress,
GError **error);
gchar * utils_generate_object_path (const gchar *base,
const gchar *part,
...);
@ -40,3 +35,8 @@ gboolean utils_load_sysroot_and_repo (gchar *path,
OstreeSysroot **out_sysroot,
OstreeRepo **out_repo,
GError **error);
gboolean refspec_parse_partial (const gchar *new_provided_refspec,
gchar *base_refspec,
gchar **out_refspec,
GError **error);