Merge pull request #73984 from RedworkDE/net-nuget-cache-fix

C#: Discontinue `GodotNuGetFallbackFolder`
This commit is contained in:
Yuri Sizov 2023-04-10 12:50:59 +02:00 committed by GitHub
commit 98f8638bab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 0 additions and 311 deletions

View File

@ -317,16 +317,6 @@ namespace GodotTools.Build
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
return true; // No solution to build
try
{
// Make sure our packages are added to the fallback folder
NuGetUtils.AddBundledPackagesToFallbackFolder(NuGetUtils.GodotFallbackFolderPath);
}
catch (Exception e)
{
GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
if (GodotSharpEditor.Instance.SkipBuildBeforePlaying)
return true; // Requested play from an external editor/IDE which already built the project

View File

@ -34,16 +34,6 @@ namespace GodotTools.Build
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
return; // No solution to build
try
{
// Make sure our packages are added to the fallback folder
NuGetUtils.AddBundledPackagesToFallbackFolder(NuGetUtils.GodotFallbackFolderPath);
}
catch (Exception e)
{
GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
if (!BuildManager.BuildProjectBlocking("Debug"))
return; // Build failed
@ -62,16 +52,6 @@ namespace GodotTools.Build
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
return; // No solution to build
try
{
// Make sure our packages are added to the fallback folder
NuGetUtils.AddBundledPackagesToFallbackFolder(NuGetUtils.GodotFallbackFolderPath);
}
catch (Exception e)
{
GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
if (!BuildManager.BuildProjectBlocking("Debug", rebuild: true))
return; // Build failed

View File

@ -1,253 +0,0 @@
using System;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using Godot;
using GodotTools.Internals;
using GodotTools.Shared;
using Directory = GodotTools.Utils.Directory;
using Environment = System.Environment;
using File = GodotTools.Utils.File;
namespace GodotTools.Build
{
public static class NuGetUtils
{
public const string GodotFallbackFolderName = "Godot Offline Packages";
public static string GodotFallbackFolderPath
=> Path.Combine(GodotSharpDirs.MonoUserDir, "GodotNuGetFallbackFolder");
/// <summary>
/// Returns all the paths where the Godot.Offline.Config files can be found.
/// Does not determine whether the returned files exist or not.
/// </summary>
private static string[] GetAllGodotNuGetConfigFilePaths()
{
// Where to find 'NuGet/config/Godot.Offline.Config':
//
// - Mono/.NETFramework (standalone NuGet):
// Uses Environment.SpecialFolder.ApplicationData
// - Windows: '%APPDATA%'
// - Linux/macOS: '$HOME/.config'
// - CoreCLR (dotnet CLI NuGet):
// - Windows: '%APPDATA%'
// - Linux/macOS: '$DOTNET_CLI_HOME/.nuget' otherwise '$HOME/.nuget'
string applicationData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
const string configFileName = "Godot.Offline.Config";
if (Utils.OS.IsWindows)
{
// %APPDATA% for both
return new[] { Path.Combine(applicationData, "NuGet", "config", configFileName) };
}
var paths = new string[2];
// CoreCLR (dotnet CLI NuGet)
string dotnetCliHome = Environment.GetEnvironmentVariable("DOTNET_CLI_HOME");
if (!string.IsNullOrEmpty(dotnetCliHome))
{
paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "config", configFileName);
}
else
{
string home = Environment.GetEnvironmentVariable("HOME");
if (string.IsNullOrEmpty(home))
throw new InvalidOperationException("Required environment variable 'HOME' is not set.");
paths[0] = Path.Combine(home, ".nuget", "NuGet", "config", configFileName);
}
// Mono/.NETFramework (standalone NuGet)
// ApplicationData is $HOME/.config on Linux/macOS
paths[1] = Path.Combine(applicationData, "NuGet", "config", configFileName);
return paths;
}
// nupkg extraction
//
// Exclude: (NuGet.Client -> NuGet.Packaging.PackageHelper.ExcludePaths)
// package/
// _rels/
// [Content_Types].xml
//
// Don't ignore files that begin with a dot (.)
//
// The nuspec is not lower case inside the nupkg but must be made lower case when extracted.
/// <summary>
/// Adds the specified fallback folder to the Godot.Offline.Config files,
/// for both standalone NuGet (Mono/.NETFramework) and dotnet CLI NuGet.
/// </summary>
public static void AddFallbackFolderToGodotNuGetConfigs(string name, string path)
{
// Make sure the fallback folder exists to avoid error:
// MSB4018: The "ResolvePackageAssets" task failed unexpectedly.
System.IO.Directory.CreateDirectory(path);
foreach (string nuGetConfigPath in GetAllGodotNuGetConfigFilePaths())
{
string defaultConfig = @$"<?xml version=""1.0"" encoding=""utf-8""?>
<configuration>
<fallbackPackageFolders>
<add key=""{name}"" value=""{path}"" />
</fallbackPackageFolders>
</configuration>
";
System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
}
}
private static void AddPackageToFallbackFolder(string fallbackFolder,
string nupkgPath, string packageId, string packageVersion)
{
// dotnet CLI provides no command for this, but we can do it manually.
//
// - The expected structure is as follows:
// fallback_folder/
// <package.name>/<version>/
// <package.name>.<version>.nupkg
// <package.name>.<version>.nupkg.sha512
// <package.name>.nuspec
// ... extracted nupkg files (check code for excluded files) ...
//
// - <package.name> and <version> must be in lower case.
// - The sha512 of the nupkg is base64 encoded.
// - We can get the nuspec from the nupkg which is a Zip file.
string packageIdLower = packageId.ToLowerInvariant();
string packageVersionLower = packageVersion.ToLowerInvariant();
string destDir = Path.Combine(fallbackFolder, packageIdLower, packageVersionLower);
string nupkgDestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg");
string nupkgSha512DestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg.sha512");
string nupkgMetadataDestPath = Path.Combine(destDir, ".nupkg.metadata");
if (File.Exists(nupkgDestPath) && File.Exists(nupkgSha512DestPath))
return; // Already added (for speed we don't check if every file is properly extracted)
Directory.CreateDirectory(destDir);
// Generate .nupkg.sha512 file
byte[] hash = SHA512.HashData(File.ReadAllBytes(nupkgPath));
string base64Hash = Convert.ToBase64String(hash);
File.WriteAllText(nupkgSha512DestPath, base64Hash);
// Generate .nupkg.metadata file
// Spec: https://github.com/NuGet/Home/wiki/Nupkg-Metadata-File
File.WriteAllText(nupkgMetadataDestPath, @$"{{
""version"": 2,
""contentHash"": ""{base64Hash}"",
""source"": null
}}");
// Extract nupkg
ExtractNupkg(destDir, nupkgPath, packageId, packageVersion);
// Copy .nupkg
File.Copy(nupkgPath, nupkgDestPath);
}
private static readonly string[] NupkgExcludePaths =
{
"_rels/",
"package/",
"[Content_Types].xml"
};
private static void ExtractNupkg(string destDir, string nupkgPath, string packageId, string packageVersion)
{
// NOTE: Must use SimplifyGodotPath to make sure we don't extract files outside the destination directory.
using (var archive = ZipFile.OpenRead(nupkgPath))
{
// Extract .nuspec manually as it needs to be in lower case
var nuspecEntry = archive.GetEntry(packageId + ".nuspec");
if (nuspecEntry == null)
throw new InvalidOperationException(
$"Failed to extract package {packageId}.{packageVersion}. Could not find the nuspec file.");
nuspecEntry.ExtractToFile(Path.Combine(destDir, nuspecEntry.Name
.ToLowerInvariant().SimplifyGodotPath()));
// Extract the other package files
foreach (var entry in archive.Entries)
{
// NOTE: SimplifyGodotPath() removes trailing slash and backslash,
// so we can't use the result to check if the entry is a directory.
string entryFullName = entry.FullName.Replace('\\', '/');
// Check if the file must be ignored
if ( // Excluded files.
NupkgExcludePaths.Any(e => entryFullName.StartsWith(e, StringComparison.OrdinalIgnoreCase)) ||
// Nupkg hash files and nupkg metadata files on all directory.
entryFullName.EndsWith(".nupkg.sha512", StringComparison.OrdinalIgnoreCase) ||
entryFullName.EndsWith(".nupkg.metadata", StringComparison.OrdinalIgnoreCase) ||
// Nuspec at root level. We already extracted it previously but in lower case.
!entryFullName.Contains('/') && entryFullName.EndsWith(".nuspec"))
{
continue;
}
string entryFullNameSimplified = entryFullName.SimplifyGodotPath();
string destFilePath = Path.Combine(destDir, entryFullNameSimplified);
bool isDir = entryFullName.EndsWith("/");
if (isDir)
{
Directory.CreateDirectory(destFilePath);
}
else
{
Directory.CreateDirectory(Path.GetDirectoryName(destFilePath));
entry.ExtractToFile(destFilePath, overwrite: true);
}
}
}
}
/// <summary>
/// Copies and extracts all the Godot bundled packages to the Godot NuGet fallback folder.
/// Does nothing if the packages were already copied.
/// </summary>
public static void AddBundledPackagesToFallbackFolder(string fallbackFolder)
{
GD.Print("Copying Godot Offline Packages...");
string nupkgsLocation = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "nupkgs");
void AddPackage(string packageId, string packageVersion)
{
string nupkgPath = Path.Combine(nupkgsLocation, $"{packageId}.{packageVersion}.nupkg");
AddPackageToFallbackFolder(fallbackFolder, nupkgPath, packageId, packageVersion);
}
foreach (var (packageId, packageVersion) in PackagesToAdd)
AddPackage(packageId, packageVersion);
}
private static readonly (string packageId, string packageVersion)[] PackagesToAdd =
{
("Godot.NET.Sdk", GeneratedGodotNupkgsVersions.GodotNETSdk),
("Godot.SourceGenerators", GeneratedGodotNupkgsVersions.GodotSourceGenerators),
("GodotSharp", GeneratedGodotNupkgsVersions.GodotSharp),
("GodotSharpEditor", GeneratedGodotNupkgsVersions.GodotSharp),
};
}
}

View File

@ -133,22 +133,6 @@ namespace GodotTools
}
break;
}
case MenuOptions.SetupGodotNugetFallbackFolder:
{
try
{
string fallbackFolder = NuGetUtils.GodotFallbackFolderPath;
NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
fallbackFolder);
NuGetUtils.AddBundledPackagesToFallbackFolder(fallbackFolder);
}
catch (Exception e)
{
ShowErrorDialog("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
break;
}
default:
throw new ArgumentOutOfRangeException(nameof(id), id, "Invalid menu option");
}
@ -168,7 +152,6 @@ namespace GodotTools
private enum MenuOptions
{
CreateSln,
SetupGodotNugetFallbackFolder,
}
public void ShowErrorDialog(string message, string title = "Error")
@ -533,17 +516,6 @@ namespace GodotTools
exportPlugin.RegisterExportSettings();
_exportPluginWeak = WeakRef(exportPlugin);
try
{
// At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
NuGetUtils.GodotFallbackFolderPath);
}
catch (Exception e)
{
GD.PushError("Failed to add Godot NuGet Offline Packages to NuGet.Config: " + e.Message);
}
BuildManager.Initialize();
RiderPathManager.Initialize();