diff --git a/Makefile-ostree.am b/Makefile-ostree.am index ccfd3742..58aa6769 100644 --- a/Makefile-ostree.am +++ b/Makefile-ostree.am @@ -36,6 +36,7 @@ ostree_SOURCES = src/ostree/main.c \ src/ostree/ot-builtin-prune.c \ src/ostree/ot-builtin-refs.c \ src/ostree/ot-builtin-remote.c \ + src/ostree/ot-builtin-reset.c \ src/ostree/ot-builtin-rev-parse.c \ src/ostree/ot-builtin-show.c \ src/ostree/ot-builtin-write-refs.c \ diff --git a/src/ostree/main.c b/src/ostree/main.c index 15420958..ae0e3ce4 100644 --- a/src/ostree/main.c +++ b/src/ostree/main.c @@ -43,6 +43,7 @@ static OstreeCommand commands[] = { { "log", ostree_builtin_log, 0 }, { "ls", ostree_builtin_ls, 0 }, { "refs", ostree_builtin_refs, 0 }, + { "reset", ostree_builtin_reset, 0 }, { "prune", ostree_builtin_prune, 0 }, #ifdef HAVE_LIBSOUP { "pull", ostree_builtin_pull, 0 }, diff --git a/src/ostree/ot-builtin-reset.c b/src/ostree/ot-builtin-reset.c new file mode 100644 index 00000000..44e0450c --- /dev/null +++ b/src/ostree/ot-builtin-reset.c @@ -0,0 +1,134 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013 Stef Walter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Stef Walter + */ + +#include "config.h" + +#include "ot-builtins.h" +#include "ostree.h" +#include "otutil.h" + +static GOptionEntry options[] = { + { NULL } +}; + +static gchar * +find_current_ref (OstreeRepo *repo, + const gchar *ref, + GCancellable *cancellable, + GError **error) +{ + gs_unref_hashtable GHashTable *refs = NULL; + gchar *ret; + + if (!ostree_repo_list_refs (repo, NULL, &refs, cancellable, error)) + return NULL; + ret = g_strdup (g_hash_table_lookup (refs, ref)); + if (ret == NULL) + g_set_error (error, G_IO_ERROR, G_IO_ERROR, "The ref was not found: %s", ref); + + return ret; +} + +static gboolean +check_revision_is_parent (OstreeRepo *repo, + const char *descendant, + const char *ancestor, + GCancellable *cancellable, + GError **error) +{ + gs_free char *parent = NULL; + gs_unref_variant GVariant *variant = NULL; + gboolean ret = FALSE; + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + descendant, &variant, error)) + goto out; + + parent = ostree_commit_get_parent (variant); + if (!parent) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "The ref does not have this commit as an ancestor: %s", ancestor); + goto out; + } + + if (!g_str_equal (parent, ancestor) && + !check_revision_is_parent (repo, parent, ancestor, cancellable, error)) + goto out; + + ret = TRUE; +out: + return ret; +} + +gboolean +ostree_builtin_reset (int argc, + char **argv, + GFile *repo_path, + GCancellable *cancellable, + GError **error) +{ + GOptionContext *context; + gboolean ret = FALSE; + const char *ref; + const char *target = NULL; + gs_unref_object OstreeRepo *repo = NULL; + gs_free gchar *current = NULL; + gs_free gchar *checksum = NULL; + + context = g_option_context_new ("[ARG] - Reset a ref to a previous commit"); + g_option_context_add_main_entries (context, options, NULL); + + if (!g_option_context_parse (context, &argc, &argv, error)) + goto out; + + repo = ostree_repo_new (repo_path); + if (!ostree_repo_check (repo, error)) + goto out; + + if (argc <= 2) + { + ot_util_usage_error (context, "A ref and commit argument is required", error); + goto out; + } + ref = argv[1]; + target = argv[2]; + + if (!ostree_repo_resolve_rev (repo, target, FALSE, &checksum, error)) + goto out; + + current = find_current_ref (repo, ref, cancellable, error); + if (current == NULL) + goto out; + + if (!check_revision_is_parent (repo, current, checksum, cancellable, error)) + goto out; + + if (!ostree_repo_write_ref (repo, NULL, ref, checksum, error)) + goto out; + + ret = TRUE; + out: + if (context) + g_option_context_free (context); + return ret; +} diff --git a/src/ostree/ot-builtins.h b/src/ostree/ot-builtins.h index 69af3737..4fbb4c17 100644 --- a/src/ostree/ot-builtins.h +++ b/src/ostree/ot-builtins.h @@ -40,6 +40,7 @@ gboolean ostree_builtin_pull_local (int argc, char **argv, GFile *repo_path, GCa gboolean ostree_builtin_ls (int argc, char **argv, GFile *repo_path, GCancellable *cancellable, GError **error); gboolean ostree_builtin_prune (int argc, char **argv, GFile *repo_path, GCancellable *cancellable, GError **error); gboolean ostree_builtin_refs (int argc, char **argv, GFile *repo_path, GCancellable *cancellable, GError **error); +gboolean ostree_builtin_reset (int argc, char **argv, GFile *repo_path, GCancellable *cancellable, GError **error); gboolean ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GCancellable *cancellable, GError **error); gboolean ostree_builtin_show (int argc, char **argv, GFile *repo_path, GCancellable *cancellable, GError **error); gboolean ostree_builtin_rev_parse (int argc, char **argv, GFile *repo_path, GCancellable *cancellable, GError **error); diff --git a/tests/test-basic.sh b/tests/test-basic.sh index 154a93df..de372bdb 100755 --- a/tests/test-basic.sh +++ b/tests/test-basic.sh @@ -19,7 +19,7 @@ set -e -echo "1..38" +echo "1..39" . $(dirname $0)/libtest.sh @@ -265,3 +265,13 @@ assert_file_has_content log-output "commit $checksum1" assert_file_has_content log-output "Second commit" assert_file_has_content log-output "commit $checksum2" echo "ok log output" + +cd ${test_tmpdir} +checksum1=$($OSTREE commit -b test6 -s "First commit") +checksum2=$($OSTREE commit -b test6 -s "Second commit") +$OSTREE show test6 > show-output +assert_file_has_content show-output "commit $checksum2" +$OSTREE reset test6 $checksum1 +$OSTREE show test6 > show-output +assert_file_has_content show-output "commit $checksum1" +echo "ok basic reset"