Skip to content

Commit 4ba934b

Browse files
authored
Merge pull request #65507 from raulsntos/dotnet/nuget-fallback
Fix NuGet fallback folder packages
2 parents 20d6672 + 02bd072 commit 4ba934b

File tree

4 files changed

+46
-92
lines changed

4 files changed

+46
-92
lines changed

modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
<!-- C# source generators -->
1919
<ItemGroup Condition=" '$(DisableImplicitGodotGeneratorReferences)' != 'true' ">
20-
<PackageReference Include="Godot.SourceGenerators" Version="$(PackageFloatingVersion_Godot)" />
20+
<PackageReference Include="Godot.SourceGenerators" Version="$(PackageVersion_Godot_SourceGenerators)" />
2121
</ItemGroup>
2222

2323
<!-- Godot API references -->

modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets

+5-2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
Outputs="$(GeneratedGodotNupkgsVersionsFile)">
2222
<PropertyGroup>
2323
<GenerateGodotNupkgsVersionsCode><![CDATA[
24-
namespace $(RootNamespace) {
25-
public class GeneratedGodotNupkgsVersions {
24+
namespace $(RootNamespace)
25+
{
26+
public class GeneratedGodotNupkgsVersions
27+
{
2628
public const string GodotNETSdk = "$(PackageVersion_Godot_NET_Sdk)"%3b
2729
public const string GodotSourceGenerators = "$(PackageVersion_Godot_SourceGenerators)"%3b
30+
public const string GodotSharp = "$(PackageVersion_GodotSharp)"%3b
2831
}
2932
}
3033
]]></GenerateGodotNupkgsVersionsCode>

modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs

+38-87
Original file line numberDiff line numberDiff line change
@@ -22,71 +22,13 @@ public static class NuGetUtils
2222
public static string GodotFallbackFolderPath
2323
=> Path.Combine(GodotSharpDirs.MonoUserDir, "GodotNuGetFallbackFolder");
2424

25-
private static void AddFallbackFolderToNuGetConfig(string nuGetConfigPath, string name, string path)
26-
{
27-
var xmlDoc = new XmlDocument();
28-
xmlDoc.Load(nuGetConfigPath);
29-
30-
const string nuGetConfigRootName = "configuration";
31-
32-
var rootNode = xmlDoc.DocumentElement;
33-
34-
if (rootNode == null)
35-
{
36-
// No root node, create it
37-
rootNode = xmlDoc.CreateElement(nuGetConfigRootName);
38-
xmlDoc.AppendChild(rootNode);
39-
40-
// Since this can be considered pretty much a new NuGet.Config, add the default nuget.org source as well
41-
XmlElement nugetOrgSourceEntry = xmlDoc.CreateElement("add");
42-
nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = "nuget.org";
43-
nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value =
44-
"https://api.nuget.org/v3/index.json";
45-
nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("protocolVersion")).Value = "3";
46-
rootNode.AppendChild(xmlDoc.CreateElement("packageSources")).AppendChild(nugetOrgSourceEntry);
47-
}
48-
else
49-
{
50-
// Check that the root node is the expected one
51-
if (rootNode.Name != nuGetConfigRootName)
52-
throw new FormatException("Invalid root Xml node for NuGet.Config. " +
53-
$"Expected '{nuGetConfigRootName}' got '{rootNode.Name}'.");
54-
}
55-
56-
var fallbackFoldersNode = rootNode["fallbackPackageFolders"] ??
57-
rootNode.AppendChild(xmlDoc.CreateElement("fallbackPackageFolders"));
58-
59-
// Check if it already has our fallback package folder
60-
for (var xmlNode = fallbackFoldersNode.FirstChild; xmlNode != null; xmlNode = xmlNode.NextSibling)
61-
{
62-
if (xmlNode.NodeType != XmlNodeType.Element)
63-
continue;
64-
65-
var xmlElement = (XmlElement)xmlNode;
66-
if (xmlElement.Name == "add" &&
67-
xmlElement.Attributes["key"]?.Value == name &&
68-
xmlElement.Attributes["value"]?.Value == path)
69-
{
70-
return;
71-
}
72-
}
73-
74-
XmlElement newEntry = xmlDoc.CreateElement("add");
75-
newEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = name;
76-
newEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value = path;
77-
78-
fallbackFoldersNode.AppendChild(newEntry);
79-
80-
xmlDoc.Save(nuGetConfigPath);
81-
}
82-
8325
/// <summary>
84-
/// Returns all the paths where the user NuGet.Config files can be found.
26+
/// Returns all the paths where the Godot.Offline.Config files can be found.
8527
/// Does not determine whether the returned files exist or not.
8628
/// </summary>
87-
private static string[] GetAllUserNuGetConfigFilePaths()
29+
private static string[] GetAllGodotNuGetConfigFilePaths()
8830
{
89-
// Where to find 'NuGet/NuGet.Config':
31+
// Where to find 'NuGet/config/Godot.Offline.Config':
9032
//
9133
// - Mono/.NETFramework (standalone NuGet):
9234
// Uses Environment.SpecialFolder.ApplicationData
@@ -98,10 +40,12 @@ private static string[] GetAllUserNuGetConfigFilePaths()
9840

9941
string applicationData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
10042

43+
const string configFileName = "Godot.Offline.Config";
44+
10145
if (Utils.OS.IsWindows)
10246
{
10347
// %APPDATA% for both
104-
return new[] { Path.Combine(applicationData, "NuGet", "NuGet.Config") };
48+
return new[] { Path.Combine(applicationData, "NuGet", "config", configFileName) };
10549
}
10650

10751
var paths = new string[2];
@@ -111,20 +55,20 @@ private static string[] GetAllUserNuGetConfigFilePaths()
11155
string dotnetCliHome = Environment.GetEnvironmentVariable("DOTNET_CLI_HOME");
11256
if (!string.IsNullOrEmpty(dotnetCliHome))
11357
{
114-
paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "NuGet.Config");
58+
paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "config", configFileName);
11559
}
11660
else
11761
{
11862
string home = Environment.GetEnvironmentVariable("HOME");
11963
if (string.IsNullOrEmpty(home))
12064
throw new InvalidOperationException("Required environment variable 'HOME' is not set.");
121-
paths[0] = Path.Combine(home, ".nuget", "NuGet", "NuGet.Config");
65+
paths[0] = Path.Combine(home, ".nuget", "NuGet", "config", configFileName);
12266
}
12367

