From a4c3c4ae38da32e665a8b4fd291adb4d71376eac Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 29 Aug 2013 17:23:20 +0200 Subject: [PATCH] ostree: Support for using EDITOR to fill commit subject/body Behave similar to git when 'ostree commit' is run without a --subject or --body. Bring up an editor. The first line becomes the subject and following lines become the --body after an optional blank line. Use similar logic to git in determining EDITOR https://bugzilla.gnome.org/show_bug.cgi?id=707063 --- Makefile-ostree.am | 2 + src/ostree/ot-builtin-commit.c | 107 +++++++++++++++++++++++++++++--- src/ostree/ot-editor.c | 110 +++++++++++++++++++++++++++++++++ src/ostree/ot-editor.h | 30 +++++++++ 4 files changed, 242 insertions(+), 7 deletions(-) create mode 100644 src/ostree/ot-editor.c create mode 100644 src/ostree/ot-editor.h diff --git a/Makefile-ostree.am b/Makefile-ostree.am index 4cdde468..19bc85cc 100644 --- a/Makefile-ostree.am +++ b/Makefile-ostree.am @@ -44,6 +44,8 @@ ostree_SOURCES = src/ostree/main.c \ src/ostree/ot-main.c \ src/ostree/ot-dump.h \ src/ostree/ot-dump.c \ + src/ostree/ot-editor.c \ + src/ostree/ot-editor.h \ $(NULL) # Admin subcommand diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index a62aa8bf..ace5aeb5 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -23,6 +23,7 @@ #include "config.h" #include "ot-builtins.h" +#include "ot-editor.h" #include "ostree.h" #include "otutil.h" @@ -134,6 +135,92 @@ commit_filter (OstreeRepo *self, return OSTREE_REPO_COMMIT_FILTER_ALLOW; } +static gboolean +commit_editor (OstreeRepo *repo, + const char *branch, + char **subject, + char **body, + GCancellable *cancellable, + GError **error) +{ + const char *template = + "\n" + "# Please enter the commit message for your changes. The first line will\n" + "# become the subject, and the remainder the body. Lines starting\n" + "# with '#' will be ignored, and an empty message aborts the commit.\n" + "#\n" + "# Branch: %s\n"; + + gs_free char *input = NULL; + gs_free char *output = NULL; + gboolean ret = FALSE; + GString *bodybuf = NULL; + char **lines = NULL; + int i; + + *subject = NULL; + *body = NULL; + + input = g_strdup_printf (template, branch); + + output = ot_editor_prompt (repo, input, cancellable, error); + if (output == NULL) + goto out; + + lines = g_strsplit (output, "\n", -1); + for (i = 0; lines[i] != NULL; i++) + { + g_strchomp (lines[i]); + + /* Lines starting with # are skipped */ + if (lines[i][0] == '#') + continue; + + /* Blank lines before body starts are skipped */ + if (lines[i][0] == '\0') + { + if (!bodybuf) + continue; + } + + if (!*subject) + { + *subject = g_strdup (lines[i]); + } + else if (!bodybuf) + { + bodybuf = g_string_new (lines[i]); + } + else + { + g_string_append_c (bodybuf, '\n'); + g_string_append (bodybuf, lines[i]); + } + } + + if (!*subject) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Aborting commit due to empty commit subject."); + goto out; + } + + if (bodybuf) + { + *body = g_string_free (bodybuf, FALSE); + g_strchomp (*body); + bodybuf = NULL; + } + + ret = TRUE; + +out: + g_strfreev (lines); + if (bodybuf) + g_string_free (bodybuf, TRUE); + return ret; +} + gboolean ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error) { @@ -179,13 +266,6 @@ ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *ca goto out; } - if (!opt_subject) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "A subject must be specified with --subject"); - goto out; - } - if (opt_owner_uid >= 0 || opt_owner_gid >= 0 || opt_statoverride_file != NULL || opt_no_xattrs) { @@ -205,6 +285,19 @@ ostree_builtin_commit (int argc, char **argv, OstreeRepo *repo, GCancellable *ca goto out; } + if (!opt_subject && !opt_body) + { + if (!commit_editor (repo, opt_branch, &opt_subject, &opt_body, cancellable, error)) + goto out; + } + + if (!opt_subject) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "A subject must be specified with --subject"); + goto out; + } + if (!ostree_repo_prepare_transaction (repo, opt_link_checkout_speedup, NULL, cancellable, error)) goto out; diff --git a/src/ostree/ot-editor.c b/src/ostree/ot-editor.c new file mode 100644 index 00000000..e1ca1a18 --- /dev/null +++ b/src/ostree/ot-editor.c @@ -0,0 +1,110 @@ +/* -*- 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-editor.h" +#include "libgsystem.h" + +#include +#include + +#ifndef DEFAULT_EDITOR +#define DEFAULT_EDITOR "vi" +#endif + +/* Logic pulled from git */ + +static const char * +get_editor (void) +{ + const char *editor = g_getenv ("OSTREE_EDITOR"); + const char *terminal = g_getenv ("TERM"); + int terminal_is_dumb = !terminal || g_str_equal (terminal, "dumb"); + + if (!editor && !terminal_is_dumb) + editor = g_getenv ("VISUAL"); + if (!editor) + editor = g_getenv ("EDITOR"); + + if (!editor && terminal_is_dumb) + return NULL; + + if (!editor) + editor = DEFAULT_EDITOR; + + return editor; +} + +char * +ot_editor_prompt (OstreeRepo *repo, + const char *input, + GCancellable *cancellable, + GError **error) +{ + gs_unref_object GSSubprocessContext *ctx = NULL; + gs_unref_object GSSubprocess *proc = NULL; + gs_unref_object GFile *file = NULL; + gs_unref_object GFileIOStream *io = NULL; + GOutputStream *output; + const char *editor; + char *ret = NULL; + + editor = get_editor (); + if (editor == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Terminal is dumb, but EDITOR unset"); + goto out; + } + + file = g_file_new_tmp (NULL, &io, error); + if (file == NULL) + goto out; + + output = g_io_stream_get_output_stream (G_IO_STREAM (io)); + if (!g_output_stream_write_all (output, input, strlen (input), NULL, cancellable, error) || + !g_io_stream_close (G_IO_STREAM (io), cancellable, error)) + goto out; + + ctx = gs_subprocess_context_newv (editor, gs_file_get_path_cached (file), NULL); + gs_subprocess_context_set_stdin_disposition (ctx, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT); + gs_subprocess_context_set_stdout_disposition (ctx, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT); + gs_subprocess_context_set_stderr_disposition (ctx, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT); + + proc = gs_subprocess_new (ctx, cancellable, error); + if (proc == NULL) + goto out; + + if (!gs_subprocess_wait_sync_check (proc, cancellable, error)) + { + g_prefix_error (error, "There was a problem with the editor '%s'.", editor); + goto out; + } + + ret = gs_file_load_contents_utf8 (file, cancellable, error); + +out: + if (file) + (void )g_file_delete (file, NULL, NULL); + return ret; +} diff --git a/src/ostree/ot-editor.h b/src/ostree/ot-editor.h new file mode 100644 index 00000000..81b6361e --- /dev/null +++ b/src/ostree/ot-editor.h @@ -0,0 +1,30 @@ +/* -*- 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 + */ + +#pragma once + +#include + +#include "ostree.h" + +char * ot_editor_prompt (OstreeRepo *repo, const char *input, + GCancellable *cancellable, GError **error);