2016-10-05 18:51:59 +00:00
|
|
|
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
|
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
|
|
|
|
|
|
using System;
|
2016-02-25 00:05:55 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
2016-09-28 21:21:52 +00:00
|
|
|
|
using Microsoft.DotNet.Tools.Common;
|
2016-03-17 18:45:13 +00:00
|
|
|
|
using Microsoft.Extensions.DependencyModel;
|
2016-10-28 01:46:43 +00:00
|
|
|
|
using NuGet.Configuration;
|
2016-02-25 00:05:55 +00:00
|
|
|
|
using NuGet.Frameworks;
|
2016-09-23 22:30:53 +00:00
|
|
|
|
using NuGet.ProjectModel;
|
2016-10-03 17:06:37 +00:00
|
|
|
|
using NuGet.Versioning;
|
2016-02-25 00:05:55 +00:00
|
|
|
|
|
2016-10-11 00:13:46 +00:00
|
|
|
|
namespace Microsoft.DotNet.Cli.Utils
|
2016-02-25 00:05:55 +00:00
|
|
|
|
{
|
|
|
|
|
public class ProjectToolsCommandResolver : ICommandResolver
|
|
|
|
|
{
|
2016-04-07 21:05:35 +00:00
|
|
|
|
private static readonly NuGetFramework s_toolPackageFramework = FrameworkConstants.CommonFrameworks.NetCoreApp10;
|
2016-04-28 23:30:32 +00:00
|
|
|
|
|
|
|
|
|
private static readonly CommandResolutionStrategy s_commandResolutionStrategy =
|
2016-02-25 00:05:55 +00:00
|
|
|
|
CommandResolutionStrategy.ProjectToolsPackage;
|
|
|
|
|
|
|
|
|
|
private List<string> _allowedCommandExtensions;
|
|
|
|
|
private IPackagedCommandSpecFactory _packagedCommandSpecFactory;
|
|
|
|
|
|
2016-10-11 00:13:46 +00:00
|
|
|
|
private IEnvironmentProvider _environment;
|
|
|
|
|
|
|
|
|
|
public ProjectToolsCommandResolver(
|
|
|
|
|
IPackagedCommandSpecFactory packagedCommandSpecFactory,
|
|
|
|
|
IEnvironmentProvider environment)
|
2016-02-25 00:05:55 +00:00
|
|
|
|
{
|
|
|
|
|
_packagedCommandSpecFactory = packagedCommandSpecFactory;
|
2016-10-11 00:13:46 +00:00
|
|
|
|
_environment = environment;
|
2016-02-25 00:05:55 +00:00
|
|
|
|
|
2016-04-28 23:30:32 +00:00
|
|
|
|
_allowedCommandExtensions = new List<string>()
|
2016-02-25 00:05:55 +00:00
|
|
|
|
{
|
|
|
|
|
FileNameSuffixes.DotNet.DynamicLib
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CommandSpec Resolve(CommandResolverArguments commandResolverArguments)
|
|
|
|
|
{
|
2016-03-07 19:50:52 +00:00
|
|
|
|
if (commandResolverArguments.CommandName == null
|
|
|
|
|
|| commandResolverArguments.ProjectDirectory == null)
|
|
|
|
|
{
|
2016-10-28 01:46:43 +00:00
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: Invalid CommandResolverArguments");
|
|
|
|
|
|
2016-03-07 19:50:52 +00:00
|
|
|
|
return null;
|
|
|
|
|
}
|
2016-04-28 23:30:32 +00:00
|
|
|
|
|
2016-10-11 00:13:46 +00:00
|
|
|
|
return ResolveFromProjectTools(commandResolverArguments);
|
2016-02-25 00:05:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-11 00:13:46 +00:00
|
|
|
|
private CommandSpec ResolveFromProjectTools(CommandResolverArguments commandResolverArguments)
|
2016-02-25 00:05:55 +00:00
|
|
|
|
{
|
2016-10-11 00:13:46 +00:00
|
|
|
|
var projectFactory = new ProjectFactory(_environment);
|
2016-10-28 01:46:43 +00:00
|
|
|
|
|
2016-10-11 00:13:46 +00:00
|
|
|
|
var project = projectFactory.GetProject(
|
|
|
|
|
commandResolverArguments.ProjectDirectory,
|
|
|
|
|
commandResolverArguments.Framework,
|
|
|
|
|
commandResolverArguments.Configuration,
|
|
|
|
|
commandResolverArguments.BuildBasePath,
|
|
|
|
|
commandResolverArguments.OutputPath);
|
2016-10-28 01:46:43 +00:00
|
|
|
|
|
|
|
|
|
if (project == null)
|
|
|
|
|
{
|
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: ProjectFactory did not find Project.");
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-05 01:58:04 +00:00
|
|
|
|
var tools = project.GetTools();
|
2016-02-25 00:05:55 +00:00
|
|
|
|
|
|
|
|
|
return ResolveCommandSpecFromAllToolLibraries(
|
2016-10-03 17:06:37 +00:00
|
|
|
|
tools,
|
2016-10-11 00:13:46 +00:00
|
|
|
|
commandResolverArguments.CommandName,
|
|
|
|
|
commandResolverArguments.CommandArguments.OrEmptyIfNull(),
|
|
|
|
|
project);
|
2016-02-25 00:05:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private CommandSpec ResolveCommandSpecFromAllToolLibraries(
|
2016-10-05 01:58:04 +00:00
|
|
|
|
IEnumerable<SingleProjectInfo> toolsLibraries,
|
2016-02-25 00:05:55 +00:00
|
|
|
|
string commandName,
|
|
|
|
|
IEnumerable<string> args,
|
2016-10-11 00:13:46 +00:00
|
|
|
|
IProject project)
|
2016-02-25 00:05:55 +00:00
|
|
|
|
{
|
2016-10-28 01:46:43 +00:00
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: resolving commandspec from {toolsLibraries.Count()} Tool Libraries.");
|
|
|
|
|
|
2016-02-25 00:05:55 +00:00
|
|
|
|
foreach (var toolLibrary in toolsLibraries)
|
|
|
|
|
{
|
2016-10-11 00:13:46 +00:00
|
|
|
|
var commandSpec = ResolveCommandSpecFromToolLibrary(
|
|
|
|
|
toolLibrary,
|
|
|
|
|
commandName,
|
|
|
|
|
args,
|
|
|
|
|
project);
|
2016-02-25 00:05:55 +00:00
|
|
|
|
|
|
|
|
|
if (commandSpec != null)
|
|
|
|
|
{
|
|
|
|
|
return commandSpec;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: failed to resolve commandspec from library.");
|
|
|
|
|
|
2016-02-25 00:05:55 +00:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private CommandSpec ResolveCommandSpecFromToolLibrary(
|
2016-10-05 01:58:04 +00:00
|
|
|
|
SingleProjectInfo toolLibraryRange,
|
2016-02-25 00:05:55 +00:00
|
|
|
|
string commandName,
|
|
|
|
|
IEnumerable<string> args,
|
2016-10-11 00:13:46 +00:00
|
|
|
|
IProject project)
|
2016-02-25 00:05:55 +00:00
|
|
|
|
{
|
2016-10-28 01:46:43 +00:00
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: Attempting to resolve command spec from tool {toolLibraryRange.Name}");
|
|
|
|
|
|
|
|
|
|
var nuGetPathContext = NuGetPathContext.Create(project.ProjectRoot);
|
|
|
|
|
|
|
|
|
|
var nugetPackagesRoot = nuGetPathContext.UserPackageFolder;
|
|
|
|
|
|
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: nuget packages root:\n{nugetPackagesRoot}");
|
2016-04-28 23:30:32 +00:00
|
|
|
|
|
2016-10-03 17:06:37 +00:00
|
|
|
|
var toolLockFile = GetToolLockFile(toolLibraryRange, nugetPackagesRoot);
|
2016-02-25 00:05:55 +00:00
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: found tool lockfile at : {toolLockFile.Path}");
|
|
|
|
|
|
2016-10-03 17:06:37 +00:00
|
|
|
|
var toolLibrary = toolLockFile.Targets
|
|
|
|
|
.FirstOrDefault(
|
|
|
|
|
t => t.TargetFramework.GetShortFolderName().Equals(s_toolPackageFramework.GetShortFolderName()))
|
2016-03-28 05:24:20 +00:00
|
|
|
|
?.Libraries.FirstOrDefault(l => l.Name == toolLibraryRange.Name);
|
2016-02-25 00:05:55 +00:00
|
|
|
|
|
2016-03-28 05:24:20 +00:00
|
|
|
|
if (toolLibrary == null)
|
|
|
|
|
{
|
2016-10-28 01:46:43 +00:00
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: library not found in lock file.");
|
|
|
|
|
|
2016-03-28 05:24:20 +00:00
|
|
|
|
return null;
|
|
|
|
|
}
|
2016-04-28 23:30:32 +00:00
|
|
|
|
|
2016-10-03 17:06:37 +00:00
|
|
|
|
var depsFileRoot = Path.GetDirectoryName(toolLockFile.Path);
|
2016-10-28 01:46:43 +00:00
|
|
|
|
|
2016-10-03 17:06:37 +00:00
|
|
|
|
var depsFilePath = GetToolDepsFilePath(toolLibraryRange, toolLockFile, depsFileRoot);
|
2016-04-28 23:30:32 +00:00
|
|
|
|
|
2016-09-28 22:40:38 +00:00
|
|
|
|
var normalizedNugetPackagesRoot = PathUtility.EnsureNoTrailingDirectorySeparator(nugetPackagesRoot);
|
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: attempting to create commandspec");
|
|
|
|
|
|
2016-10-11 00:13:46 +00:00
|
|
|
|
var commandSpec = _packagedCommandSpecFactory.CreateCommandSpecFromLibrary(
|
2016-03-28 05:24:20 +00:00
|
|
|
|
toolLibrary,
|
2016-02-25 00:05:55 +00:00
|
|
|
|
commandName,
|
|
|
|
|
args,
|
|
|
|
|
_allowedCommandExtensions,
|
2016-09-28 22:40:38 +00:00
|
|
|
|
normalizedNugetPackagesRoot,
|
2016-02-25 00:05:55 +00:00
|
|
|
|
s_commandResolutionStrategy,
|
2016-04-07 23:20:51 +00:00
|
|
|
|
depsFilePath,
|
|
|
|
|
null);
|
2016-10-11 00:13:46 +00:00
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
|
if (commandSpec == null)
|
|
|
|
|
{
|
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: commandSpec is null.");
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-11 00:13:46 +00:00
|
|
|
|
commandSpec?.AddEnvironmentVariablesFromProject(project);
|
|
|
|
|
|
|
|
|
|
return commandSpec;
|
2016-03-17 18:45:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private LockFile GetToolLockFile(
|
2016-10-05 01:58:04 +00:00
|
|
|
|
SingleProjectInfo toolLibrary,
|
2016-03-17 18:45:13 +00:00
|
|
|
|
string nugetPackagesRoot)
|
|
|
|
|
{
|
|
|
|
|
var lockFilePath = GetToolLockFilePath(toolLibrary, nugetPackagesRoot);
|
|
|
|
|
|
|
|
|
|
if (!File.Exists(lockFilePath))
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LockFile lockFile = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2016-12-13 22:15:35 +00:00
|
|
|
|
lockFile = new LockFileFormat()
|
|
|
|
|
.ReadWithLock(lockFilePath)
|
|
|
|
|
.Result;
|
2016-03-17 18:45:13 +00:00
|
|
|
|
}
|
|
|
|
|
catch (FileFormatException ex)
|
|
|
|
|
{
|
|
|
|
|
throw ex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lockFile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string GetToolLockFilePath(
|
2016-10-05 01:58:04 +00:00
|
|
|
|
SingleProjectInfo toolLibrary,
|
2016-03-17 18:45:13 +00:00
|
|
|
|
string nugetPackagesRoot)
|
|
|
|
|
{
|
|
|
|
|
var toolPathCalculator = new ToolPathCalculator(nugetPackagesRoot);
|
|
|
|
|
|
|
|
|
|
return toolPathCalculator.GetBestLockFilePath(
|
2016-04-28 23:30:32 +00:00
|
|
|
|
toolLibrary.Name,
|
2016-10-11 00:13:46 +00:00
|
|
|
|
VersionRange.Parse(toolLibrary.Version),
|
2016-03-17 18:45:13 +00:00
|
|
|
|
s_toolPackageFramework);
|
2016-02-25 00:05:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-17 18:45:13 +00:00
|
|
|
|
private string GetToolDepsFilePath(
|
2016-10-05 01:58:04 +00:00
|
|
|
|
SingleProjectInfo toolLibrary,
|
2016-04-28 23:30:32 +00:00
|
|
|
|
LockFile toolLockFile,
|
2016-03-17 18:45:13 +00:00
|
|
|
|
string depsPathRoot)
|
|
|
|
|
{
|
|
|
|
|
var depsJsonPath = Path.Combine(
|
|
|
|
|
depsPathRoot,
|
|
|
|
|
toolLibrary.Name + FileNameSuffixes.DepsJson);
|
|
|
|
|
|
2016-10-28 01:46:43 +00:00
|
|
|
|
Reporter.Verbose.WriteLine($"projecttoolscommandresolver: expect deps.json at: {depsJsonPath}");
|
|
|
|
|
|
2016-10-03 22:36:14 +00:00
|
|
|
|
EnsureToolJsonDepsFileExists(toolLockFile, depsJsonPath, toolLibrary);
|
2016-03-17 18:45:13 +00:00
|
|
|
|
|
|
|
|
|
return depsJsonPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void EnsureToolJsonDepsFileExists(
|
2016-04-28 23:30:32 +00:00
|
|
|
|
LockFile toolLockFile,
|
2016-10-03 22:36:14 +00:00
|
|
|
|
string depsPath,
|
2016-10-05 01:58:04 +00:00
|
|
|
|
SingleProjectInfo toolLibrary)
|
2016-03-17 18:45:13 +00:00
|
|
|
|
{
|
|
|
|
|
if (!File.Exists(depsPath))
|
|
|
|
|
{
|
2016-10-03 22:36:14 +00:00
|
|
|
|
GenerateDepsJsonFile(toolLockFile, depsPath, toolLibrary);
|
2016-04-09 00:07:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-05 01:58:04 +00:00
|
|
|
|
internal void GenerateDepsJsonFile(
|
2016-04-28 23:30:32 +00:00
|
|
|
|
LockFile toolLockFile,
|
2016-10-03 22:36:14 +00:00
|
|
|
|
string depsPath,
|
2016-10-05 01:58:04 +00:00
|
|
|
|
SingleProjectInfo toolLibrary)
|
2016-04-09 00:07:29 +00:00
|
|
|
|
{
|
|
|
|
|
Reporter.Verbose.WriteLine($"Generating deps.json at: {depsPath}");
|
|
|
|
|
|
2016-10-04 04:40:24 +00:00
|
|
|
|
var dependencyContext = new DepsJsonBuilder()
|
2016-10-05 01:58:04 +00:00
|
|
|
|
.Build(toolLibrary, null, toolLockFile, s_toolPackageFramework, null);
|
2016-04-09 00:07:29 +00:00
|
|
|
|
|
|
|
|
|
var tempDepsFile = Path.GetTempFileName();
|
|
|
|
|
using (var fileStream = File.Open(tempDepsFile, FileMode.Open, FileAccess.Write))
|
|
|
|
|
{
|
|
|
|
|
var dependencyContextWriter = new DependencyContextWriter();
|
|
|
|
|
|
|
|
|
|
dependencyContextWriter.Write(dependencyContext, fileStream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2016-12-04 19:54:29 +00:00
|
|
|
|
File.Move(tempDepsFile, depsPath);
|
2016-04-09 00:07:29 +00:00
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Reporter.Verbose.WriteLine($"unable to generate deps.json, it may have been already generated: {e.Message}");
|
2016-12-04 19:54:29 +00:00
|
|
|
|
|
2016-04-09 00:07:29 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
File.Delete(tempDepsFile);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e2)
|
2016-04-28 23:30:32 +00:00
|
|
|
|
{
|
2016-04-09 00:07:29 +00:00
|
|
|
|
Reporter.Verbose.WriteLine($"unable to delete temporary deps.json file: {e2.Message}");
|
2016-03-17 18:45:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-25 00:05:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|