[ostree] ostree: Support for using EDITOR to fill commit subject/body



commit a4c3c4ae38da32e665a8b4fd291adb4d71376eac
Author: Stef Walter <stefw redhat com>
Date:   Thu Aug 29 17:23:20 2013 +0200

    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(-)
---
diff --git a/Makefile-ostree.am b/Makefile-ostree.am
index 4cdde46..19bc85c 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 a62aa8b..ace5aeb 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 0000000..e1ca1a1
--- /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 <stefw redhat com>
+ *
+ * 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 <stefw redhat com>
+ */
+
+#include "config.h"
+
+#include "ot-editor.h"
+#include "libgsystem.h"
+
+#include <sys/wait.h>
+#include <string.h>
+
+#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 0000000..81b6361
--- /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 <stefw redhat com>
+ *
+ * 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 <stefw redhat com>
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+
+#include "ostree.h"
+
+char *  ot_editor_prompt    (OstreeRepo *repo, const char *input,
+                             GCancellable *cancellable, GError **error);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]