diff --git a/src/NuGetUtility/Extensions/ProjectExtensions.cs b/src/NuGetUtility/Extensions/ProjectExtensions.cs index 5f9c466b..95a650bd 100644 --- a/src/NuGetUtility/Extensions/ProjectExtensions.cs +++ b/src/NuGetUtility/Extensions/ProjectExtensions.cs @@ -19,6 +19,11 @@ public static bool IsPackageReferenceProject(this IProject project) !project.HasPackagesConfigFile(); } + public static string GetPackagesConfigPath(this IProject project) + { + return Path.Join(Path.GetDirectoryName(project.FullPath), PackagesConfigFileName); + } + private static bool HasPackagesConfigFile(this IProject project) { return project.GetEvaluatedIncludes().Any(include => include?.Equals(PackagesConfigFileName) ?? false); diff --git a/src/NuGetUtility/NuGetUtility.csproj b/src/NuGetUtility/NuGetUtility.csproj index 9ac21a6b..e50f7a19 100644 --- a/src/NuGetUtility/NuGetUtility.csproj +++ b/src/NuGetUtility/NuGetUtility.csproj @@ -30,6 +30,7 @@ + diff --git a/src/NuGetUtility/ReferencedPackagesReader/ReferencedPackageReader.cs b/src/NuGetUtility/ReferencedPackagesReader/ReferencedPackageReader.cs index b438348e..15f3c777 100644 --- a/src/NuGetUtility/ReferencedPackagesReader/ReferencedPackageReader.cs +++ b/src/NuGetUtility/ReferencedPackagesReader/ReferencedPackageReader.cs @@ -27,7 +27,10 @@ public IEnumerable GetInstalledPackages(string projectPath, boo return Enumerable.Empty(); } - return GetInstalledPackagesFromAssetsFile(includeTransitive, project); + if (project.IsPackageReferenceProject()) + return GetInstalledPackagesFromAssetsFile(includeTransitive, project); + + return PackagesConfigReader.GetPackages(project.GetPackagesConfigPath()); } private IEnumerable GetInstalledPackagesFromAssetsFile(bool includeTransitive, diff --git a/src/NuGetUtility/Wrapper/MsBuildWrapper/MsBuildAbstraction.cs b/src/NuGetUtility/Wrapper/MsBuildWrapper/MsBuildAbstraction.cs index 40eeb00c..e8cf2d41 100644 --- a/src/NuGetUtility/Wrapper/MsBuildWrapper/MsBuildAbstraction.cs +++ b/src/NuGetUtility/Wrapper/MsBuildWrapper/MsBuildAbstraction.cs @@ -1,3 +1,4 @@ +using System.Management; using Microsoft.Build.Construction; using Microsoft.Build.Evaluation; using Microsoft.Build.Exceptions; @@ -12,10 +13,17 @@ namespace NuGetUtility.Wrapper.MsBuildWrapper public class MsBuildAbstraction : IMsBuildAbstraction { private const string CollectPackageReferences = "CollectPackageReferences"; + private readonly Dictionary _project_props = new(); public MsBuildAbstraction() { RegisterMsBuildLocatorIfNeeded(); + + // to support VC-projects we need to workaround : https://github.com/3F/MvsSln/issues/1 + // adding 'VCTargetsPath' to Project::GlobalProperties seem to be enough + + if (GetBestVCTargetsPath() is string path) + _project_props.Add("VCTargetsPath", $"{path}\\"); } public IEnumerable GetPackageReferencesFromProjectForFramework(IProject project, @@ -40,16 +48,9 @@ public IProject GetProject(string projectPath) { ProjectRootElement rootElement = TryGetProjectRootElement(projectPath); - var project = new Project(rootElement); - var projectWrapper = new ProjectWrapper(project); - - if (!projectWrapper.IsPackageReferenceProject()) - { - throw new MsBuildAbstractionException( - $"Invalid project structure detected. Currently only PackageReference projects are supported (Project: {project.FullPath})"); - } + var project = new Project(rootElement, _project_props, null); - return projectWrapper; + return new ProjectWrapper(project); } public IEnumerable GetProjectsFromSolution(string inputPath) @@ -59,6 +60,35 @@ public IEnumerable GetProjectsFromSolution(string inputPath) return sln.ProjectsInOrder.Select(p => p.AbsolutePath); } + private static string? GetBestVCTargetsPath() + { + var cpp_props = new List(); + + foreach (string path in GetVisualStudioInstallPaths()) + cpp_props.AddRange(new DirectoryInfo(path).GetFiles("Microsoft.Cpp.Default.props", SearchOption.AllDirectories)); + + // if multiple, assume most recent 'LastWriteTime' property is 'best' + return cpp_props.OrderBy(f => f.LastWriteTime).LastOrDefault()?.DirectoryName; + } + + private static IEnumerable GetVisualStudioInstallPaths() + { + // https://learn.microsoft.com/en-us/visualstudio/install/tools-for-managing-visual-studio-instances?view=vs-2022#using-windows-management-instrumentation-wmi + + var result = new List(); + + if (OperatingSystem.IsWindows()) + { + var mmc = new ManagementClass("root/cimv2/vs:MSFT_VSInstance"); + + foreach (ManagementBaseObject? vs_instance in mmc.GetInstances()) + if (vs_instance["InstallLocation"] is string install_path) + result.Add(install_path); + } + + return result; + } + private static void RegisterMsBuildLocatorIfNeeded() { if (!MSBuildLocator.IsRegistered) diff --git a/src/NuGetUtility/Wrapper/NuGetWrapper/Packaging/Core/PackageConfigReader.cs b/src/NuGetUtility/Wrapper/NuGetWrapper/Packaging/Core/PackageConfigReader.cs new file mode 100644 index 00000000..ef8aba29 --- /dev/null +++ b/src/NuGetUtility/Wrapper/NuGetWrapper/Packaging/Core/PackageConfigReader.cs @@ -0,0 +1,17 @@ +using System.Xml.Linq; +using NuGetUtility.Wrapper.NuGetWrapper.Versioning; + +namespace NuGetUtility.Wrapper.NuGetWrapper.Packaging.Core +{ + public static class PackagesConfigReader + { + public static IEnumerable GetPackages(string path) + { + var document = XDocument.Load(path); + + var reader = new NuGet.Packaging.PackagesConfigReader(document); + + return reader.GetPackages().Select(p => new PackageIdentity(p.PackageIdentity.Id, new WrappedNuGetVersion(p.PackageIdentity.Version))); + } + } +} diff --git a/tests/NuGetUtility.Test/ReferencedPackagesReader/ReferencedPackagesReaderIntegrationTest.cs b/tests/NuGetUtility.Test/ReferencedPackagesReader/ReferencedPackagesReaderIntegrationTest.cs index 6cb0997c..194776db 100644 --- a/tests/NuGetUtility.Test/ReferencedPackagesReader/ReferencedPackagesReaderIntegrationTest.cs +++ b/tests/NuGetUtility.Test/ReferencedPackagesReader/ReferencedPackagesReaderIntegrationTest.cs @@ -65,12 +65,13 @@ public void GetInstalledPackagesShould_ReturnEmptyEnumerableForProjectsWithoutPa [Test] [Platform(Include = "Win")] - public void GetInstalledPackagesShould_ThrowMsBuildAbstractionException_If_ProjectUsesPackagesConfig() + public void GetInstalledPackagesShould_ReturnPackagesForPackagesConfigProject() { string path = Path.GetFullPath("../../../../targets/PackagesConfigProject/PackagesConfigProject.csproj"); - MsBuildAbstractionException? exception = Assert.Throws(() => _uut!.GetInstalledPackages(path, false)); - Assert.That(exception?.Message, Is.EqualTo($"Invalid project structure detected. Currently only PackageReference projects are supported (Project: {path})")); + IEnumerable result = _uut!.GetInstalledPackages(path, false); + + Assert.That(result.Count, Is.EqualTo(1)); } } }