ProjectInfoFactory.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright (c) .NET Foundation. All rights reserved.
  2. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using Microsoft.Build.Construction;
  8. using Microsoft.Build.Evaluation;
  9. using Microsoft.Build.Execution;
  10. using NuGet.Frameworks;
  11. using RepoTasks.Utilities;
  12. using Microsoft.Build.Utilities;
  13. namespace RepoTasks.ProjectModel
  14. {
  15. internal class ProjectInfoFactory
  16. {
  17. private readonly TaskLoggingHelper _logger;
  18. public ProjectInfoFactory(TaskLoggingHelper logger)
  19. {
  20. _logger = logger ?? throw new ArgumentNullException(nameof(logger));
  21. }
  22. public ProjectInfo Create(string path, ProjectCollection projectCollection)
  23. {
  24. var project = GetProject(path, projectCollection);
  25. var instance = project.CreateProjectInstance(ProjectInstanceSettings.ImmutableWithFastItemLookup);
  26. var targetFrameworks = instance.GetPropertyValue("TargetFrameworks");
  27. var targetFramework = instance.GetPropertyValue("TargetFramework");
  28. var frameworks = new List<ProjectFrameworkInfo>();
  29. if (!string.IsNullOrEmpty(targetFrameworks) && string.IsNullOrEmpty(targetFramework))
  30. {
  31. // multi targeting
  32. foreach (var tfm in targetFrameworks.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
  33. {
  34. project.SetGlobalProperty("TargetFramework", tfm);
  35. var innerBuild = project.CreateProjectInstance(ProjectInstanceSettings.ImmutableWithFastItemLookup);
  36. var tfmInfo = new ProjectFrameworkInfo(NuGetFramework.Parse(tfm), GetDependencies(innerBuild));
  37. frameworks.Add(tfmInfo);
  38. }
  39. project.RemoveGlobalProperty("TargetFramework");
  40. }
  41. else if (!string.IsNullOrEmpty(targetFramework))
  42. {
  43. var tfmInfo = new ProjectFrameworkInfo(NuGetFramework.Parse(targetFramework), GetDependencies(instance));
  44. frameworks.Add(tfmInfo);
  45. }
  46. var projectDir = Path.GetDirectoryName(path);
  47. var tools = GetTools(instance).ToArray();
  48. bool.TryParse(instance.GetPropertyValue("IsPackable"), out var isPackable);
  49. var packageId = instance.GetPropertyValue("PackageId");
  50. var packageVersion = instance.GetPropertyValue("PackageVersion");
  51. return new ProjectInfo(path,
  52. frameworks,
  53. tools,
  54. isPackable,
  55. packageId,
  56. packageVersion);
  57. }
  58. private static object _projLock = new object();
  59. private static Project GetProject(string path, ProjectCollection projectCollection)
  60. {
  61. var projects = projectCollection.GetLoadedProjects(path);
  62. foreach(var proj in projects)
  63. {
  64. if (proj.GetPropertyValue("DesignTimeBuild") == "true")
  65. {
  66. return proj;
  67. }
  68. }
  69. var xml = ProjectRootElement.Open(path, projectCollection);
  70. var globalProps = new Dictionary<string, string>()
  71. {
  72. ["DesignTimeBuild"] = "true",
  73. ["ExcludeRestorePackageImports"] = "true",
  74. };
  75. var project = new Project(xml,
  76. globalProps,
  77. toolsVersion: "15.0",
  78. projectCollection: projectCollection)
  79. {
  80. IsBuildEnabled = false
  81. };
  82. return project;
  83. }
  84. private IReadOnlyDictionary<string, PackageReferenceInfo> GetDependencies(ProjectInstance project)
  85. {
  86. var references = new Dictionary<string, PackageReferenceInfo>(StringComparer.OrdinalIgnoreCase);
  87. foreach (var item in project.GetItems("PackageReference"))
  88. {
  89. bool.TryParse(item.GetMetadataValue("IsImplicitlyDefined"), out var isImplicit);
  90. var info = new PackageReferenceInfo(item.EvaluatedInclude, item.GetMetadataValue("Version"), isImplicit);
  91. if (references.ContainsKey(info.Id))
  92. {
  93. _logger.LogKoreBuildWarning(project.ProjectFileLocation.File, KoreBuildErrors.DuplicatePackageReference, $"Found a duplicate PackageReference for {info.Id}. Restore results may be unpredictable.");
  94. }
  95. references[info.Id] = info;
  96. }
  97. return references;
  98. }
  99. private static IEnumerable<DotNetCliReferenceInfo> GetTools(ProjectInstance project)
  100. {
  101. return project.GetItems("DotNetCliToolReference").Select(item =>
  102. new DotNetCliReferenceInfo(item.EvaluatedInclude, item.GetMetadataValue("Version")));
  103. }
  104. }
  105. }