@@ -1258,6 +1258,134 @@ private FileMetadataByVersion FindMetadataByVersion(string filenameCanonical,
1258
1258
return metadataByVersion ;
1259
1259
}
1260
1260
1261
+ /// <summary>
1262
+ /// Find the highest priority name of a manifest.
1263
+ /// </summary>
1264
+ /// <param name="name">Name to lookup from the graph.</param>
1265
+ /// <param name="aliasesByName">Adjacency list (graph) of aliases to search.</param>
1266
+ /// <param name="maxDepth">Maximum depth to traverse the graph.</param>
1267
+ /// <param name="depth">Graph traversal depth.</param>
1268
+ /// <returns>Name and depth in the graph or the supplied name and a depth of -1
1269
+ /// if not found.</returns>
1270
+ private static KeyValuePair < string , int > FindHighestPriorityManifestName (
1271
+ string name , Dictionary < string , HashSet < string > > aliasesByName , int maxDepth ,
1272
+ int depth = 0 ) {
1273
+ if ( depth > maxDepth ) {
1274
+ Log ( String . Format (
1275
+ "Detected manifest name alias loop for name {0}, to fix this change the " +
1276
+ "list (see below) to not contain a loop:\n {1}" +
1277
+ name , String . Join ( "\n " , ( new List < string > ( aliasesByName . Keys ) ) . ToArray ( ) ) ) ,
1278
+ level : LogLevel . Warning ) ;
1279
+ return new KeyValuePair < string , int > ( name , - 1 ) ;
1280
+ }
1281
+ KeyValuePair < string , int > deepestNameAndDepth =
1282
+ new KeyValuePair < string , int > ( name , depth ) ;
1283
+ HashSet < string > aliases ;
1284
+ if ( ! aliasesByName . TryGetValue ( name , out aliases ) ) {
1285
+ return deepestNameAndDepth ;
1286
+ }
1287
+ if ( aliases . Count == 1 && ( new List < string > ( aliases ) ) [ 0 ] == name ) {
1288
+ return deepestNameAndDepth ;
1289
+ }
1290
+ foreach ( var alias in aliases ) {
1291
+ var nameAndDepth = FindHighestPriorityManifestName (
1292
+ alias , aliasesByName , maxDepth , depth : depth + 1 ) ;
1293
+ if ( nameAndDepth . Value > deepestNameAndDepth . Value ) {
1294
+ deepestNameAndDepth = nameAndDepth ;
1295
+ }
1296
+ }
1297
+ return deepestNameAndDepth ;
1298
+ }
1299
+
1300
+ /// <summary>
1301
+ /// Create an adjacency list of manifest names.
1302
+ /// </summary>
1303
+ /// <returns>Adjacency list of manifest names. For example, given the set of manifest
1304
+ /// names for a file "foo.txt" [manifestName-0A, manifestName-1B, manifestName-1C]
1305
+ /// this returns the set of aliaes for the name of manifest "A", i.e {"A": ["B, "C"]}.
1306
+ /// </returns>
1307
+ private Dictionary < string , HashSet < string > > GetManifestAliasesByName ( ) {
1308
+ // Create an adjacency list of manifest alias to name which can be used to search the
1309
+ // highest priority name of a manifest "foo", which is the entry {"foo": ["foo"]}.
1310
+ var aliasesByName = new Dictionary < string , HashSet < string > > ( ) ;
1311
+ foreach ( var metadataByVersion in Values ) {
1312
+ var metadata = metadataByVersion . MostRecentVersion ;
1313
+ if ( metadata . isManifest ) {
1314
+ foreach ( var name in metadata . customManifestNames . Values ) {
1315
+ HashSet < string > aliases = null ;
1316
+ if ( ! aliasesByName . TryGetValue ( name , out aliases ) ) {
1317
+ aliases = new HashSet < string > ( ) ;
1318
+ aliasesByName [ name ] = aliases ;
1319
+ }
1320
+ aliases . Add ( metadata . customManifestNames . Values [ 0 ] ) ;
1321
+ }
1322
+ }
1323
+ }
1324
+ // Display adjacency list for debugging.
1325
+ var logLines = new List < string > ( ) ;
1326
+ foreach ( var nameAndAliases in aliasesByName ) {
1327
+ logLines . Add ( String . Format (
1328
+ "name: {0} --> aliases: [{1}]" , nameAndAliases . Key ,
1329
+ String . Join ( ", " , ( new List < string > ( nameAndAliases . Value ) ) . ToArray ( ) ) ) ) ;
1330
+ }
1331
+ if ( logLines . Count > 0 ) {
1332
+ Log ( String . Format ( "Manifest aliases:\n {0}" ,
1333
+ String . Join ( "\n " , logLines . ToArray ( ) ) ) , verbose : true ) ;
1334
+ }
1335
+ return aliasesByName ;
1336
+ }
1337
+
1338
+ /// <summary>
1339
+ /// Use manifest aliases to cosolidate manifest metadata.
1340
+ /// </summary>
1341
+ public void ConsolidateManifests ( ) {
1342
+ var aliasesByName = GetManifestAliasesByName ( ) ;
1343
+ // Flatten graph of manifest aliases so that each entry maps to the highest priority
1344
+ // name.
1345
+ var manifestAliases = new Dictionary < string , string > ( ) ;
1346
+ int numberOfAliases = aliasesByName . Count ;
1347
+
1348
+ var logLines = new List < string > ( ) ;
1349
+ foreach ( var name in aliasesByName . Keys ) {
1350
+ var foundName = FindHighestPriorityManifestName ( name , aliasesByName ,
1351
+ numberOfAliases ) . Key ;
1352
+ manifestAliases [ name ] = foundName ;
1353
+ logLines . Add ( String . Format ( "name: {0} --> alias: {1}" , name , foundName ) ) ;
1354
+ }
1355
+ if ( logLines . Count > 0 ) {
1356
+ Log ( String . Format ( "Flattened manifest aliases:\n {0}" ,
1357
+ String . Join ( "\n " , logLines . ToArray ( ) ) ) , verbose : true ) ;
1358
+ }
1359
+
1360
+ // Create a new metadata map consolidating manifests by their highest priority name.
1361
+ var oldMetadataByCanonicalFilename = metadataByCanonicalFilename ;
1362
+ Clear ( ) ;
1363
+ foreach ( var canonicalFilenameAndMetadataByVersion in oldMetadataByCanonicalFilename ) {
1364
+ var metadata = canonicalFilenameAndMetadataByVersion . Value . MostRecentVersion ;
1365
+ if ( metadata . isManifest ) {
1366
+ FileMetadataByVersion manifests = canonicalFilenameAndMetadataByVersion . Value ;
1367
+ // Merge multiple versions of the manifest.
1368
+ string manifestName ;
1369
+ if ( ! manifestAliases . TryGetValue ( metadata . ManifestName , out manifestName ) ) {
1370
+ manifestName = metadata . ManifestName ;
1371
+ }
1372
+ Add ( manifestName , manifests ) ;
1373
+
1374
+ logLines = new List < string > ( ) ;
1375
+ foreach ( var manifest in manifests . Values ) {
1376
+ logLines . Add ( String . Format ( "file: {0}, version: {1}" ,
1377
+ manifest . filename , manifest . versionString ) ) ;
1378
+ }
1379
+ Log ( String . Format ( "Add manifests to package '{0}':\n {1}" ,
1380
+ manifestName , String . Join ( "\n " , logLines . ToArray ( ) ) ) ,
1381
+ verbose : true ) ;
1382
+ } else {
1383
+ Add ( canonicalFilenameAndMetadataByVersion . Key ,
1384
+ canonicalFilenameAndMetadataByVersion . Value ) ;
1385
+ }
1386
+ }
1387
+ }
1388
+
1261
1389
/// <summary>
1262
1390
/// For each plugin (DLL) referenced by this set, disable targeting
1263
1391
/// for all versions and re-enable platform targeting for the most
@@ -1553,6 +1681,7 @@ public bool ParseManifests(FileMetadataByVersion metadataByVersion,
1553
1681
/// obsolete files referenced in each manifest file.</returns>
1554
1682
public static List < ManifestReferences > FindAndReadManifests (
1555
1683
FileMetadataSet metadataSet ) {
1684
+ metadataSet . ConsolidateManifests ( ) ;
1556
1685
var manifestReferencesList = new List < ManifestReferences > ( ) ;
1557
1686
foreach ( var metadataByVersion in metadataSet . Values ) {
1558
1687
ManifestReferences manifestReferences =
0 commit comments