Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3d40dcc
Support file-based apps in place of projects in the xplat CLI
jjonescz Feb 17, 2026
90bdcb5
Add package reference
jjonescz Feb 18, 2026
3435c86
Pass project collection to the API
jjonescz Feb 18, 2026
9cc867e
Let SDK provide the API to avoid a circular dependency
jjonescz Feb 24, 2026
284c974
Load dotnet.dll
jjonescz Feb 24, 2026
170dfeb
Move interface to its own file
jjonescz Feb 24, 2026
d730f85
Add a comment
jjonescz Feb 24, 2026
68fc9e7
Add a parameter for project content file
jjonescz Feb 25, 2026
09bec45
Merge branch 'dev' into 14390-fbp-2
jjonescz Feb 27, 2026
dea79fe
Avoid hard-coding .cs extension
jjonescz Feb 27, 2026
3f5eb66
Use correct MSBuild
jjonescz Feb 27, 2026
5115070
Use API again instead of a command-line option
jjonescz Mar 6, 2026
d97bad3
Merge branch 'dev' into 14390-fbp-2
jjonescz Mar 6, 2026
0e72883
Fixup after merge
jjonescz Mar 6, 2026
0f8f395
Improve code
jjonescz Mar 13, 2026
bff2206
Avoid using IVirtualProjectBuilder singletons
jjonescz Mar 13, 2026
4dba4eb
Merge branch 'dev' into 14390-fbp-2
jjonescz Mar 13, 2026
ca21710
Improve reflection
jjonescz Mar 13, 2026
db37ef1
Remove unnecessary check
jjonescz Mar 18, 2026
92020d5
Use SDK-provided project path
jjonescz Mar 18, 2026
7eecf67
Add public Program.Run API
jjonescz Mar 19, 2026
54cc213
Add SaveProject API
jjonescz Mar 19, 2026
e4aef8c
Handle Why command API
jjonescz Mar 19, 2026
dde5c33
Add unit tests
jjonescz Mar 19, 2026
b4fa7b1
Update help texts
jjonescz Mar 19, 2026
44944b2
Fixup a test
jjonescz Mar 19, 2026
2fc9af8
Improve code
jjonescz Mar 20, 2026
ea57406
Fixup restore option passed to msbuild
jjonescz Mar 20, 2026
335a3a8
Link a tracking issue
jjonescz Mar 24, 2026
97908b6
Simplify unit test utility
jjonescz Mar 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#nullable enable

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;

namespace NuGet.CommandLine.XPlat;

/// <summary>
/// We cannot have a dependency on a package from SDK due to source build,
/// hence we invert the relationship and define the interface here,
/// SDK implements it and we load the implementation dynamically.
/// </summary>
public interface IVirtualProjectBuilder
{
bool IsValidEntryPointPath(string entryPointFilePath);
Comment thread
nkolev92 marked this conversation as resolved.

ProjectRootElement CreateProjectRootElement(string entryPointFilePath, ProjectCollection projectCollection);

internal static IVirtualProjectBuilder? TryLoad()
Comment thread
jjonescz marked this conversation as resolved.
Outdated
{
var assemblyPath = Path.Join(AppContext.BaseDirectory, "dotnet.dll");
Comment thread
jjonescz marked this conversation as resolved.
Outdated

if (!File.Exists(assemblyPath))
{
return null;
}

var type = Assembly.LoadFile(assemblyPath)
.GetExportedTypes()
.FirstOrDefault(static t => t.IsAssignableTo(typeof(IVirtualProjectBuilder)));
return type != null ? (IVirtualProjectBuilder?)Activator.CreateInstance(type) : null;
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
#nullable enable
NuGet.CommandLine.XPlat.IVirtualProjectBuilder
NuGet.CommandLine.XPlat.IVirtualProjectBuilder.CreateProjectRootElement(string! entryPointFilePath, Microsoft.Build.Evaluation.ProjectCollection! projectCollection) -> Microsoft.Build.Construction.ProjectRootElement!
NuGet.CommandLine.XPlat.IVirtualProjectBuilder.IsValidEntryPointPath(string! entryPointFilePath) -> bool
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,6 @@ internal static List<FrameworkPackages> GetResolvedVersions(
throw new ArgumentNullException(nameof(assetsFile));
}

var projectPath = project.FullPath;
var resultPackages = new List<FrameworkPackages>();
var requestedTargetFrameworks = assetsFile.PackageSpec.TargetFrameworks;
var requestedTargets = assetsFile.Targets;
Expand Down Expand Up @@ -781,7 +780,7 @@ internal static List<FrameworkPackages> GetResolvedVersions(

//The packages for the framework that were retrieved with GetRequestedVersions
var frameworkDependencies = tfmInformation.Dependencies;
var projectPackages = GetPackageReferencesFromTargets(projectPath, tfmInformation.ToString());
var projectPackages = GetPackageReferencesFromTargets(project, tfmInformation.ToString());
var topLevelPackages = new List<InstalledPackageReference>();
var transitivePackages = new List<InstalledPackageReference>();

Expand All @@ -808,7 +807,7 @@ internal static List<FrameworkPackages> GetResolvedVersions(
}
catch (Exception)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ListPkg_ErrorReadingReferenceFromProject, projectPath));
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ListPkg_ErrorReadingReferenceFromProject, project.FullPath));
}
}
else
Expand Down Expand Up @@ -900,18 +899,18 @@ private static IEnumerable<ProjectItem> GetPackageReferences(Project project, Li
/// <summary>
/// Returns all package references after invoking the target CollectPackageReferences.
/// </summary>
/// <param name="projectPath"> Path to the project for which the package references have to be obtained.</param>
/// <param name="project">The project for which the package references have to be obtained.</param>
/// <param name="framework">Framework to get reference(s) for</param>
/// <returns>List of Items containing the package reference for the package.
/// If the libraryDependency is null then it returns all package references</returns>
private static IEnumerable<InstalledPackageReference> GetPackageReferencesFromTargets(string projectPath, string framework)
private static IEnumerable<InstalledPackageReference> GetPackageReferencesFromTargets(Project project, string framework)
{
var globalProperties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "TargetFramework", framework },
{ "ExcludeRestorePackageImports", bool.TrueString }
};
var newProject = new ProjectInstance(projectPath, globalProperties, null);
var newProject = new ProjectInstance(project.Xml, globalProperties, null, ProjectCollection.GlobalProjectCollection);
newProject.Build(new[] { CollectPackageReferences, CollectCentralPackageVersions }, new List<Microsoft.Build.Framework.ILogger> { }, out var targetOutputs);

// Find the first target output that matches `CollectPackageReferences`
Expand Down Expand Up @@ -1040,6 +1039,12 @@ private static IEnumerable<string> GetProjectFrameworks(Project project)

private static ProjectRootElement TryOpenProjectRootElement(string filename)
{
var virtualProjectBuilder = IVirtualProjectBuilder.TryLoad();
if (virtualProjectBuilder != null && virtualProjectBuilder.IsValidEntryPointPath(filename))
{
return virtualProjectBuilder.CreateProjectRootElement(filename, ProjectCollection.GlobalProjectCollection);
}

try
{
// There is ProjectRootElement.TryOpen but it does not work as expected
Expand Down