@@ -611,6 +611,150 @@ void parse_path_pattern(const char **pattern,
611
611
* patternlen = len ;
612
612
}
613
613
614
+ static int pl_hashmap_cmp (const void * unused_cmp_data ,
615
+ const struct hashmap_entry * a ,
616
+ const struct hashmap_entry * b ,
617
+ const void * key )
618
+ {
619
+ const struct pattern_entry * ee1 =
620
+ container_of (a , struct pattern_entry , ent );
621
+ const struct pattern_entry * ee2 =
622
+ container_of (b , struct pattern_entry , ent );
623
+
624
+ size_t min_len = ee1 -> patternlen <= ee2 -> patternlen
625
+ ? ee1 -> patternlen
626
+ : ee2 -> patternlen ;
627
+
628
+ return strncmp (ee1 -> pattern , ee2 -> pattern , min_len );
629
+ }
630
+
631
+ static void add_pattern_to_hashsets (struct pattern_list * pl , struct path_pattern * given )
632
+ {
633
+ struct pattern_entry * translated ;
634
+ char * truncated ;
635
+ char * data = NULL ;
636
+
637
+ if (!pl -> use_cone_patterns )
638
+ return ;
639
+
640
+ if (given -> flags & PATTERN_FLAG_NEGATIVE &&
641
+ given -> flags & PATTERN_FLAG_MUSTBEDIR &&
642
+ !strcmp (given -> pattern , "/*" )) {
643
+ pl -> full_cone = 0 ;
644
+ return ;
645
+ }
646
+
647
+ if (!given -> flags && !strcmp (given -> pattern , "/*" )) {
648
+ pl -> full_cone = 1 ;
649
+ return ;
650
+ }
651
+
652
+ if (given -> patternlen > 2 &&
653
+ !strcmp (given -> pattern + given -> patternlen - 2 , "/*" )) {
654
+ if (!(given -> flags & PATTERN_FLAG_NEGATIVE )) {
655
+ /* Not a cone pattern. */
656
+ pl -> use_cone_patterns = 0 ;
657
+ warning (_ ("unrecognized pattern: '%s'" ), given -> pattern );
658
+ goto clear_hashmaps ;
659
+ }
660
+
661
+ truncated = xstrdup (given -> pattern );
662
+ truncated [given -> patternlen - 2 ] = 0 ;
663
+
664
+ translated = xmalloc (sizeof (struct pattern_entry ));
665
+ translated -> pattern = truncated ;
666
+ translated -> patternlen = given -> patternlen - 2 ;
667
+ hashmap_entry_init (& translated -> ent ,
668
+ memhash (translated -> pattern , translated -> patternlen ));
669
+
670
+ if (!hashmap_get_entry (& pl -> recursive_hashmap ,
671
+ translated , ent , NULL )) {
672
+ /* We did not see the "parent" included */
673
+ warning (_ ("unrecognized negative pattern: '%s'" ),
674
+ given -> pattern );
675
+ free (truncated );
676
+ free (translated );
677
+ goto clear_hashmaps ;
678
+ }
679
+
680
+ hashmap_add (& pl -> parent_hashmap , & translated -> ent );
681
+ hashmap_remove (& pl -> recursive_hashmap , & translated -> ent , & data );
682
+ free (data );
683
+ return ;
684
+ }
685
+
686
+ if (given -> flags & PATTERN_FLAG_NEGATIVE ) {
687
+ warning (_ ("unrecognized negative pattern: '%s'" ),
688
+ given -> pattern );
689
+ goto clear_hashmaps ;
690
+ }
691
+
692
+ translated = xmalloc (sizeof (struct pattern_entry ));
693
+
694
+ translated -> pattern = xstrdup (given -> pattern );
695
+ translated -> patternlen = given -> patternlen ;
696
+ hashmap_entry_init (& translated -> ent ,
697
+ memhash (translated -> pattern , translated -> patternlen ));
698
+
699
+ hashmap_add (& pl -> recursive_hashmap , & translated -> ent );
700
+
701
+ if (hashmap_get_entry (& pl -> parent_hashmap , translated , ent , NULL )) {
702
+ /* we already included this at the parent level */
703
+ warning (_ ("your sparse-checkout file may have issues: pattern '%s' is repeated" ),
704
+ given -> pattern );
705
+ hashmap_remove (& pl -> parent_hashmap , & translated -> ent , & data );
706
+ free (data );
707
+ free (translated );
708
+ }
709
+
710
+ return ;
711
+
712
+ clear_hashmaps :
713
+ warning (_ ("disabling cone pattern matching" ));
714
+ hashmap_free_entries (& pl -> parent_hashmap , struct pattern_entry , ent );
715
+ hashmap_free_entries (& pl -> recursive_hashmap , struct pattern_entry , ent );
716
+ pl -> use_cone_patterns = 0 ;
717
+ }
718
+
719
+ static int hashmap_contains_path (struct hashmap * map ,
720
+ struct strbuf * pattern )
721
+ {
722
+ struct pattern_entry p ;
723
+
724
+ /* Check straight mapping */
725
+ p .pattern = pattern -> buf ;
726
+ p .patternlen = pattern -> len ;
727
+ hashmap_entry_init (& p .ent , memhash (p .pattern , p .patternlen ));
728
+ return !!hashmap_get_entry (map , & p , ent , NULL );
729
+ }
730
+
731
+ int hashmap_contains_parent (struct hashmap * map ,
732
+ const char * path ,
733
+ struct strbuf * buffer )
734
+ {
735
+ char * slash_pos ;
736
+
737
+ strbuf_setlen (buffer , 0 );
738
+
739
+ if (path [0 ] != '/' )
740
+ strbuf_addch (buffer , '/' );
741
+
742
+ strbuf_addstr (buffer , path );
743
+
744
+ slash_pos = strrchr (buffer -> buf , '/' );
745
+
746
+ while (slash_pos > buffer -> buf ) {
747
+ strbuf_setlen (buffer , slash_pos - buffer -> buf );
748
+
749
+ if (hashmap_contains_path (map , buffer ))
750
+ return 1 ;
751
+
752
+ slash_pos = strrchr (buffer -> buf , '/' );
753
+ }
754
+
755
+ return 0 ;
756
+ }
757
+
614
758
void add_pattern (const char * string , const char * base ,
615
759
int baselen , struct pattern_list * pl , int srcpos )
616
760
{
@@ -635,6 +779,8 @@ void add_pattern(const char *string, const char *base,
635
779
ALLOC_GROW (pl -> patterns , pl -> nr + 1 , pl -> alloc );
636
780
pl -> patterns [pl -> nr ++ ] = pattern ;
637
781
pattern -> pl = pl ;
782
+
783
+ add_pattern_to_hashsets (pl , pattern );
638
784
}
639
785
640
786
static int read_skip_worktree_file_from_index (const struct index_state * istate ,
@@ -860,6 +1006,9 @@ static int add_patterns_from_buffer(char *buf, size_t size,
860
1006
int i , lineno = 1 ;
861
1007
char * entry ;
862
1008
1009
+ hashmap_init (& pl -> recursive_hashmap , pl_hashmap_cmp , NULL , 0 );
1010
+ hashmap_init (& pl -> parent_hashmap , pl_hashmap_cmp , NULL , 0 );
1011
+
863
1012
pl -> filebuf = buf ;
864
1013
865
1014
if (skip_utf8_bom (& buf , size ))
@@ -1096,16 +1245,58 @@ enum pattern_match_result path_matches_pattern_list(
1096
1245
struct index_state * istate )
1097
1246
{
1098
1247
struct path_pattern * pattern ;
1099
- pattern = last_matching_pattern_from_list (pathname , pathlen , basename ,
1100
- dtype , pl , istate );
1101
- if (pattern ) {
1102
- if (pattern -> flags & PATTERN_FLAG_NEGATIVE )
1103
- return NOT_MATCHED ;
1104
- else
1105
- return MATCHED ;
1248
+ struct strbuf parent_pathname = STRBUF_INIT ;
1249
+ int result = NOT_MATCHED ;
1250
+ const char * slash_pos ;
1251
+
1252
+ if (!pl -> use_cone_patterns ) {
1253
+ pattern = last_matching_pattern_from_list (pathname , pathlen , basename ,
1254
+ dtype , pl , istate );
1255
+ if (pattern ) {
1256
+ if (pattern -> flags & PATTERN_FLAG_NEGATIVE )
1257
+ return NOT_MATCHED ;
1258
+ else
1259
+ return MATCHED ;
1260
+ }
1261
+
1262
+ return UNDECIDED ;
1263
+ }
1264
+
1265
+ if (pl -> full_cone )
1266
+ return MATCHED ;
1267
+
1268
+ strbuf_addch (& parent_pathname , '/' );
1269
+ strbuf_add (& parent_pathname , pathname , pathlen );
1270
+
1271
+ if (hashmap_contains_path (& pl -> recursive_hashmap ,
1272
+ & parent_pathname )) {
1273
+ result = MATCHED ;
1274
+ goto done ;
1275
+ }
1276
+
1277
+ slash_pos = strrchr (parent_pathname .buf , '/' );
1278
+
1279
+ if (slash_pos == parent_pathname .buf ) {
1280
+ /* include every file in root */
1281
+ result = MATCHED ;
1282
+ goto done ;
1106
1283
}
1107
1284
1108
- return UNDECIDED ;
1285
+ strbuf_setlen (& parent_pathname , slash_pos - parent_pathname .buf );
1286
+
1287
+ if (hashmap_contains_path (& pl -> parent_hashmap , & parent_pathname )) {
1288
+ result = MATCHED ;
1289
+ goto done ;
1290
+ }
1291
+
1292
+ if (hashmap_contains_parent (& pl -> recursive_hashmap ,
1293
+ pathname ,
1294
+ & parent_pathname ))
1295
+ result = MATCHED ;
1296
+
1297
+ done :
1298
+ strbuf_release (& parent_pathname );
1299
+ return result ;
1109
1300
}
1110
1301
1111
1302
static struct path_pattern * last_matching_pattern_from_lists (
0 commit comments