Skip to content

Commit

Permalink
repo: Add OstreeRepoRemoteChange replace operation
Browse files Browse the repository at this point in the history
Add the OSTREE_REPO_REMOTE_CHANGE_REPLACE operation to the
OstreeRepoRemoteChange enum. This operation will add a remote or replace
an existing one. It respects the location of the remote configuration
file when replacing and the remotes config dir settings when adding a
new remote.

Closes: #1166
Approved by: cgwalters
  • Loading branch information
dbnicholson authored and rh-atomic-bot committed Feb 8, 2019
1 parent 6e935ee commit 15ba200
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 4 deletions.
85 changes: 85 additions & 0 deletions src/libostree/ostree-repo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1735,6 +1735,88 @@ ostree_repo_remote_delete (OstreeRepo *self,
return impl_repo_remote_delete (self, NULL, FALSE, name, cancellable, error);
}


static gboolean
impl_repo_remote_replace (OstreeRepo *self,
GFile *sysroot,
const char *name,
const char *url,
GVariant *options,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (url != NULL, FALSE);
g_return_val_if_fail (options == NULL || g_variant_is_of_type (options, G_VARIANT_TYPE ("a{sv}")), FALSE);

if (!ostree_validate_remote_name (name, error))
return FALSE;

g_autoptr(GError) local_error = NULL;
g_autoptr(OstreeRemote) remote = _ostree_repo_get_remote (self, name, &local_error);
if (remote == NULL)
{
if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
g_clear_error (&local_error);
if (!impl_repo_remote_add (self, sysroot, FALSE, name, url, options,
cancellable, error))
return FALSE;
}
else
{
/* Replace the entire option group */
if (!g_key_file_remove_group (remote->options, remote->group, error))
return FALSE;

if (g_str_has_prefix (url, "metalink="))
g_key_file_set_string (remote->options, remote->group, "metalink",
url + strlen ("metalink="));
else
g_key_file_set_string (remote->options, remote->group, "url", url);

if (options != NULL)
keyfile_set_from_vardict (remote->options, remote->group, options);

/* Write out updated settings */
if (remote->file != NULL)
{
gsize length;
g_autofree char *data = g_key_file_to_data (remote->options, &length,
NULL);

if (!g_file_replace_contents (remote->file, data, length,
NULL, FALSE, 0, NULL,
cancellable, error))
return FALSE;
}
else
{
g_autoptr(GKeyFile) config = ostree_repo_copy_config (self);

/* Remove the existing group if it exists */
if (!g_key_file_remove_group (config, remote->group, &local_error))
{
if (!g_error_matches (local_error, G_KEY_FILE_ERROR,
G_KEY_FILE_ERROR_GROUP_NOT_FOUND))
{
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
}

ot_keyfile_copy_group (remote->options, config, remote->group);
if (!ostree_repo_write_config (self, config, error))
return FALSE;
}
}

return TRUE;
}

/**
* ostree_repo_remote_change:
* @self: Repo
Expand Down Expand Up @@ -1776,6 +1858,9 @@ ostree_repo_remote_change (OstreeRepo *self,
case OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS:
return impl_repo_remote_delete (self, sysroot, TRUE, name,
cancellable, error);
case OSTREE_REPO_REMOTE_CHANGE_REPLACE:
return impl_repo_remote_replace (self, sysroot, name, url, options,
cancellable, error);
}
g_assert_not_reached ();
}
Expand Down
4 changes: 3 additions & 1 deletion src/libostree/ostree-repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,14 @@ gboolean ostree_repo_remote_delete (OstreeRepo *self,
* @OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS: Like above, but do nothing if the remote exists
* @OSTREE_REPO_REMOTE_CHANGE_DELETE: Delete a remote
* @OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS: Delete a remote, do nothing if the remote does not exist
* @OSTREE_REPO_REMOTE_CHANGE_REPLACE: Add or replace a remote (Since: 2019.1)
*/
typedef enum {
OSTREE_REPO_REMOTE_CHANGE_ADD,
OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS,
OSTREE_REPO_REMOTE_CHANGE_DELETE,
OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS
OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS,
OSTREE_REPO_REMOTE_CHANGE_REPLACE,
} OstreeRepoRemoteChange;

_OSTREE_PUBLIC
Expand Down
56 changes: 53 additions & 3 deletions tests/test-remotes-config-dir.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function assertNotEquals(a, b) {
throw new Error("assertion failed " + JSON.stringify(a) + " != " + JSON.stringify(b));
}

print('1..6')
print('1..9')

let remotesDir = Gio.File.new_for_path('remotes.d');
remotesDir.make_directory(null);
Expand All @@ -45,6 +45,10 @@ remoteConfig.set_value('remote "foo"', 'url', 'http://foo')
let remoteConfigFile = remotesDir.get_child('foo.conf')
remoteConfig.save_to_file(remoteConfigFile.get_path())

let remoteOptions = GLib.Variant.new('a{sv}', {
'branches': GLib.Variant.new('as', ['test']),
});

// Use the full Repo constructor to set remotes-config-dir
let repoFile = Gio.File.new_for_path('repo');
let repo = new OSTree.Repo({path: repoFile,
Expand All @@ -60,7 +64,7 @@ print("ok read-remotes-config-dir");

// Adding a remote should not go in the remotes.d dir unless this is a
// system repo or add-remotes-config-dir is set to true
repo.remote_add('bar', 'http://bar', null, null);
repo.remote_add('bar', 'http://bar', remoteOptions, null);
remotes = repo.remote_list()
assertNotEquals(remotes.indexOf('bar'), -1);
assertEquals(remotesDir.get_child('bar.conf').query_exists(null), false);
Expand All @@ -81,7 +85,7 @@ let repoConfig = repo.copy_config();
repoConfig.set_boolean('core', 'add-remotes-config-dir', true);
repo.write_config(repoConfig);
repo.reload_config(null);
repo.remote_add('baz', 'http://baz', null, null);
repo.remote_add('baz', 'http://baz', remoteOptions, null);
remotes = repo.remote_list()
assertNotEquals(remotes.indexOf('baz'), -1);
assertEquals(remotesDir.get_child('baz.conf').query_exists(null), true);
Expand Down Expand Up @@ -114,3 +118,49 @@ try {
}

print("ok config-remote-in-config-dir-fails");

// Replacing a non-existent remote should succeed. This should go in the
// config dir since add-remote-config-dir is set to true above
repo.remote_change(null, OSTree.RepoRemoteChange.REPLACE,
'nonexistent', 'http://nonexistent',
null, null);
remotes = repo.remote_list();
assertNotEquals(remotes.indexOf('nonexistent'), -1);
assertEquals(remotesDir.get_child('nonexistent.conf').query_exists(null), true);

print("ok replace-missing-remote-succeeds");

// Test replacing remote options in config dir. This should remove the
// branches setting above
repo.remote_change(null, OSTree.RepoRemoteChange.REPLACE, 'baz',
'http://baz2', null, null);
remoteConfigFile = remotesDir.get_child('baz.conf');
remoteConfig = GLib.KeyFile.new();
remoteConfig.load_from_file(remoteConfigFile.get_path(),
GLib.KeyFileFlags.NONE);
assertEquals(remoteConfig.get_value('remote "baz"', 'url'), 'http://baz2');
try {
remoteConfig.get_string_list('remote "baz"', 'branches');
throw new Error('baz remote should not have branches option');
} catch (e) {
if (!(e.matches(GLib.KeyFileError, GLib.KeyFileError.KEY_NOT_FOUND)))
throw e;
}

print("ok replace-remote-in-config-dir");

// Test replacing remote options in config file. This should remove the
// branches setting above
repo.remote_change(null, OSTree.RepoRemoteChange.REPLACE, 'bar',
'http://bar2', null, null);
repoConfig = repo.get_config();
assertEquals(repoConfig.get_value('remote "bar"', 'url'), 'http://bar2');
try {
repoConfig.get_string_list('remote "bar"', 'branches');
throw new Error('bar remote should not have branches option');
} catch (e) {
if (!(e.matches(GLib.KeyFileError, GLib.KeyFileError.KEY_NOT_FOUND)))
throw e;
}

print("ok replace-remote-in-config-file");

0 comments on commit 15ba200

Please sign in to comment.