diff --git a/src/OmniSharp.Host/Services/DotNetCliService.cs b/src/OmniSharp.Host/Services/DotNetCliService.cs index d6c77c4389..4048d2a4ad 100644 --- a/src/OmniSharp.Host/Services/DotNetCliService.cs +++ b/src/OmniSharp.Host/Services/DotNetCliService.cs @@ -20,7 +20,7 @@ internal class DotNetCliService : IDotNetCliService private readonly ILogger _logger; private readonly IEventEmitter _eventEmitter; - private readonly ConcurrentDictionary _locks; + private readonly ConcurrentDictionary<(string WorkingDirectory, string Arguments), Task> _restoreTasks; private readonly SemaphoreSlim _semaphore; public string DotNetPath { get; } @@ -29,7 +29,7 @@ public DotNetCliService(ILoggerFactory loggerFactory, IEventEmitter eventEmitter { _logger = loggerFactory.CreateLogger(); _eventEmitter = eventEmitter; - _locks = new ConcurrentDictionary(); + _restoreTasks = new(); _semaphore = new SemaphoreSlim(Environment.ProcessorCount / 2); // Check if any of the provided paths have a dotnet executable. @@ -78,39 +78,42 @@ private static void RemoveMSBuildEnvironmentVariables(IDictionary { + var (workingDirectory, arguments) = key; + _logger.LogInformation($"Begin dotnet restore in '{workingDirectory}'"); - var restoreLock = _locks.GetOrAdd(workingDirectory, new object()); - lock (restoreLock) + var exitStatus = new ProcessExitStatus(-1); + _eventEmitter.RestoreStarted(workingDirectory); + _semaphore.Wait(); + try { - var exitStatus = new ProcessExitStatus(-1); - _eventEmitter.RestoreStarted(workingDirectory); - _semaphore.Wait(); - try - { - // A successful restore will update the project lock file which is monitored - // by the dotnet project system which eventually update the Roslyn model - exitStatus = ProcessHelper.Run(DotNetPath, $"restore {arguments}", workingDirectory, updateEnvironment: RemoveMSBuildEnvironmentVariables, - outputDataReceived: (data) => _logger.LogDebug(data), errorDataReceived: (data) => _logger.LogDebug(data)); - } - finally - { - _semaphore.Release(); - - _locks.TryRemove(workingDirectory, out _); + // A successful restore will update the project lock file which is monitored + // by the dotnet project system which eventually update the Roslyn model + exitStatus = ProcessHelper.Run(DotNetPath, $"restore {arguments}", workingDirectory, updateEnvironment: RemoveMSBuildEnvironmentVariables, + outputDataReceived: (data) => _logger.LogDebug(data), errorDataReceived: (data) => _logger.LogDebug(data)); + } + finally + { + _semaphore.Release(); - _eventEmitter.RestoreFinished(workingDirectory, exitStatus.Succeeded); + _restoreTasks.TryRemove(key, out _); - if (exitStatus.Failed && onFailure != null) - { - onFailure(); - } + _eventEmitter.RestoreFinished(workingDirectory, exitStatus.Succeeded); - _logger.LogInformation($"Finish restoring project {workingDirectory}. Exit code {exitStatus}"); + if (exitStatus.Failed && onFailure != null) + { + onFailure(); } + + _logger.LogInformation($"Finish restoring project {workingDirectory}. Exit code {exitStatus}"); } }); } diff --git a/src/OmniSharp.MSBuild/PackageDependencyChecker.cs b/src/OmniSharp.MSBuild/PackageDependencyChecker.cs index a7ae60d2ed..b8ec61d275 100644 --- a/src/OmniSharp.MSBuild/PackageDependencyChecker.cs +++ b/src/OmniSharp.MSBuild/PackageDependencyChecker.cs @@ -45,7 +45,7 @@ public void CheckForUnresolvedDependences(ProjectFileInfo projectFile, bool allo if (allowAutoRestore && _options.EnablePackageAutoRestore) { - _dotNetCli.RestoreAsync(projectFile.Directory, onFailure: () => + _dotNetCli.RestoreAsync(projectFile.Directory, projectFile.FilePath, onFailure: () => { _eventEmitter.UnresolvedDepdendencies(projectFile.FilePath, unresolvedDependencies); });