11#include "cache.h"
22#include "string-list.h"
3+ #include "run-command.h"
4+ #include "string-list.h"
35#include "trailer.h"
46/*
57 * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
@@ -33,6 +35,8 @@ static struct trailer_item *first_conf_item;
3335
3436static char * separators = ":" ;
3537
38+ #define TRAILER_ARG_STRING "$ARG"
39+
3640static int after_or_end (enum action_where where )
3741{
3842 return (where == WHERE_AFTER ) || (where == WHERE_END );
@@ -78,6 +82,13 @@ static inline int contains_only_spaces(const char *str)
7882 return !* s ;
7983}
8084
85+ static inline void strbuf_replace (struct strbuf * sb , const char * a , const char * b )
86+ {
87+ const char * ptr = strstr (sb -> buf , a );
88+ if (ptr )
89+ strbuf_splice (sb , ptr - sb -> buf , strlen (a ), b , strlen (b ));
90+ }
91+
8192static void free_trailer_item (struct trailer_item * item )
8293{
8394 free (item -> conf .name );
@@ -203,6 +214,63 @@ static struct trailer_item *remove_first(struct trailer_item **first)
203214 return item ;
204215}
205216
217+ static int read_from_command (struct child_process * cp , struct strbuf * buf )
218+ {
219+ if (run_command (cp ))
220+ return error ("running trailer command '%s' failed" , cp -> argv [0 ]);
221+ if (strbuf_read (buf , cp -> out , 1024 ) < 1 )
222+ return error ("reading from trailer command '%s' failed" , cp -> argv [0 ]);
223+ strbuf_trim (buf );
224+ return 0 ;
225+ }
226+
227+ static const char * apply_command (const char * command , const char * arg )
228+ {
229+ struct strbuf cmd = STRBUF_INIT ;
230+ struct strbuf buf = STRBUF_INIT ;
231+ struct child_process cp ;
232+ const char * argv [] = {NULL , NULL };
233+ const char * result ;
234+
235+ strbuf_addstr (& cmd , command );
236+ if (arg )
237+ strbuf_replace (& cmd , TRAILER_ARG_STRING , arg );
238+
239+ argv [0 ] = cmd .buf ;
240+ memset (& cp , 0 , sizeof (cp ));
241+ cp .argv = argv ;
242+ cp .env = local_repo_env ;
243+ cp .no_stdin = 1 ;
244+ cp .out = -1 ;
245+ cp .use_shell = 1 ;
246+
247+ if (read_from_command (& cp , & buf )) {
248+ strbuf_release (& buf );
249+ result = xstrdup ("" );
250+ } else
251+ result = strbuf_detach (& buf , NULL );
252+
253+ strbuf_release (& cmd );
254+ return result ;
255+ }
256+
257+ static void apply_item_command (struct trailer_item * in_tok , struct trailer_item * arg_tok )
258+ {
259+ if (arg_tok -> conf .command ) {
260+ const char * arg ;
261+ if (arg_tok -> value && arg_tok -> value [0 ]) {
262+ arg = arg_tok -> value ;
263+ } else {
264+ if (in_tok && in_tok -> value )
265+ arg = xstrdup (in_tok -> value );
266+ else
267+ arg = xstrdup ("" );
268+ }
269+ arg_tok -> value = apply_command (arg_tok -> conf .command , arg );
270+ free ((char * )arg );
271+ }
272+ }
273+
206274static void apply_arg_if_exists (struct trailer_item * in_tok ,
207275 struct trailer_item * arg_tok ,
208276 struct trailer_item * on_tok ,
@@ -214,23 +282,27 @@ static void apply_arg_if_exists(struct trailer_item *in_tok,
214282 free_trailer_item (arg_tok );
215283 break ;
216284 case EXISTS_REPLACE :
285+ apply_item_command (in_tok , arg_tok );
217286 add_arg_to_input_list (on_tok , arg_tok ,
218287 in_tok_first , in_tok_last );
219288 remove_from_list (in_tok , in_tok_first , in_tok_last );
220289 free_trailer_item (in_tok );
221290 break ;
222291 case EXISTS_ADD :
292+ apply_item_command (in_tok , arg_tok );
223293 add_arg_to_input_list (on_tok , arg_tok ,
224294 in_tok_first , in_tok_last );
225295 break ;
226296 case EXISTS_ADD_IF_DIFFERENT :
297+ apply_item_command (in_tok , arg_tok );
227298 if (check_if_different (in_tok , arg_tok , 1 ))
228299 add_arg_to_input_list (on_tok , arg_tok ,
229300 in_tok_first , in_tok_last );
230301 else
231302 free_trailer_item (arg_tok );
232303 break ;
233304 case EXISTS_ADD_IF_DIFFERENT_NEIGHBOR :
305+ apply_item_command (in_tok , arg_tok );
234306 if (check_if_different (on_tok , arg_tok , 0 ))
235307 add_arg_to_input_list (on_tok , arg_tok ,
236308 in_tok_first , in_tok_last );
@@ -254,6 +326,7 @@ static void apply_arg_if_missing(struct trailer_item **in_tok_first,
254326 case MISSING_ADD :
255327 where = arg_tok -> conf .where ;
256328 in_tok = after_or_end (where ) ? in_tok_last : in_tok_first ;
329+ apply_item_command (NULL , arg_tok );
257330 if (* in_tok ) {
258331 add_arg_to_input_list (* in_tok , arg_tok ,
259332 in_tok_first , in_tok_last );
@@ -537,7 +610,7 @@ static struct trailer_item *new_trailer_item(struct trailer_item *conf_item,
537610 char * tok , char * val )
538611{
539612 struct trailer_item * new = xcalloc (sizeof (* new ), 1 );
540- new -> value = val ;
613+ new -> value = val ? val : xstrdup ( "" ) ;
541614
542615 if (conf_item ) {
543616 duplicate_conf (& new -> conf , & conf_item -> conf );
@@ -604,7 +677,17 @@ static struct trailer_item *process_command_line_args(struct string_list *traile
604677 struct trailer_item * arg_tok_first = NULL ;
605678 struct trailer_item * arg_tok_last = NULL ;
606679 struct string_list_item * tr ;
680+ struct trailer_item * item ;
681+
682+ /* Add a trailer item for each configured trailer with a command */
683+ for (item = first_conf_item ; item ; item = item -> next ) {
684+ if (item -> conf .command ) {
685+ struct trailer_item * new = new_trailer_item (item , NULL , NULL );
686+ add_trailer_item (& arg_tok_first , & arg_tok_last , new );
687+ }
688+ }
607689
690+ /* Add a trailer item for each trailer on the command line */
608691 for_each_string_list_item (tr , trailers ) {
609692 struct trailer_item * new = create_trailer_item (tr -> string );
610693 add_trailer_item (& arg_tok_first , & arg_tok_last , new );
0 commit comments