-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Add BuildHost APIs for loading an in-memory project #78303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
I'm wondering if this PR is not correctly handling batch builds, or whether that scenario is relevant. |
|
||
await using var buildHostProcessManager = new BuildHostProcessManager(ImmutableDictionary<string, string>.Empty); | ||
|
||
var buildHost = await buildHostProcessManager.GetBuildHostWithFallbackAsync(projectFilePath, CancellationToken.None); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...like right here. 😄 But maybe this case is OK for your actual needs? We'd call GetBuildHostWithFallback with the temp project path, but call the next one with the real project? Or should we just hardcode this to use the netcore build host?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds like a good idea to just specify the NetCore host, here and in its practical usage in the LanguageServer.
} | ||
|
||
// load project file | ||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(projectContent)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to tell MSBuild somewhere else that we're still encoding with UTF8? Or will we have a BOM there for it to figure out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to tell MSBuild somewhere else that we're still encoding with UTF8?
That is not clear to me. It is also not clear to me how that would be happening in the ordinary on-disk project case.
Or will we have a BOM there for it to figure out?
It looks like the Unicode standard (ctrl+f for "neither required nor recommended") does not recommend using a BOM with UTF8. I think that GetBytes does not include a BOM.
The overload of XmlReader.Create we are using says:
The XmlReader scans the first bytes of the stream looking for a byte order mark or other sign of encoding. When encoding is determined, the encoding is used to continue reading the stream, and processing continues parsing the input as a stream of (Unicode) characters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So should we have some way to thread the encoding through to avoid mojibake if the XmlReader doesn't infer it correctly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or should we have a UTF-8 BOM precisely so it can infer in this case?
It might not be -- I think we use the batch build case if we're loading an entire solution at once, and that would only happen in an OpenSolutionAsync() case. So that might not be needed right now. But that said, at some point we'll probably need to ask how we're going to add support to MSBuildWorkspace for these projects too. And you'll need it then. |
2e973ae
to
883d36b
Compare
I was struggling to deal with the number of overloads with the same name here. So I tried to improve organization marginally by separating the public and private methods. |
@@ -33,6 +33,16 @@ public async Task<RemoteProjectFile> LoadProjectFileAsync(string projectFilePath | |||
return new RemoteProjectFile(_client, remoteProjectFileTargetObject); | |||
} | |||
|
|||
/// <summary>Permits loading a project file which only exists in-memory, for example, for file-based program scenarios.</summary> | |||
/// <param name="projectFilePath">A path to a project file which may or may not exist on disk. Note that an extension that is known by MSBuild, such as .csproj or .vbproj, should be used here.</param> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent warning to add! 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...except this should go on the interface since that's what's actually seen by consumers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved with one concern that I'm still not entirely sure how encoding is going to be handled when we convert the string to a UTF8 byte array. Having a test that ensures we round-trip that might be good to add. I'm OK though if we want to defer checking that and merging this, with the promise we file a bug and promise to fix it. 😄
} | ||
|
||
// load project file | ||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(projectContent)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So should we have some way to thread the encoding through to avoid mojibake if the XmlReader doesn't infer it correctly?
} | ||
|
||
// load project file | ||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(projectContent)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or should we have a UTF-8 BOM precisely so it can infer in this case?
@@ -27,4 +29,18 @@ public async Task<ProjectFile> LoadProjectFileAsync(string path, ProjectBuildMan | |||
|
|||
return this.CreateProjectFile(project, buildManager, log); | |||
} | |||
|
|||
public ProjectFile LoadProjectFile(string path, string projectContent, ProjectBuildManager buildManager) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public ProjectFile LoadProjectFile(string path, string projectContent, ProjectBuildManager buildManager) | |
public ProjectFile LoadProject(string path, string projectContent, ProjectBuildManager buildManager) |
Just to match your naming elsewhere.
_ => throw ExceptionUtilities.UnexpectedValue(languageName) | ||
}; | ||
|
||
_logger.LogInformation($"Loading {projectFilePath}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_logger.LogInformation($"Loading {projectFilePath}"); | |
_logger.LogInformation($"Loading an in-memory project with the path {projectFilePath}"); |
@@ -187,6 +196,23 @@ private async Task<int> LoadProjectFileCoreAsync(string projectFilePath, string | |||
return _server.AddTarget(projectFile); | |||
} | |||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copy the comment for the NoInlining use from the method above.
var log = new DiagnosticLog(); | ||
try | ||
{ | ||
var projectCollection = new MSB.Evaluation.ProjectCollection( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I admit I don't know the significance of this not using the batch project collection, or whether this creates problems around the loggers conflicting like you saw. That said, I'm not sure how to answer that question either. If we already had an existing bug there, then perhaps that can be counted as tracking the issue and this is fine.
Part of dotnet/sdk#48176
Related to #78208
We need to be able to create a project (XML) in memory and run a design time build on it. Adding these APIs is a prerequisite for us doing that.