зеркало из https://github.com/microsoft/git.git
interpret-trailers: add option for in-place editing
Add a command line option --in-place to support in-place editing akin to sed -i. This allows to write commands like the following: git interpret-trailers --trailer "X: Y" a.txt > b.txt && mv b.txt a.txt in a more concise way: git interpret-trailers --trailer "X: Y" --in-place a.txt Signed-off-by: Tobias Klauser <tklauser@distanz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
d0d2344ad8
Коммит
e1f898639e
|
@ -8,7 +8,7 @@ git-interpret-trailers - help add structured information into commit messages
|
|||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git interpret-trailers' [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]
|
||||
'git interpret-trailers' [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -64,6 +64,9 @@ folding rules, the encoding rules and probably many other rules.
|
|||
|
||||
OPTIONS
|
||||
-------
|
||||
--in-place::
|
||||
Edit the files in place.
|
||||
|
||||
--trim-empty::
|
||||
If the <value> part of any trailer contains only whitespace,
|
||||
the whole trailer will be removed from the resulting message.
|
||||
|
@ -216,6 +219,25 @@ Signed-off-by: Alice <alice@example.com>
|
|||
Signed-off-by: Bob <bob@example.com>
|
||||
------------
|
||||
|
||||
* Use the '--in-place' option to edit a message file in place:
|
||||
+
|
||||
------------
|
||||
$ cat msg.txt
|
||||
subject
|
||||
|
||||
message
|
||||
|
||||
Signed-off-by: Bob <bob@example.com>
|
||||
$ git interpret-trailers --trailer 'Acked-by: Alice <alice@example.com>' --in-place msg.txt
|
||||
$ cat msg.txt
|
||||
subject
|
||||
|
||||
message
|
||||
|
||||
Signed-off-by: Bob <bob@example.com>
|
||||
Acked-by: Alice <alice@example.com>
|
||||
------------
|
||||
|
||||
* Extract the last commit as a patch, and add a 'Cc' and a
|
||||
'Reviewed-by' trailer to it:
|
||||
+
|
||||
|
|
|
@ -12,16 +12,18 @@
|
|||
#include "trailer.h"
|
||||
|
||||
static const char * const git_interpret_trailers_usage[] = {
|
||||
N_("git interpret-trailers [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"),
|
||||
N_("git interpret-trailers [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"),
|
||||
NULL
|
||||
};
|
||||
|
||||
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int in_place = 0;
|
||||
int trim_empty = 0;
|
||||
struct string_list trailers = STRING_LIST_INIT_DUP;
|
||||
|
||||
struct option options[] = {
|
||||
OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")),
|
||||
OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")),
|
||||
OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"),
|
||||
N_("trailer(s) to add")),
|
||||
|
@ -34,9 +36,12 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
|
|||
if (argc) {
|
||||
int i;
|
||||
for (i = 0; i < argc; i++)
|
||||
process_trailers(argv[i], trim_empty, &trailers);
|
||||
} else
|
||||
process_trailers(NULL, trim_empty, &trailers);
|
||||
process_trailers(argv[i], in_place, trim_empty, &trailers);
|
||||
} else {
|
||||
if (in_place)
|
||||
die(_("no input file given for in-place editing"));
|
||||
process_trailers(NULL, in_place, trim_empty, &trailers);
|
||||
}
|
||||
|
||||
string_list_clear(&trailers, 0);
|
||||
|
||||
|
|
|
@ -326,6 +326,46 @@ test_expect_success 'with complex patch, args and --trim-empty' '
|
|||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'in-place editing with basic patch' '
|
||||
cat basic_message >message &&
|
||||
cat basic_patch >>message &&
|
||||
cat basic_message >expected &&
|
||||
echo >>expected &&
|
||||
cat basic_patch >>expected &&
|
||||
git interpret-trailers --in-place message &&
|
||||
test_cmp expected message
|
||||
'
|
||||
|
||||
test_expect_success 'in-place editing with additional trailer' '
|
||||
cat basic_message >message &&
|
||||
cat basic_patch >>message &&
|
||||
cat basic_message >expected &&
|
||||
echo >>expected &&
|
||||
cat >>expected <<-\EOF &&
|
||||
Reviewed-by: Alice
|
||||
EOF
|
||||
cat basic_patch >>expected &&
|
||||
git interpret-trailers --trailer "Reviewed-by: Alice" --in-place message &&
|
||||
test_cmp expected message
|
||||
'
|
||||
|
||||
test_expect_success 'in-place editing on stdin disallowed' '
|
||||
test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place < basic_message
|
||||
'
|
||||
|
||||
test_expect_success 'in-place editing on non-existing file' '
|
||||
test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place nonexisting &&
|
||||
test_path_is_missing nonexisting
|
||||
'
|
||||
|
||||
test_expect_success POSIXPERM,SANITY "in-place editing doesn't clobber original file on error" '
|
||||
cat basic_message >message &&
|
||||
chmod -r message &&
|
||||
test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place message &&
|
||||
chmod +r message &&
|
||||
test_cmp message basic_message
|
||||
'
|
||||
|
||||
test_expect_success 'using "where = before"' '
|
||||
git config trailer.bug.where "before" &&
|
||||
cat complex_message_body >expected &&
|
||||
|
|
41
trailer.c
41
trailer.c
|
@ -2,6 +2,7 @@
|
|||
#include "string-list.h"
|
||||
#include "run-command.h"
|
||||
#include "commit.h"
|
||||
#include "tempfile.h"
|
||||
#include "trailer.h"
|
||||
/*
|
||||
* Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
|
||||
|
@ -843,7 +844,38 @@ static void free_all(struct trailer_item **first)
|
|||
}
|
||||
}
|
||||
|
||||
void process_trailers(const char *file, int trim_empty, struct string_list *trailers)
|
||||
static struct tempfile trailers_tempfile;
|
||||
|
||||
static FILE *create_in_place_tempfile(const char *file)
|
||||
{
|
||||
struct stat st;
|
||||
struct strbuf template = STRBUF_INIT;
|
||||
const char *tail;
|
||||
FILE *outfile;
|
||||
|
||||
if (stat(file, &st))
|
||||
die_errno(_("could not stat %s"), file);
|
||||
if (!S_ISREG(st.st_mode))
|
||||
die(_("file %s is not a regular file"), file);
|
||||
if (!(st.st_mode & S_IWUSR))
|
||||
die(_("file %s is not writable by user"), file);
|
||||
|
||||
/* Create temporary file in the same directory as the original */
|
||||
tail = strrchr(file, '/');
|
||||
if (tail != NULL)
|
||||
strbuf_add(&template, file, tail - file + 1);
|
||||
strbuf_addstr(&template, "git-interpret-trailers-XXXXXX");
|
||||
|
||||
xmks_tempfile_m(&trailers_tempfile, template.buf, st.st_mode);
|
||||
strbuf_release(&template);
|
||||
outfile = fdopen_tempfile(&trailers_tempfile, "w");
|
||||
if (!outfile)
|
||||
die_errno(_("could not open temporary file"));
|
||||
|
||||
return outfile;
|
||||
}
|
||||
|
||||
void process_trailers(const char *file, int in_place, int trim_empty, struct string_list *trailers)
|
||||
{
|
||||
struct trailer_item *in_tok_first = NULL;
|
||||
struct trailer_item *in_tok_last = NULL;
|
||||
|
@ -858,6 +890,9 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
|
|||
|
||||
lines = read_input_file(file);
|
||||
|
||||
if (in_place)
|
||||
outfile = create_in_place_tempfile(file);
|
||||
|
||||
/* Print the lines before the trailers */
|
||||
trailer_end = process_input_file(outfile, lines, &in_tok_first, &in_tok_last);
|
||||
|
||||
|
@ -872,5 +907,9 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
|
|||
/* Print the lines after the trailers as is */
|
||||
print_lines(outfile, lines, trailer_end, INT_MAX);
|
||||
|
||||
if (in_place)
|
||||
if (rename_tempfile(&trailers_tempfile, file))
|
||||
die_errno(_("could not rename temporary file to %s"), file);
|
||||
|
||||
strbuf_list_free(lines);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef TRAILER_H
|
||||
#define TRAILER_H
|
||||
|
||||
void process_trailers(const char *file, int trim_empty, struct string_list *trailers);
|
||||
void process_trailers(const char *file, int in_place, int trim_empty,
|
||||
struct string_list *trailers);
|
||||
|
||||
#endif /* TRAILER_H */
|
||||
|
|
Загрузка…
Ссылка в новой задаче