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
This commit is contained in:
Stef Walter 2013-08-29 17:23:20 +02:00
parent 1a708accf1
commit a4c3c4ae38
4 changed files with 242 additions and 7 deletions

View File

@ -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

View File

@ -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;

110
src/ostree/ot-editor.c Normal file
View File

@ -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;
}

30
src/ostree/ot-editor.h Normal file
View File

@ -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);