Skip to content

Commit e1f8986

Browse files
tklausergitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d0d2344 commit e1f8986

File tree

5 files changed

+114
-7
lines changed

5 files changed

+114
-7
lines changed

Documentation/git-interpret-trailers.txt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ git-interpret-trailers - help add structured information into commit messages
88
SYNOPSIS
99
--------
1010
[verse]
11-
'git interpret-trailers' [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]
11+
'git interpret-trailers' [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]
1212

1313
DESCRIPTION
1414
-----------
@@ -64,6 +64,9 @@ folding rules, the encoding rules and probably many other rules.
6464

6565
OPTIONS
6666
-------
67+
--in-place::
68+
Edit the files in place.
69+
6770
--trim-empty::
6871
If the <value> part of any trailer contains only whitespace,
6972
the whole trailer will be removed from the resulting message.
@@ -216,6 +219,25 @@ Signed-off-by: Alice <[email protected]>
216219
Signed-off-by: Bob <[email protected]>
217220
------------
218221

222+
* Use the '--in-place' option to edit a message file in place:
223+
+
224+
------------
225+
$ cat msg.txt
226+
subject
227+
228+
message
229+
230+
Signed-off-by: Bob <[email protected]>
231+
$ git interpret-trailers --trailer 'Acked-by: Alice <[email protected]>' --in-place msg.txt
232+
$ cat msg.txt
233+
subject
234+
235+
message
236+
237+
Signed-off-by: Bob <[email protected]>
238+
Acked-by: Alice <[email protected]>
239+
------------
240+
219241
* Extract the last commit as a patch, and add a 'Cc' and a
220242
'Reviewed-by' trailer to it:
221243
+

builtin/interpret-trailers.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,18 @@
1212
#include "trailer.h"
1313

1414
static const char * const git_interpret_trailers_usage[] = {
15-
N_("git interpret-trailers [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"),
15+
N_("git interpret-trailers [--in-place] [--trim-empty] [(--trailer <token>[(=|:)<value>])...] [<file>...]"),
1616
NULL
1717
};
1818