12468
// Mono/.NETFramework (standalone NuGet)
12569

12670
// ApplicationData is $HOME/.config on Linux/macOS
127-
paths[1] = Path.Combine(applicationData, "NuGet", "NuGet.Config");
71+
paths[1] = Path.Combine(applicationData, "NuGet", "config", configFileName);
12872

12973
return paths;
13074
}
@@ -141,28 +85,26 @@ private static string[] GetAllUserNuGetConfigFilePaths()
14185
// The nuspec is not lower case inside the nupkg but must be made lower case when extracted.
14286

14387
/// <summary>
144-
/// Adds the specified fallback folder to the user NuGet.Config files,
88+
/// Adds the specified fallback folder to the Godot.Offline.Config files,
14589
/// for both standalone NuGet (Mono/.NETFramework) and dotnet CLI NuGet.
14690
/// </summary>
147-
public static void AddFallbackFolderToUserNuGetConfigs(string name, string path)
91+
public static void AddFallbackFolderToGodotNuGetConfigs(string name, string path)
14892
{
149-
foreach (string nuGetConfigPath in GetAllUserNuGetConfigFilePaths())
93+
// Make sure the fallback folder exists to avoid error:
94+
// MSB4018: The "ResolvePackageAssets" task failed unexpectedly.
95+
System.IO.Directory.CreateDirectory(path);
96+
97+
foreach (string nuGetConfigPath in GetAllGodotNuGetConfigFilePaths())
15098
{
151-
if (!System.IO.File.Exists(nuGetConfigPath))
152-
{
153-
// It doesn't exist, so we create a default one
154-
const string defaultConfig = @"<?xml version=""1.0"" encoding=""utf-8""?>
99+
string defaultConfig = @$"<?xml version=""1.0"" encoding=""utf-8""?>
155100
<configuration>
156-
<packageSources>
157-
<add key=""nuget.org"" value=""https://api.nuget.org/v3/index.json"" protocolVersion=""3"" />
158-
</packageSources>
101+
<fallbackPackageFolders>
102+
<add key=""{name}"" value=""{path}"" />
103+
</fallbackPackageFolders>
159104
</configuration>
160105
";
161-
System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
162-
System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
163-
}
164-
165-
AddFallbackFolderToNuGetConfig(nuGetConfigPath, name, path);
106+
System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
107+
System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
166108
}
167109
}
168110

