@@ -266,13 +266,22 @@ static int queue_or_write_archive_entry(const struct object_id *oid,
266
266
stage , context );
267
267
}
268
268
269
+ struct extra_file_info {
270
+ char * base ;
271
+ struct stat stat ;
272
+ };
273
+
269
274
int write_archive_entries (struct archiver_args * args ,
270
275
write_archive_entry_fn_t write_entry )
271
276
{
272
277
struct archiver_context context ;
273
278
struct unpack_trees_options opts ;
274
279
struct tree_desc t ;
275
280
int err ;
281
+ struct strbuf path_in_archive = STRBUF_INIT ;
282
+ struct strbuf content = STRBUF_INIT ;
283
+ struct object_id fake_oid = null_oid ;
284
+ int i ;
276
285
277
286
if (args -> baselen > 0 && args -> base [args -> baselen - 1 ] == '/' ) {
278
287
size_t len = args -> baselen ;
@@ -318,6 +327,33 @@ int write_archive_entries(struct archiver_args *args,
318
327
free (context .bottom );
319
328
context .bottom = next ;
320
329
}
330
+
331
+ for (i = 0 ; i < args -> extra_files .nr ; i ++ ) {
332
+ struct string_list_item * item = args -> extra_files .items + i ;
333
+ char * path = item -> string ;
334
+ struct extra_file_info * info = item -> util ;
335
+
336
+ put_be64 (fake_oid .hash , i + 1 );
337
+
338
+ strbuf_reset (& path_in_archive );
339
+ if (info -> base )
340
+ strbuf_addstr (& path_in_archive , info -> base );
341
+ strbuf_addstr (& path_in_archive , basename (path ));
342
+
343
+ strbuf_reset (& content );
344
+ if (strbuf_read_file (& content , path , info -> stat .st_size ) < 0 )
345
+ err = error_errno (_ ("could not read '%s'" ), path );
346
+ else
347
+ err = write_entry (args , & fake_oid , path_in_archive .buf ,
348
+ path_in_archive .len ,
349
+ info -> stat .st_mode ,
350
+ content .buf , content .len );
351
+ if (err )
352
+ break ;
353
+ }
354
+ strbuf_release (& path_in_archive );
355
+ strbuf_release (& content );
356
+
321
357
return err ;
322
358
}
323
359
@@ -457,6 +493,42 @@ static void parse_treeish_arg(const char **argv,
457
493
ar_args -> time = archive_time ;
458
494
}
459
495
496
+ static void extra_file_info_clear (void * util , const char * str )
497
+ {
498
+ struct extra_file_info * info = util ;
499
+ free (info -> base );
500
+ free (info );
501
+ }
502
+
503
+ static int add_file_cb (const struct option * opt , const char * arg , int unset )
504
+ {
505
+ struct archiver_args * args = opt -> value ;
506
+ const char * * basep = (const char * * )opt -> defval ;
507
+ const char * base = * basep ;
508
+ char * path ;
509
+ struct string_list_item * item ;
510
+ struct extra_file_info * info ;
511
+
512
+ if (unset ) {
513
+ string_list_clear_func (& args -> extra_files ,
514
+ extra_file_info_clear );
515
+ return 0 ;
516
+ }
517
+
518
+ if (!arg )
519
+ return -1 ;
520
+
521
+ path = prefix_filename (args -> prefix , arg );
522
+ item = string_list_append_nodup (& args -> extra_files , path );
523
+ item -> util = info = xmalloc (sizeof (* info ));
524
+ info -> base = xstrdup_or_null (base );
525
+ if (stat (path , & info -> stat ))
526
+ die (_ ("File not found: %s" ), path );
527
+ if (!S_ISREG (info -> stat .st_mode ))
528
+ die (_ ("Not a regular file: %s" ), path );
529
+ return 0 ;
530
+ }
531
+
460
532
#define OPT__COMPR (s , v , h , p ) \
461
533
OPT_SET_INT_F(s, NULL, v, h, p, PARSE_OPT_NONEG)
462
534
#define OPT__COMPR_HIDDEN (s , v , p ) \
@@ -481,6 +553,9 @@ static int parse_archive_args(int argc, const char **argv,
481
553
OPT_STRING (0 , "format" , & format , N_ ("fmt" ), N_ ("archive format" )),
482
554
OPT_STRING (0 , "prefix" , & base , N_ ("prefix" ),
483
555
N_ ("prepend prefix to each pathname in the archive" )),
556
+ { OPTION_CALLBACK , 0 , "add-file" , args , N_ ("file" ),
557
+ N_ ("add untracked file to archive" ), 0 , add_file_cb ,
558
+ (intptr_t )& base },
484
559
OPT_STRING ('o' , "output" , & output , N_ ("file" ),
485
560
N_ ("write the archive to this file" )),
486
561
OPT_BOOL (0 , "worktree-attributes" , & worktree_attributes ,
@@ -515,6 +590,8 @@ static int parse_archive_args(int argc, const char **argv,
515
590
die (_ ("Option --exec can only be used together with --remote" ));
516
591
if (output )
517
592
die (_ ("Unexpected option --output" ));
593
+ if (is_remote && args -> extra_files .nr )
594
+ die (_ ("Options --add-file and --remote cannot be used together" ));
518
595
519
596
if (!base )
520
597
base = "" ;
@@ -561,11 +638,14 @@ int write_archive(int argc, const char **argv, const char *prefix,
561
638
{
562
639
const struct archiver * ar = NULL ;
563
640
struct archiver_args args ;
641
+ int rc ;
564
642
565
643
git_config_get_bool ("uploadarchive.allowunreachable" , & remote_allow_unreachable );
566
644
git_config (git_default_config , NULL );
567
645
568
646
args .repo = repo ;
647
+ args .prefix = prefix ;
648
+ string_list_init (& args .extra_files , 1 );
569
649
argc = parse_archive_args (argc , argv , & ar , & args , name_hint , remote );
570
650
if (!startup_info -> have_repository ) {
571
651
/*
@@ -579,7 +659,11 @@ int write_archive(int argc, const char **argv, const char *prefix,
579
659
parse_treeish_arg (argv , & args , prefix , remote );
580
660
parse_pathspec_arg (argv + 1 , & args );
581
661
582
- return ar -> write_archive (ar , & args );
662
+ rc = ar -> write_archive (ar , & args );
663
+
664
+ string_list_clear_func (& args .extra_files , extra_file_info_clear );
665
+
666
+ return rc ;
583
667
}
584
668
585
669
static int match_extension (const char * filename , const char * ext )
0 commit comments