1919
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
2020
{
21+
int in_place = 0;
2122
int trim_empty = 0;
2223
struct string_list trailers = STRING_LIST_INIT_DUP;
2324

2425
struct option options[] = {
26+
OPT_BOOL(0, "in-place", &in_place, N_("edit files in place")),
2527
OPT_BOOL(0, "trim-empty", &trim_empty, N_("trim empty trailers")),
2628
OPT_STRING_LIST(0, "trailer", &trailers, N_("trailer"),
2729
N_("trailer(s) to add")),
@@ -34,9 +36,12 @@ int cmd_interpret_trailers(int argc, const char **argv, const char *prefix)
3436
if (argc) {
3537
int i;
3638
for (i = 0; i < argc; i++)
37-
process_trailers(argv[i], trim_empty, &trailers);
38-
} else
39-
process_trailers(NULL, trim_empty, &trailers);
39+
process_trailers(argv[i], in_place, trim_empty, &trailers);
40+
} else {
41+
if (in_place)
42+
die(_("no input file given for in-place editing"));
43+
process_trailers(NULL, in_place, trim_empty, &trailers);
44+
}
4045

4146
string_list_clear(&trailers, 0);
4247

t/t7513-interpret-trailers.sh

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,46 @@ test_expect_success 'with complex patch, args and --trim-empty' '
326326
test_cmp expected actual
327327
'
328328

329+
test_expect_success 'in-place editing with basic patch' '
330+
cat basic_message >message &&
331+
cat basic_patch >>message &&
332+
cat basic_message >expected &&
333+
echo >>expected &&
334+
cat basic_patch >>expected &&
335+
git interpret-trailers --in-place message &&
336+
test_cmp expected message
337+
'
338+
339+
test_expect_success 'in-place editing with additional trailer' '
340+
cat basic_message >message &&
341+
cat basic_patch >>message &&
342+
cat basic_message >expected &&
343+
echo >>expected &&
344+
cat >>expected <<-\EOF &&
345+
Reviewed-by: Alice
346+
EOF
347+
cat basic_patch >>expected &&
348+
git interpret-trailers --trailer "Reviewed-by: Alice" --in-place message &&
349+
test_cmp expected message
350+
'
351+
352+
test_expect_success 'in-place editing on stdin disallowed' '
353+
test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place < basic_message
354+
'
355+
356+
test_expect_success 'in-place editing on non-existing file' '
357+
test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place nonexisting &&
358+
test_path_is_missing nonexisting
359+
'
360+
361+
test_expect_success POSIXPERM,SANITY "in-place editing doesn't clobber original file on error" '
362+
cat basic_message >message &&
363+
chmod -r message &&
364+
test_must_fail git interpret-trailers --trailer "Reviewed-by: Alice" --in-place message &&
365+
chmod +r message &&
366+
test_cmp message basic_message
367+
'
368+
329369
test_expect_success 'using "where = before"' '
330370
git config trailer.bug.where "before" &&
331371
cat complex_message_body >expected &&

trailer.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "string-list.h"
33
#include "run-command.h"
44
#include "commit.h"
5+
#include "tempfile.h"
56
#include "trailer.h"
67
/*
78
* Copyright (c) 2013, 2014 Christian Couder <[email protected]>
@@ -843,7 +844,38 @@ static void free_all(struct trailer_item **first)
843844
}
844845
}
845846

846-
void process_trailers(const char *file, int trim_empty, struct string_list *trailers)
847+
static struct tempfile trailers_tempfile;
848+
849+
static FILE *create_in_place_tempfile(const char *file)
850+
{
851+
struct stat st;
852+
struct strbuf template = STRBUF_INIT;
853+
const char *tail;
854+
FILE *outfile;
855+
856+
if (stat(file, &st))
857+
die_errno(_("could not stat %s"), file);
858+
if (!S_ISREG(st.st_mode))
859+
die(_("file %s is not a regular file"), file);
860+
if (!(st.st_mode & S_IWUSR))
861+
die(_("file %s is not writable by user"), file);
862+
863+
/* Create temporary file in the same directory as the original */
864+
tail = strrchr(file, '/');
865+
if (tail != NULL)
866+
strbuf_add(&template, file, tail - file + 1);
867+
strbuf_addstr(&template, "git-interpret-trailers-XXXXXX");
868+
869+
xmks_tempfile_m(&trailers_tempfile, template.buf, st.st_mode);
870+
strbuf_release(&template);
871+
outfile = fdopen_tempfile(&trailers_tempfile, "w");
872+
if (!outfile)
873+
die_errno(_("could not open temporary file"));
874+
875+
return outfile;
876+
}
877+
878+
void process_trailers(const char *file, int in_place, int trim_empty, struct string_list *trailers)
847879
{
848880
struct trailer_item *in_tok_first = NULL;
849881
struct trailer_item *in_tok_last = NULL;
@@ -858,6 +890,9 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
858890

859891
lines = read_input_file(file);
860892

893+
if (in_place)
894+
outfile = create_in_place_tempfile(file);
895+
861896
/* Print the lines before the trailers */
862897
trailer_end = process_input_file(outfile, lines, &in_tok_first, &in_tok_last);
863898

@@ -872,5 +907,9 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
872907
/* Print the lines after the trailers as is */
873908
print_lines(outfile, lines, trailer_end, INT_MAX);
874909

910+
if (in_place)
911+
if (rename_tempfile(&trailers_tempfile, file))
912+
die_errno(_("could not rename temporary file to %s"), file);
913+
875914
strbuf_list_free(lines);
876915
}

trailer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef TRAILER_H
22
#define TRAILER_H
33

4-
void process_trailers(const char *file, int trim_empty, struct string_list *trailers);
4+
void process_trailers(const char *file, int in_place, int trim_empty,
5+
struct string_list *trailers);
56

67
#endif /* TRAILER_H */

0 commit comments

Comments
 (0)