引言
我们都知道, dotnet core的命令行工具运行dotnet restore 会利用nuget获取项目中的依赖项和工具. 上一篇文章dotnet core 使用 MongoDB 进行高性能Nosql数据库操作中, 我引用了MongoDB的驱动库, 但是restore之后, 虽然一切运转正常, 我却产生了迷惑. 以前引用的dll文件默认都会在项目路径中或是在system32中. 找遍了项目文件, 与MongoDB相关的只找到project.json文件中的一句淡淡的引用.
不信找不到你丫的!
通过我不屑的努(sou)力(suo), 终于找到了引用文件的存储位置.
小样, 这也能难倒小爷?
restore命令干了什么?
怀着一个操碎了的心, 我心里打出无数个问号, restore命令到底都干了什么吗?
好吧, 翻源码, 打开dotnet core cli的源码, 很容易就找到了restore命令的代码文件.
public static int Restore(IEnumerable args)
{
var prefixArgs = new List();
if (!args.Any(s => s.Equals("--verbosity", StringComparison.OrdinalIgnoreCase) || s.Equals("-v", StringComparison.OrdinalIgnoreCase)))
{
prefixArgs.Add("--verbosity");
prefixArgs.Add("minimal");
}
prefixArgs.Add("restore");
var nugetApp = new NuGetForwardingApp(Enumerable.Concat(prefixArgs, args));
// setting NUGET_XPROJ_WRITE_TARGETS will tell nuget restore to install .props and .targets files
// coming from NuGet packages
const string nugetXProjWriteTargets = "NUGET_XPROJ_WRITE_TARGETS";
bool setXProjWriteTargets = Environment.GetEnvironmentVariable(nugetXProjWriteTargets) == null;
if (setXProjWriteTargets)
{
nugetApp.WithEnvironmentVariable(nugetXProjWriteTargets, "true");
}
return nugetApp.Execute();
}
通读了一遍, 发现只是一些参数处理, 对于我的问题, 并没有什么卵用.
不过至少我找到了它 NuGetForwardingApp , 就是它隐藏了真正干活的家伙, 接着追, 找到了真正的幕后黑手 NuGet.CommandLine.XPlat.dll 就是它, 其实就是nuget client的dotnet core 版本. 好吧, clone 代码, 接着翻. 顺便说一下, nuget的源码在https://github.com/NuGet?page=1, 有兴趣的童鞋自行获取.
通过我的不屑努力, 终于在一周之后找到了实际的逻辑代码.
代码700多行, 贴这肯定有人说我凑字, 我才不上当:-) 说下路径吧, 在nuget.client项目下的 nuget.core->nuget.commands->RestoreCommand->RestoreCommand.cs
具体的逻辑也很简单. 如官方文档所言, restore会获取依赖的文件和工具, 所以有两个函数ExecuteRestoreAsync和ExecuteToolRestoresAsync
在ProjectRestoreCommand.TryRestore中, 首先根据project.json文件, 处理Framework的支持
foreach (var pair in runtimesByFramework)
{
_logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, pair.Key.DotNetFrameworkName));
frameworkTasks.Add(WalkDependenciesAsync(projectRange,
pair.Key,
remoteWalker,
context,
token: token));
}
生成项目依赖库的图
foreach (var graph in graphs)
{
// Get the runtime graph for this specific tfm graph
var runtimeGraph = GetRuntimeGraph(graph, localRepositories);
var runtimeIds = runtimesByFramework[graph.Framework];
// Merge all runtimes for the output
allRuntimes = RuntimeGraph.Merge(allRuntimes, runtimeGraph);
runtimeTasks.Add(WalkRuntimeDependenciesAsync(projectRange,
graph,
runtimeIds.Where(rid => !string.IsNullOrEmpty(rid)),
remoteWalker,
context,
runtimeGraph,
token: token));
}
foreach (var runtimeSpecificGraph in (await Task.WhenAll(runtimeTasks)).SelectMany(g => g))
{
runtimeGraphs.Add(runtimeSpecificGraph);
}
根据生成的图安装相应的依赖文件
// Install runtime-specific packages
await InstallPackagesAsync(runtimeGraphs,
allInstalledPackages,
token);
好了, 今天就到这, 有什么问题欢迎讨论.
什么? 开始的问题还没解决?