Merge pull request #65507 from raulsntos/dotnet/nuget-fallback
Fix NuGet fallback folder packages
This commit is contained in:
commit
4ba934bf3d
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
<!-- C# source generators -->
|
<!-- C# source generators -->
|
||||||
<ItemGroup Condition=" '$(DisableImplicitGodotGeneratorReferences)' != 'true' ">
|
<ItemGroup Condition=" '$(DisableImplicitGodotGeneratorReferences)' != 'true' ">
|
||||||
<PackageReference Include="Godot.SourceGenerators" Version="$(PackageFloatingVersion_Godot)" />
|
<PackageReference Include="Godot.SourceGenerators" Version="$(PackageVersion_Godot_SourceGenerators)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Godot API references -->
|
<!-- Godot API references -->
|
||||||
|
@ -21,10 +21,13 @@
|
|||||||
Outputs="$(GeneratedGodotNupkgsVersionsFile)">
|
Outputs="$(GeneratedGodotNupkgsVersionsFile)">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<GenerateGodotNupkgsVersionsCode><![CDATA[
|
<GenerateGodotNupkgsVersionsCode><![CDATA[
|
||||||
namespace $(RootNamespace) {
|
namespace $(RootNamespace)
|
||||||
public class GeneratedGodotNupkgsVersions {
|
{
|
||||||
|
public class GeneratedGodotNupkgsVersions
|
||||||
|
{
|
||||||
public const string GodotNETSdk = "$(PackageVersion_Godot_NET_Sdk)"%3b
|
public const string GodotNETSdk = "$(PackageVersion_Godot_NET_Sdk)"%3b
|
||||||
public const string GodotSourceGenerators = "$(PackageVersion_Godot_SourceGenerators)"%3b
|
public const string GodotSourceGenerators = "$(PackageVersion_Godot_SourceGenerators)"%3b
|
||||||
|
public const string GodotSharp = "$(PackageVersion_GodotSharp)"%3b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]]></GenerateGodotNupkgsVersionsCode>
|
]]></GenerateGodotNupkgsVersionsCode>
|
||||||
|
@ -22,71 +22,13 @@ namespace GodotTools.Build
|
|||||||
public static string GodotFallbackFolderPath
|
public static string GodotFallbackFolderPath
|
||||||
=> Path.Combine(GodotSharpDirs.MonoUserDir, "GodotNuGetFallbackFolder");
|
=> Path.Combine(GodotSharpDirs.MonoUserDir, "GodotNuGetFallbackFolder");
|
||||||
|
|
||||||
private static void AddFallbackFolderToNuGetConfig(string nuGetConfigPath, string name, string path)
|
|
||||||
{
|
|
||||||
var xmlDoc = new XmlDocument();
|
|
||||||
xmlDoc.Load(nuGetConfigPath);
|
|
||||||
|
|
||||||
const string nuGetConfigRootName = "configuration";
|
|
||||||
|
|
||||||
var rootNode = xmlDoc.DocumentElement;
|
|
||||||
|
|
||||||
if (rootNode == null)
|
|
||||||
{
|
|
||||||
// No root node, create it
|
|
||||||
rootNode = xmlDoc.CreateElement(nuGetConfigRootName);
|
|
||||||
xmlDoc.AppendChild(rootNode);
|
|
||||||
|
|
||||||
// Since this can be considered pretty much a new NuGet.Config, add the default nuget.org source as well
|
|
||||||
XmlElement nugetOrgSourceEntry = xmlDoc.CreateElement("add");
|
|
||||||
nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = "nuget.org";
|
|
||||||
nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value =
|
|
||||||
"https://api.nuget.org/v3/index.json";
|
|
||||||
nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("protocolVersion")).Value = "3";
|
|
||||||
rootNode.AppendChild(xmlDoc.CreateElement("packageSources")).AppendChild(nugetOrgSourceEntry);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check that the root node is the expected one
|
|
||||||
if (rootNode.Name != nuGetConfigRootName)
|
|
||||||
throw new FormatException("Invalid root Xml node for NuGet.Config. " +
|
|
||||||
$"Expected '{nuGetConfigRootName}' got '{rootNode.Name}'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var fallbackFoldersNode = rootNode["fallbackPackageFolders"] ??
|
|
||||||
rootNode.AppendChild(xmlDoc.CreateElement("fallbackPackageFolders"));
|
|
||||||
|
|
||||||
// Check if it already has our fallback package folder
|
|
||||||
for (var xmlNode = fallbackFoldersNode.FirstChild; xmlNode != null; xmlNode = xmlNode.NextSibling)
|
|
||||||
{
|
|
||||||
if (xmlNode.NodeType != XmlNodeType.Element)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var xmlElement = (XmlElement)xmlNode;
|
|
||||||
if (xmlElement.Name == "add" &&
|
|
||||||
xmlElement.Attributes["key"]?.Value == name &&
|
|
||||||
xmlElement.Attributes["value"]?.Value == path)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XmlElement newEntry = xmlDoc.CreateElement("add");
|
|
||||||
newEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = name;
|
|
||||||
newEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value = path;
|
|
||||||
|
|
||||||
fallbackFoldersNode.AppendChild(newEntry);
|
|
||||||
|
|
||||||
xmlDoc.Save(nuGetConfigPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns all the paths where the user NuGet.Config files can be found.
|
/// Returns all the paths where the Godot.Offline.Config files can be found.
|
||||||
/// Does not determine whether the returned files exist or not.
|
/// Does not determine whether the returned files exist or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static string[] GetAllUserNuGetConfigFilePaths()
|
private static string[] GetAllGodotNuGetConfigFilePaths()
|
||||||
{
|
{
|
||||||
// Where to find 'NuGet/NuGet.Config':
|
// Where to find 'NuGet/config/Godot.Offline.Config':
|
||||||
//
|
//
|
||||||
// - Mono/.NETFramework (standalone NuGet):
|
// - Mono/.NETFramework (standalone NuGet):
|
||||||
// Uses Environment.SpecialFolder.ApplicationData
|
// Uses Environment.SpecialFolder.ApplicationData
|
||||||
@ -98,10 +40,12 @@ namespace GodotTools.Build
|
|||||||
|
|
||||||
string applicationData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
string applicationData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||||
|
|
||||||
|
const string configFileName = "Godot.Offline.Config";
|
||||||
|
|
||||||
if (Utils.OS.IsWindows)
|
if (Utils.OS.IsWindows)
|
||||||
{
|
{
|
||||||
// %APPDATA% for both
|
// %APPDATA% for both
|
||||||
return new[] { Path.Combine(applicationData, "NuGet", "NuGet.Config") };
|
return new[] { Path.Combine(applicationData, "NuGet", "config", configFileName) };
|
||||||
}
|
}
|
||||||
|
|
||||||
var paths = new string[2];
|
var paths = new string[2];
|
||||||
@ -111,20 +55,20 @@ namespace GodotTools.Build
|
|||||||
string dotnetCliHome = Environment.GetEnvironmentVariable("DOTNET_CLI_HOME");
|
string dotnetCliHome = Environment.GetEnvironmentVariable("DOTNET_CLI_HOME");
|
||||||
if (!string.IsNullOrEmpty(dotnetCliHome))
|
if (!string.IsNullOrEmpty(dotnetCliHome))
|
||||||
{
|
{
|
||||||
paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "NuGet.Config");
|
paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "config", configFileName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string home = Environment.GetEnvironmentVariable("HOME");
|
string home = Environment.GetEnvironmentVariable("HOME");
|
||||||
if (string.IsNullOrEmpty(home))
|
if (string.IsNullOrEmpty(home))
|
||||||
throw new InvalidOperationException("Required environment variable 'HOME' is not set.");
|
throw new InvalidOperationException("Required environment variable 'HOME' is not set.");
|
||||||
paths[0] = Path.Combine(home, ".nuget", "NuGet", "NuGet.Config");
|
paths[0] = Path.Combine(home, ".nuget", "NuGet", "config", configFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mono/.NETFramework (standalone NuGet)
|
// Mono/.NETFramework (standalone NuGet)
|
||||||
|
|
||||||
// ApplicationData is $HOME/.config on Linux/macOS
|
// ApplicationData is $HOME/.config on Linux/macOS
|
||||||
paths[1] = Path.Combine(applicationData, "NuGet", "NuGet.Config");
|
paths[1] = Path.Combine(applicationData, "NuGet", "config", configFileName);
|
||||||
|
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
@ -141,28 +85,26 @@ namespace GodotTools.Build
|
|||||||
// The nuspec is not lower case inside the nupkg but must be made lower case when extracted.
|
// The nuspec is not lower case inside the nupkg but must be made lower case when extracted.
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the specified fallback folder to the user NuGet.Config files,
|
/// Adds the specified fallback folder to the Godot.Offline.Config files,
|
||||||
/// for both standalone NuGet (Mono/.NETFramework) and dotnet CLI NuGet.
|
/// for both standalone NuGet (Mono/.NETFramework) and dotnet CLI NuGet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void AddFallbackFolderToUserNuGetConfigs(string name, string path)
|
public static void AddFallbackFolderToGodotNuGetConfigs(string name, string path)
|
||||||
{
|
{
|
||||||
foreach (string nuGetConfigPath in GetAllUserNuGetConfigFilePaths())
|
// 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())
|
||||||
{
|
{
|
||||||
if (!System.IO.File.Exists(nuGetConfigPath))
|
string defaultConfig = @$"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||||
{
|
|
||||||
// It doesn't exist, so we create a default one
|
|
||||||
const string defaultConfig = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<fallbackPackageFolders>
|
||||||
<add key=""nuget.org"" value=""https://api.nuget.org/v3/index.json"" protocolVersion=""3"" />
|
<add key=""{name}"" value=""{path}"" />
|
||||||
</packageSources>
|
</fallbackPackageFolders>
|
||||||
</configuration>
|
</configuration>
|
||||||
";
|
";
|
||||||
System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
|
System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
|
||||||
System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
|
System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
|
||||||
}
|
|
||||||
|
|
||||||
AddFallbackFolderToNuGetConfig(nuGetConfigPath, name, path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,6 +131,7 @@ namespace GodotTools.Build
|
|||||||
string destDir = Path.Combine(fallbackFolder, packageIdLower, packageVersionLower);
|
string destDir = Path.Combine(fallbackFolder, packageIdLower, packageVersionLower);
|
||||||
string nupkgDestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg");
|
string nupkgDestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg");
|
||||||
string nupkgSha512DestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg.sha512");
|
string nupkgSha512DestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg.sha512");
|
||||||
|
string nupkgMetadataDestPath = Path.Combine(destDir, ".nupkg.metadata");
|
||||||
|
|
||||||
if (File.Exists(nupkgDestPath) && File.Exists(nupkgSha512DestPath))
|
if (File.Exists(nupkgDestPath) && File.Exists(nupkgSha512DestPath))
|
||||||
return; // Already added (for speed we don't check if every file is properly extracted)
|
return; // Already added (for speed we don't check if every file is properly extracted)
|
||||||
@ -197,12 +140,18 @@ namespace GodotTools.Build
|
|||||||
|
|
||||||
// Generate .nupkg.sha512 file
|
// Generate .nupkg.sha512 file
|
||||||
|
|
||||||
using (var alg = SHA512.Create())
|
byte[] hash = SHA512.HashData(File.ReadAllBytes(nupkgPath));
|
||||||
{
|
string base64Hash = Convert.ToBase64String(hash);
|
||||||
alg.ComputeHash(File.ReadAllBytes(nupkgPath));
|
File.WriteAllText(nupkgSha512DestPath, base64Hash);
|
||||||
string base64Hash = Convert.ToBase64String(alg.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
|
// Extract nupkg
|
||||||
ExtractNupkg(destDir, nupkgPath, packageId, packageVersion);
|
ExtractNupkg(destDir, nupkgPath, packageId, packageVersion);
|
||||||
@ -251,7 +200,7 @@ namespace GodotTools.Build
|
|||||||
entryFullName.EndsWith(".nupkg.sha512", StringComparison.OrdinalIgnoreCase) ||
|
entryFullName.EndsWith(".nupkg.sha512", StringComparison.OrdinalIgnoreCase) ||
|
||||||
entryFullName.EndsWith(".nupkg.metadata", StringComparison.OrdinalIgnoreCase) ||
|
entryFullName.EndsWith(".nupkg.metadata", StringComparison.OrdinalIgnoreCase) ||
|
||||||
// Nuspec at root level. We already extracted it previously but in lower case.
|
// Nuspec at root level. We already extracted it previously but in lower case.
|
||||||
entryFullName.IndexOf('/') == -1 && entryFullName.EndsWith(".nuspec"))
|
!entryFullName.Contains('/') && entryFullName.EndsWith(".nuspec"))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -297,6 +246,8 @@ namespace GodotTools.Build
|
|||||||
{
|
{
|
||||||
("Godot.NET.Sdk", GeneratedGodotNupkgsVersions.GodotNETSdk),
|
("Godot.NET.Sdk", GeneratedGodotNupkgsVersions.GodotNETSdk),
|
||||||
("Godot.SourceGenerators", GeneratedGodotNupkgsVersions.GodotSourceGenerators),
|
("Godot.SourceGenerators", GeneratedGodotNupkgsVersions.GodotSourceGenerators),
|
||||||
|
("GodotSharp", GeneratedGodotNupkgsVersions.GodotSharp),
|
||||||
|
("GodotSharpEditor", GeneratedGodotNupkgsVersions.GodotSharp),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ namespace GodotTools
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
string fallbackFolder = NuGetUtils.GodotFallbackFolderPath;
|
string fallbackFolder = NuGetUtils.GodotFallbackFolderPath;
|
||||||
NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
|
NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
|
||||||
fallbackFolder);
|
fallbackFolder);
|
||||||
NuGetUtils.AddBundledPackagesToFallbackFolder(fallbackFolder);
|
NuGetUtils.AddBundledPackagesToFallbackFolder(fallbackFolder);
|
||||||
}
|
}
|
||||||
@ -497,7 +497,7 @@ namespace GodotTools
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
|
// At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
|
||||||
NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
|
NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
|
||||||
NuGetUtils.GodotFallbackFolderPath);
|
NuGetUtils.GodotFallbackFolderPath);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
Loading…
Reference in New Issue
Block a user