From f56688da71273b32a4458d294bd7ccacb0e54c66 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 6 Nov 2015 09:50:17 +0100 Subject: [PATCH] prune: add --keep-younger-than=DATE The format used for DATE is "%Y-%m-%d %H:%M:%S %z" Signed-off-by: Giuseppe Scrivano --- Makefile-ostree.am | 2 + doc/ostree-prune.xml | 8 +++ src/ostree/ot-builtin-prune.c | 125 ++++++++++++++++++++++++++++------ src/ostree/parse-datetime.c | 37 ++++++++++ src/ostree/parse-datetime.h | 31 +++++++++ 5 files changed, 181 insertions(+), 22 deletions(-) create mode 100644 src/ostree/parse-datetime.c create mode 100644 src/ostree/parse-datetime.h diff --git a/Makefile-ostree.am b/Makefile-ostree.am index 8fd426f7..0d0a4ade 100644 --- a/Makefile-ostree.am +++ b/Makefile-ostree.am @@ -48,6 +48,8 @@ ostree_SOURCES = src/ostree/main.c \ src/ostree/ot-dump.c \ src/ostree/ot-editor.c \ src/ostree/ot-editor.h \ + src/ostree/parse-datetime.h \ + src/ostree/parse-datetime.c \ $(NULL) # Admin subcommand diff --git a/doc/ostree-prune.xml b/doc/ostree-prune.xml index 91caa813..03d7fc5c 100644 --- a/doc/ostree-prune.xml +++ b/doc/ostree-prune.xml @@ -89,6 +89,14 @@ Boston, MA 02111-1307, USA. + + =DATE + + + All commits older than DATE will be pruned. + + + =DEPTH diff --git a/src/ostree/ot-builtin-prune.c b/src/ostree/ot-builtin-prune.c index 44868a14..104736ec 100644 --- a/src/ostree/ot-builtin-prune.c +++ b/src/ostree/ot-builtin-prune.c @@ -26,20 +26,115 @@ #include "ot-builtins.h" #include "ostree.h" #include "otutil.h" +#include "parse-datetime.h" static gboolean opt_no_prune; static gint opt_depth = -1; static gboolean opt_refs_only; static char *opt_delete_commit; +static char *opt_keep_younger_than; static GOptionEntry options[] = { { "no-prune", 0, 0, G_OPTION_ARG_NONE, &opt_no_prune, "Only display unreachable objects; don't delete", NULL }, { "refs-only", 0, 0, G_OPTION_ARG_NONE, &opt_refs_only, "Only compute reachability via refs", NULL }, { "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Only traverse DEPTH parents for each commit (default: -1=infinite)", "DEPTH" }, { "delete-commit", 0, 0, G_OPTION_ARG_STRING, &opt_delete_commit, "Specify a commit to delete", "COMMIT" }, + { "keep-younger-than", 0, 0, G_OPTION_ARG_STRING, &opt_keep_younger_than, "Prune all commits older than the specified date", "DATE" }, { NULL } }; +static gboolean +delete_commit (OstreeRepo *repo, const char *commit_to_delete, GCancellable *cancellable, GError **error) +{ + g_autoptr(GHashTable) refs = NULL; + GHashTableIter hashiter; + gpointer hashkey, hashvalue; + gboolean ret = FALSE; + + if (!ostree_repo_list_refs (repo, NULL, &refs, cancellable, error)) + goto out; + + g_hash_table_iter_init (&hashiter, refs); + while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + { + const char *ref = hashkey; + const char *commit = hashvalue; + if (g_strcmp0 (commit_to_delete, commit) == 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Commit '%s' is referenced by '%s'", commit_to_delete, ref); + goto out; + } + } + + if (!ot_enable_tombstone_commits (repo, error)) + goto out; + + if (!ostree_repo_delete_object (repo, OSTREE_OBJECT_TYPE_COMMIT, commit_to_delete, cancellable, error)) + goto out; + + ret = TRUE; + + out: + return ret; +} + +static gboolean +prune_commits_keep_younger_than_date (OstreeRepo *repo, const char *date, GCancellable *cancellable, GError **error) +{ + g_autoptr(GHashTable) objects = NULL; + GHashTableIter hash_iter; + gpointer key, value; + struct timespec ts; + gboolean ret = FALSE; + + if (!parse_datetime (&ts, date, NULL)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Could not parse '%s'", date); + goto out; + } + + if (!ot_enable_tombstone_commits (repo, error)) + goto out; + + if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL, &objects, + cancellable, error)) + goto out; + + g_hash_table_iter_init (&hash_iter, objects); + + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + GVariant *serialized_key = key; + const char *checksum; + OstreeObjectType objtype; + guint64 commit_timestamp; + g_autoptr(GVariant) commit = NULL; + + ostree_object_name_deserialize (serialized_key, &checksum, &objtype); + + if (objtype != OSTREE_OBJECT_TYPE_COMMIT) + continue; + + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, checksum, + &commit, error)) + goto out; + + commit_timestamp = ostree_commit_get_timestamp (commit); + if (commit_timestamp < ts.tv_sec) + { + if (!ostree_repo_delete_object (repo, OSTREE_OBJECT_TYPE_COMMIT, checksum, cancellable, error)) + goto out; + } + } + + ret = TRUE; + + out: + return ret; +} + gboolean ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError **error) { @@ -62,36 +157,22 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * if (opt_delete_commit) { - g_autoptr(GHashTable) refs = NULL; - GHashTableIter hashiter; - gpointer hashkey, hashvalue; - if (opt_no_prune) { ot_util_usage_error (context, "Cannot specify both --delete-commit and --no-prune", error); goto out; } - - if (!ostree_repo_list_refs (repo, NULL, &refs, cancellable, error)) + if (!delete_commit (repo, opt_delete_commit, cancellable, error)) goto out; - - g_hash_table_iter_init (&hashiter, refs); - while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + } + if (opt_keep_younger_than) + { + if (opt_no_prune) { - const char *ref = hashkey; - const char *commit = hashvalue; - if (g_strcmp0 (commit, opt_delete_commit) == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Commit '%s' is referenced by '%s'", opt_delete_commit, ref); - goto out; - } + ot_util_usage_error (context, "Cannot specify both --keep-younger-than and --no-prune", error); + goto out; } - - if (!ot_enable_tombstone_commits (repo, error)) - goto out; - - if (!ostree_repo_delete_object (repo, OSTREE_OBJECT_TYPE_COMMIT, opt_delete_commit, cancellable, error)) + if (!prune_commits_keep_younger_than_date (repo, opt_keep_younger_than, cancellable, error)) goto out; } diff --git a/src/ostree/parse-datetime.c b/src/ostree/parse-datetime.c new file mode 100644 index 00000000..2bf1950f --- /dev/null +++ b/src/ostree/parse-datetime.c @@ -0,0 +1,37 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Red Hat, Inc. + * + * 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. + */ + +#include "parse-datetime.h" +#include + +bool +parse_datetime (struct timespec * result, char const *p, struct timespec const *now) +{ + struct tm tmpresult; + time_t t; + if (strptime (p, "%Y-%m-%d %H:%M:%S %z", &tmpresult) == NULL) + return false; + + t = timegm (&tmpresult); + + result->tv_sec = t; + result->tv_nsec = 0; + return true; +} diff --git a/src/ostree/parse-datetime.h b/src/ostree/parse-datetime.h new file mode 100644 index 00000000..02e3f2b2 --- /dev/null +++ b/src/ostree/parse-datetime.h @@ -0,0 +1,31 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2015 Red Hat, Inc. + * + * 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. + */ + +#pragma once + +#include "config.h" +#include +#include +#include +#include + +G_BEGIN_DECLS +bool parse_datetime (struct timespec *, char const *, struct timespec const *); +G_END_DECLS