如何下载没有依赖项的nuget包?
c#
我使用下面的代码在 CI 过程中安装 nuget 包,
Cake.Common.Tools.NuGet.NuGetAliases.NuGetInstall(context, packageid, new NuGetInstallSettings { NoCache = true, OutputDirectory = "../Packages", });
题:
如何下载没有依赖项的nuget包?
回答
底层工具 NuGet.exe 当前不支持仅下载包,在https://github.com/NuGet/Home/issues/5919上有一个 GitHub 问题跟踪此问题
也就是说,您可以使用其他 Cake 别名或简单的 C# 在 Cake 脚本中实现它。
一个定制的例子是 Cake 自己的网站,它直接从 NuGet.org 下载插件,只获取所需的 dll 和 xmldoc 文件,可以在以下位置找到:https :
//github.com/cake-build/website/blob/9a7bf2fbf8b485488517175376cf11baa3817098/ #L33
如果您对定制的 NuGetInstall 等效项感兴趣,我可以用它更新此答案。
更新添加了“DownloadLatestPackage”示例
Cake NuGet 包下载示例
这是一个示例,说明如何从 Cake 脚本中的 V3 NuGet 源下载 NuGet 包。
用法
#load "nugetinstall.cake"
await context.DownloadLatestPackage(
"PackageId",
"../Packages"
);
完整的 build.cake 示例
#load "nugetinstall.cake"
Task("DownloadPackages")
.Does(
async context => {
foreach(var packageId in new [] { "Cake.Core", "Cake.Common", "Cake.Git" })
{
await context.DownloadLatestPackage(
packageId,
"../Packages"
);
}
}
);
Task("Default")
.IsDependentOn("DownloadPackages");
RunTarget(Argument("target", "Default"));
会输出类似的东西
========================================
DownloadPackages
========================================
Downloading package ../Packages/Cake.Core.1.0.0-rc0002...
Downloading package ../Packages/Cake.Common.1.0.0-rc0002...
Downloading package ../Packages/Cake.Git.0.22.0...
========================================
Default
========================================
Task Duration
--------------------------------------------------
DownloadPackages 00:00:03.3939241
--------------------------------------------------
Total: 00:00:03.3946443
并导致包文件夹看起来像下面
Packages
+---Cake.Common.1.0.0-rc0002
|
+---Cake.Core.1.0.0-rc0002
|
---Cake.Git.0.22.0
Packages
+---Cake.Common.1.0.0-rc0002
|
+---Cake.Core.1.0.0-rc0002
|
---Cake.Git.0.22.0
帮手蛋糕脚本内容
nugetinstall.cake
nugetmodel.cake
#addin nuget:?package=System.Text.Json&version=4.6.0&loaddependencies=true
#load "nugetmodel.cake"
using System.Net.Http;
using System.Text.Json;
public static async Task<T> GetAsync<T>(this HttpClient client, string uri)
{
using (var stream = await client.GetStreamAsync(uri))
{
return await JsonSerializer.DeserializeAsync<T>(
stream,
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
);
}
}
public static async Task<bool> DownloadLatestPackage(this ICakeContext context, string packageId, DirectoryPath outputDirectory, string nuGetSource = "https://api.nuget.org/v3/index.json")
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (string.IsNullOrWhiteSpace(packageId))
{
throw new ArgumentNullException(nameof(packageId));
}
if (string.IsNullOrWhiteSpace(nuGetSource))
{
throw new ArgumentNullException(nameof(nuGetSource));
}
if (outputDirectory == null)
{
throw new ArgumentNullException(nameof(outputDirectory));
}
if (!context.DirectoryExists(outputDirectory))
{
throw new DirectoryNotFoundException($"{nameof(outputDirectory)} ({outputDirectory}) not found.");
}
using(var client = new HttpClient())
{
client.DefaultRequestHeaders.UserAgent.ParseAdd($"Cake NuGet Client/{context.Environment.Runtime.CakeVersion.ToString(3)}");
var nuGetIndex = await client.GetAsync<NuGetIndex>(nuGetSource);
var cakeBaseUrl = string.Concat(
nuGetIndex
?.Resources
?.Where(type => type.Type?.Length == 20
&& type.Type == "RegistrationsBaseUrl"
&& type.Id?.Length > 8 == true
&& type.Id.StartsWith("https://"))
.Select(url => url.Id)
.FirstOrDefault()
?? throw new Exception($"Failed to fetch RegistrationsBaseUrl from {nuGetSource}."),
$"{packageId.ToLowerInvariant()}/index.json"
);
var cakeNuGetIndex = await client.GetAsync<NuGetContainer<NuGetContainer<NuGetPackageEntry>>>(cakeBaseUrl);
var packageEntry = (
from item in cakeNuGetIndex.Items
from version in item.Items
orderby SemVersion.TryParse(
version.CatalogEntry.Version,
out var semVersion
)
? semVersion
: SemVersion.Zero
descending
select version.CatalogEntry
).FirstOrDefault();
if (string.IsNullOrWhiteSpace(packageEntry?.PackageContent))
{
throw new Exception($"Failed to found package uri for {packageId} on source {nuGetSource}");
}
var packageDirectory = outputDirectory.Combine($"{packageEntry.PackageId}.{packageEntry.Version}");
if(context.DirectoryExists(packageDirectory))
{
context.Information("Package {0} already downloaded.", packageDirectory);
return true;
}
context.Information("Downloading package {0}...", packageDirectory);
using (var stream = await client.GetStreamAsync(packageEntry?.PackageContent))
{
using (var zipStream = new System.IO.Compression.ZipArchive(stream))
{
foreach (var entry in zipStream.Entries)
{
var entryPath = packageDirectory.CombineWithFilePath(entry.FullName);
var directory = entryPath.GetDirectory();
context.EnsureDirectoryExists(directory);
using (System.IO.Stream source = entry.Open(),
target = context.FileSystem.GetFile(entryPath).OpenWrite())
{
source.CopyTo(target);
}
}
}
}
return context.DirectoryExists(packageDirectory);
}
}
要旨
作为参考,完整的工作解决方案可以在以下要点中找到
https://gist.github.com/devlead/ca566f58457f558dd33484a73f1352ed#file-build-cake