@@ -189,6 +131,7 @@ private static void AddPackageToFallbackFolder(string fallbackFolder,
189131
string destDir = Path.Combine(fallbackFolder, packageIdLower, packageVersionLower);
190132
string nupkgDestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg");
191133
string nupkgSha512DestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg.sha512");
134+
string nupkgMetadataDestPath = Path.Combine(destDir, ".nupkg.metadata");
192135

193136
if (File.Exists(nupkgDestPath) && File.Exists(nupkgSha512DestPath))
194137
return; // Already added (for speed we don't check if every file is properly extracted)
@@ -197,12 +140,18 @@ private static void AddPackageToFallbackFolder(string fallbackFolder,
197140

198141
// Generate .nupkg.sha512 file
199142

200-
using (var alg = SHA512.Create())
201-
{
202-
alg.ComputeHash(File.ReadAllBytes(nupkgPath));
203-
string base64Hash = Convert.ToBase64String(alg.Hash);
204-
File.WriteAllText(nupkgSha512DestPath, base64Hash);
205-
}
143+
byte[] hash = SHA512.HashData(File.ReadAllBytes(nupkgPath));
144+
string base64Hash = Convert.ToBase64String(hash);
145+
File.WriteAllText(nupkgSha512DestPath, base64Hash);
146+
147+
// Generate .nupkg.metadata file
148+
// Spec: https://github.com/NuGet/Home/wiki/Nupkg-Metadata-File
149+
150+
File.WriteAllText(nupkgMetadataDestPath, @$"{{
151+
""version"": 2,
152+
""contentHash"": ""{base64Hash}"",
153+
""source"": null
154+
}}");
206155

207156
// Extract nupkg
208157
ExtractNupkg(destDir, nupkgPath, packageId, packageVersion);
@@ -251,7 +200,7 @@ private static void ExtractNupkg(string destDir, string nupkgPath, string packag
251200
entryFullName.EndsWith(".nupkg.sha512", StringComparison.OrdinalIgnoreCase) ||
252201
entryFullName.EndsWith(".nupkg.metadata", StringComparison.OrdinalIgnoreCase) ||
253202
// Nuspec at root level. We already extracted it previously but in lower case.
254-
entryFullName.IndexOf('/') == -1 && entryFullName.EndsWith(".nuspec"))
203+
!entryFullName.Contains('/') && entryFullName.EndsWith(".nuspec"))
255204
{
256205
continue;
257206
}
@@ -297,6 +246,8 @@ private static readonly (string packageId, string packageVersion)[] PackagesToAd
297246
{
298247
("Godot.NET.Sdk", GeneratedGodotNupkgsVersions.GodotNETSdk),
299248
("Godot.SourceGenerators", GeneratedGodotNupkgsVersions.GodotSourceGenerators),
249+
("GodotSharp", GeneratedGodotNupkgsVersions.GodotSharp),
250+
("GodotSharpEditor", GeneratedGodotNupkgsVersions.GodotSharp),
300251
};
301252
}
302253
}

modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ private void _MenuOptionPressed(long id)
123123
try
124124
{
125125
string fallbackFolder = NuGetUtils.GodotFallbackFolderPath;
126-
NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
126+
NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
127127
fallbackFolder);
128128
NuGetUtils.AddBundledPackagesToFallbackFolder(fallbackFolder);
129129
}
@@ -497,7 +497,7 @@ public override void _EnablePlugin()
497497
try
498498
{
499499
// At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
500-
NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
500+
NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
501501
NuGetUtils.GodotFallbackFolderPath);
502502
}
503503
catch (Exception e)

0 commit comments

Comments
 (0)