Skip to content
This repository was archived by the owner on Aug 11, 2021. It is now read-only.

Commit cbdd52a

Browse files
committed
[Core] Fixes #138. Recursively resolving package version ambiguity has been improved. If a package A has two versions in a package definition file, and each version of A depends on a different version of package B (and these are the only references to B), then prior to this fix, resolving which version of A is used (e.g. on the command line, --A.version=..., or specify the default in the master package definition file), would not automatically resolve B, even though there is no ambiguity anymore. A concrete example of this issue occurred with the VisualC packages, which depend on different versions of the WindowsSDK packages; specifying --VisualC.version=X still required --WindowsSDK.version=Y prior to the fix.
1 parent 5f259ee commit cbdd52a

File tree

3 files changed

+103
-40
lines changed

3 files changed

+103
-40
lines changed

Bam.Core/Package/PackageDefinition.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ private void
120120
this.PackageRepositories.AddUnique(associatedRepo);
121121
}
122122
this.Description = string.Empty;
123+
this.Parents = new Array<PackageDefinition>();
123124
}
124125

125126
/// <summary>
@@ -1079,6 +1080,8 @@ public static void
10791080
throw new Exception(message.ToString());
10801081
}
10811082

1083+
candidates.First().Parents.AddUnique(current);
1084+
10821085
ResolveDependencies(candidates.First(), authenticated, candidatePackageDefinitions);
10831086
}
10841087
}
@@ -1316,5 +1319,14 @@ public PackageMetaData MetaData
13161319
get;
13171320
set;
13181321
}
1322+
1323+
/// <summary>
1324+
/// List of PackageDefinitions which have stated that this package is a dependency.
1325+
/// </summary>
1326+
public Array<PackageDefinition> Parents
1327+
{
1328+
get;
1329+
set;
1330+
}
13191331
}
13201332
}

Bam.Core/Package/PackageUtilities.cs

Lines changed: 89 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,83 @@ public static PackageDefinition
220220
return masterDefinitionFile;
221221
}
222222

