@@ -490,6 +490,26 @@ fn rewrite_dep_list_selections(
490490/// `old_version` replaced with `new_version`. The checksum value is replaced
491491/// with `new_checksum` when given; otherwise it is left as-is and the second
492492/// return value is `true` (the value is now stale).
493+ /// Advance past whitespace and whole-line `#` comments to the first real entry.
494+ ///
495+ /// An annotated checksums list names each file above its hash, so the first
496+ /// thing inside the brackets is often a comment rather than an entry.
497+ fn skip_to_first_entry ( bytes : & [ u8 ] , from : usize ) -> usize {
498+ let mut i = from;
499+ loop {
500+ while i < bytes. len ( ) && ( bytes[ i] as char ) . is_whitespace ( ) {
501+ i += 1 ;
502+ }
503+ if i < bytes. len ( ) && bytes[ i] == b'#' {
504+ while i < bytes. len ( ) && bytes[ i] != b'\n' {
505+ i += 1 ;
506+ }
507+ continue ;
508+ }
509+ return i;
510+ }
511+ }
512+
493513fn rewrite_source_checksum (
494514 src : & str ,
495515 old_version : & str ,
@@ -503,10 +523,7 @@ fn rewrite_source_checksum(
503523 let body = & src[ list_open_end..list_close_start] ;
504524 let body_bytes = body. as_bytes ( ) ;
505525
506- let mut start = 0usize ;
507- while start < body_bytes. len ( ) && ( body_bytes[ start] as char ) . is_whitespace ( ) {
508- start += 1 ;
509- }
526+ let start = skip_to_first_entry ( body_bytes, 0 ) ;
510527 if start >= body_bytes. len ( ) {
511528 // Empty checksums list — nothing to rewrite.
512529 return Ok ( ( src. to_string ( ) , false ) ) ;
@@ -1017,6 +1034,42 @@ checksums = [
10171034dependencies = [
10181035 ('hwloc', '2.10.0'),
10191036]
1037+ " ;
1038+
1039+ /// A checksums list that names each file in a comment above its hash, the
1040+ /// shape upstream uses for annotated multi-entry lists.
1041+ const WITH_COMMENTED_CHECKSUMS : & str = "\
1042+ name = 'OpenMPI'
1043+ version = '5.0.3'
1044+ toolchain = {'name': 'NVHPC', 'version': '24.9-CUDA-12.6.0'}
1045+ homepage = 'https://www.open-mpi.org/'
1046+ sources = [SOURCELOWER_TAR_BZ2]
1047+ patches = [
1048+ 'OpenMPI-5.0.3_fix_hle_make_errors.patch',
1049+ ]
1050+ checksums = [
1051+ # openmpi-5.0.3.tar.bz2
1052+ {'openmpi-5.0.3.tar.bz2': '990582f206b3ab32e938aa31bbf07c639368e4405dca196fabe7f0f76eeda90b'},
1053+ # OpenMPI-5.0.3_fix_hle_make_errors.patch
1054+ {'OpenMPI-5.0.3_fix_hle_make_errors.patch': '881c907a9f5901d5d6af41cd33dffdcecba4a67a9e5123e602542aea57a80895'},
1055+ ]
1056+ dependencies = [
1057+ ('hwloc', '2.10.0'),
1058+ ]
1059+ " ;
1060+
1061+ /// The same list with a bare-string first entry under its comment.
1062+ const WITH_COMMENTED_BARE_CHECKSUM : & str = "\
1063+ name = 'OpenMPI'
1064+ version = '5.0.3'
1065+ toolchain = {'name': 'NVHPC', 'version': '24.9-CUDA-12.6.0'}
1066+ homepage = 'https://www.open-mpi.org/'
1067+ sources = [SOURCELOWER_TAR_BZ2]
1068+ checksums = [
1069+ # openmpi-5.0.3.tar.bz2
1070+
1071+ '990582f206b3ab32e938aa31bbf07c639368e4405dca196fabe7f0f76eeda90b',
1072+ ]
10201073" ;
10211074
10221075 fn nvhpc ( ver : & str ) -> Toolchain {
@@ -1053,6 +1106,80 @@ dependencies = [
10531106 assert ! ( r. warnings[ 0 ] . contains( "patches" ) , "{:?}" , r. warnings) ;
10541107 }
10551108
1109+ #[ test]
1110+ fn a_comment_above_the_first_checksum_does_not_stop_the_rewrite ( ) {
1111+ let params = EmitParams {
1112+ toolchain : nvhpc ( "25.11-CUDA-12.8.0" ) ,
1113+ version : Some ( "5.0.7" . into ( ) ) ,
1114+ dep_versions : HashMap :: new ( ) ,
1115+ dep_toolchains : HashMap :: new ( ) ,
1116+ source_checksum : Some (
1117+ "119f2009936a403334d0df3c0d74d5595a32d99497f9b1d41e90019fee2fc2dd" . into ( ) ,
1118+ ) ,
1119+ } ;
1120+ let r = emit_next_generation ( WITH_COMMENTED_CHECKSUMS , & params) . expect ( "emit" ) ;
1121+ assert ! ( r. text. contains(
1122+ "{'openmpi-5.0.7.tar.bz2': '119f2009936a403334d0df3c0d74d5595a32d99497f9b1d41e90019fee2fc2dd'}"
1123+ ) , "{}" , r. text) ;
1124+ // The annotations survive: they are not the tool's to rewrite.
1125+ assert ! (
1126+ r. text. contains( " # openmpi-5.0.3.tar.bz2\n " ) ,
1127+ "{}" ,
1128+ r. text
1129+ ) ;
1130+ assert ! (
1131+ r. text
1132+ . contains( " # OpenMPI-5.0.3_fix_hle_make_errors.patch\n " ) ,
1133+ "{}" ,
1134+ r. text
1135+ ) ;
1136+ // The patch entry below the second comment is still left alone.
1137+ assert ! ( r. text. contains(
1138+ "{'OpenMPI-5.0.3_fix_hle_make_errors.patch': '881c907a9f5901d5d6af41cd33dffdcecba4a67a9e5123e602542aea57a80895'}"
1139+ ) , "{}" , r. text) ;
1140+ }
1141+
1142+ #[ test]
1143+ fn a_comment_and_a_blank_line_above_a_bare_checksum_are_skipped ( ) {
1144+ let params = EmitParams {
1145+ toolchain : nvhpc ( "25.11-CUDA-12.8.0" ) ,
1146+ version : Some ( "5.0.7" . into ( ) ) ,
1147+ dep_versions : HashMap :: new ( ) ,
1148+ dep_toolchains : HashMap :: new ( ) ,
1149+ source_checksum : Some (
1150+ "119f2009936a403334d0df3c0d74d5595a32d99497f9b1d41e90019fee2fc2dd" . into ( ) ,
1151+ ) ,
1152+ } ;
1153+ let r = emit_next_generation ( WITH_COMMENTED_BARE_CHECKSUM , & params) . expect ( "emit" ) ;
1154+ assert ! (
1155+ r. text
1156+ . contains( "'119f2009936a403334d0df3c0d74d5595a32d99497f9b1d41e90019fee2fc2dd'" ) ,
1157+ "{}" ,
1158+ r. text
1159+ ) ;
1160+ assert ! (
1161+ r. text. contains( " # openmpi-5.0.3.tar.bz2\n " ) ,
1162+ "{}" ,
1163+ r. text
1164+ ) ;
1165+ }
1166+
1167+ #[ test]
1168+ fn skipping_stops_at_the_first_entry ( ) {
1169+ // Asserting on what the index lands on, rather than on the index,
1170+ // keeps the test about the behaviour instead of about arithmetic.
1171+ fn landed_on ( s : & str ) -> & str {
1172+ & s[ skip_to_first_entry ( s. as_bytes ( ) , 0 ) ..]
1173+ }
1174+ assert_eq ! ( landed_on( "{'a': 'b'}" ) , "{'a': 'b'}" ) ;
1175+ assert_eq ! ( landed_on( " \n {'a': 'b'}" ) , "{'a': 'b'}" ) ;
1176+ assert_eq ! ( landed_on( "\n # note\n 'sha'" ) , "'sha'" ) ;
1177+ assert_eq ! ( landed_on( "\n # one\n \n # two\n 'sha'" ) , "'sha'" ) ;
1178+ // A comment running to the end leaves nothing, which reads as empty.
1179+ assert_eq ! ( landed_on( "\n # trailing" ) , "" ) ;
1180+ assert_eq ! ( landed_on( "" ) , "" ) ;
1181+ }
1182+
10561183 #[ test]
10571184 fn version_bump_without_source_checksum_renames_key_and_warns ( ) {
10581185 let params = EmitParams {
0 commit comments