223+
private static PackageDefinition
224+
TryToResolveDuplicate(
225+
PackageDefinition masterDefinitionFile,
226+
string dupName,
227+
System.Collections.Generic.IEnumerable<PackageDefinition> duplicates,
228+
Array<PackageDefinition> packageDefinitions,
229+
Array<StringArray> packageVersionSpecifiers,
230+
Array<PackageDefinition> toRemove)
231+
{
232+
// command line specifications take precedence to resolve a duplicate
233+
foreach (var specifier in packageVersionSpecifiers)
234+
{
235+
if (!specifier.Contains(dupName))
236+
{
237+
continue;
238+
}
239+
240+
foreach (var dupPackage in duplicates)
241+
{
242+
if (specifier[1] == dupPackage.Version)
243+
{
244+
toRemove.AddRange(packageDefinitions.Where(item => (item.Name == dupName) && (item != dupPackage)));
245+
return dupPackage;
246+
}
247+
}
248+
249+
var noMatchMessage = new System.Text.StringBuilder();
250+
noMatchMessage.AppendFormat("Command line version specified, {0}, could not resolve to one of the available versions of package {1}:", specifier[1], duplicates.First().Name);
251+
noMatchMessage.AppendLine();
252+
foreach (var dup in duplicates)
253+
{
254+
noMatchMessage.AppendFormat("\t{0}", dup.Version);
255+
noMatchMessage.AppendLine();
256+
}
257+
throw new Exception(noMatchMessage.ToString());
258+
}
259+
260+
// now look at the master dependency file, for any 'default' specifications
261+
var masterDependency = masterDefinitionFile.Dependents.Where(item => item.Item1 == dupName && item.Item3.HasValue && item.Item3.Value).FirstOrDefault();
262+
if (null != masterDependency)
263+
{
264+
toRemove.AddRange(packageDefinitions.Where(item => (item.Name == dupName) && (item.Version != masterDependency.Item2)));
265+
return packageDefinitions.Where(item => (item.Name == dupName) && (item.Version == masterDependency.Item2)).First();
266+
}
267+
268+
return null;
269+
}
270+
271+
private static Array<PackageDefinition>
272+
PackagesToRemove(
273+
Array<PackageDefinition> toRemove,
274+
Array<PackageDefinition> packageDefinitions,
275+
PackageDefinition masterDefinitionFile)
276+
{
277+
var additionalToRemove = new Array<PackageDefinition>();
278+
foreach (var r in toRemove)
279+
{
280+
foreach (var p in packageDefinitions)
281+
{
282+
if (p.Parents.Contains(r))
283+
{
284+
p.Parents.Remove(r);
285+
}
286+
if (0 == p.Parents.Count() && p != masterDefinitionFile && !toRemove.Contains(p))
287+
{
288+
additionalToRemove.AddUnique(p);
289+
}
290+
}
291+
}
292+
if (additionalToRemove.Count() > 0)
293+
{
294+
// recurse
295+
additionalToRemove.AddRangeUnique(PackagesToRemove(additionalToRemove, packageDefinitions, masterDefinitionFile));
296+
}
297+
return additionalToRemove;
298+
}
299+
223300
/// <summary>
224301
/// Scan though all package repositories for all package dependencies, and resolve any duplicate package names
225302
/// by either data in the package definition file, or on the command line, by specifying a particular version to
@@ -311,54 +388,25 @@ public static void
311388
foreach (var dupName in duplicatePackageNames)
312389
{
313390
var duplicates = packageDefinitions.Where(item => item.Name == dupName);
314-
PackageDefinition resolvedDuplicate = null;
315-
// command line specifications take precedence to resolve a duplicate
316-
foreach (var specifier in packageVersionSpecifiers)
391+
var resolvedDuplicate = TryToResolveDuplicate(masterDefinitionFile, dupName, duplicates, packageDefinitions, packageVersionSpecifiers, toRemove);
392+
if (null != resolvedDuplicate)
317393
{
318-
if (!specifier.Contains(dupName))
319-
{
320-
continue;
321-
}
322-
323-
foreach (var dupPackage in duplicates)
324-
{
325-
if (specifier[1] == dupPackage.Version)
326-
{
327-
resolvedDuplicate = dupPackage;
328-
break;
329-
}
330-
}
331-
332-
if (resolvedDuplicate != null)
333-
{
334-
break;
335-
}
336-
337-
var noMatchMessage = new System.Text.StringBuilder();
338-
noMatchMessage.AppendFormat("Command line version specified, {0}, could not resolve to one of the available versions of package {1}:", specifier[1], duplicates.First().Name);
339-
noMatchMessage.AppendLine();
340-
foreach (var dup in duplicates)
341-
{
342-
noMatchMessage.AppendFormat("\t{0}", dup.Version);
343-
noMatchMessage.AppendLine();
344-
}
345-
throw new Exception(noMatchMessage.ToString());
346-
}
347-
348-
if (resolvedDuplicate != null)
349-
{
350-
toRemove.AddRange(packageDefinitions.Where(item => (item.Name == dupName) && (item != resolvedDuplicate)));
351394
continue;
352395
}
353396

354-
// now look at the master dependency file, for any 'default' specifications
355-
var masterDependency = masterDefinitionFile.Dependents.Where(item => item.Item1 == dupName && item.Item3.HasValue && item.Item3.Value).FirstOrDefault();
356-
if (null != masterDependency)
397+
// try removing any packages that have already been resolved
398+
// which can remove additional packages (recursive check) because they had been added solely by those we are just about to remove
399+
toRemove.AddRangeUnique(PackagesToRemove(toRemove, packageDefinitions, masterDefinitionFile));
400+
packageDefinitions.RemoveAll(toRemove);
401+
toRemove.Clear();
402+
403+
// and if that has reduced the duplicates for this package down to a single version, we're good to carry on
404+
if (1 == duplicates.Count())
357405
{
358-
toRemove.AddRange(packageDefinitions.Where(item => (item.Name == dupName) && (item.Version != masterDependency.Item2)));
359406
continue;
360407
}
361408

409+
// otherwise, error
362410
var resolveErrorMessage = new System.Text.StringBuilder();
363411
resolveErrorMessage.AppendFormat("Unable to resolve to a single version of package {0}. Use --{0}.version=<version> to resolve. Available versions of the package are:", duplicates.First().Name);
364412
resolveErrorMessage.AppendLine();
@@ -370,6 +418,7 @@ public static void
370418
throw new Exception(resolveErrorMessage.ToString());
371419
}
372420

421+
// finally, clean up the package definition list to use, with all those that need to be deleted
373422
packageDefinitions.RemoveAll(toRemove);
374423
}
375424

Changelog.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
16-Feb-2016 Fixes #138. Recursively resolving package version ambiguity has been improved. If a package A has two versions in a package definition file, and each version of A depends on a different version of package B (and these are the only references to B), then prior to this fix, resolving which version of A is used (e.g. on the command line, --A.version=..., or specify the default in the master package definition file), would not automatically resolve B, even though there is no ambiguity anymore. A concrete example of this issue occurred with the VisualC packages, which depend on different versions of the WindowsSDK packages; specifying --VisualC.version=X still required --WindowsSDK.version=Y prior to the fix.
2+
13
16-Feb-2016 Fixes #143. VisualC-14.0 added to the test package definition files. VisualC-12.0 remains as the default.
24

35
16-Feb-2016 Fixes #142. All C/C++ source files in tests now use C style comments, since files may be compiled on a variety of different tools and different build settings, which may not support C++ style comments.

0 commit comments

Comments
 (0)