diff options
author | Ignacio Etcheverry <ignalfonsore@gmail.com> | 2019-07-11 14:01:25 +0200 |
---|---|---|
committer | Ignacio Etcheverry <ignalfonsore@gmail.com> | 2019-07-14 19:17:07 +0200 |
commit | e59ac40712aa656e94072f0bdd60147c49b003aa (patch) | |
tree | 321747690579634788d5c746eb73fa13f9aff1f7 /modules/mono/editor/GodotTools | |
parent | 4061e132ff4a5cdbe76390fa55fb7eacbf4afe97 (diff) |
Mono: Better handling of missing/outdated API assemblies
Remove the old API assembly invalidation system. It's pretty simple since now the editor has a hard dependency on the API assemblies and SCons takes care of prebuilding them.
If we fail to load a project's API assembly because it was either missing or outdated, we just copy the prebuilt assemblies to the project and try again. We also do this when creating the solution and before building, just in case the user removed them from the disk after they were loaded.
This way the API assemblies will be always loaded successfully. If they are not, it's a bug.
Also fixed:
- EditorDef was behaving like GlobalDef in GodotTools.
- NullReferenceException because we can't serialize System.WeakReference yet. Use Godot.WeakRef in the mean time.
Diffstat (limited to 'modules/mono/editor/GodotTools')
3 files changed, 18 insertions, 218 deletions
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs index e606781115..a884b0ead0 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpBuilds.cs @@ -193,134 +193,14 @@ namespace GodotTools return false; } - private static bool CopyApiAssembly(string srcDir, string dstDir, string assemblyName, ApiAssemblyType apiType) - { - // Create destination directory if needed - if (!Directory.Exists(dstDir)) - { - try - { - Directory.CreateDirectory(dstDir); - } - catch (IOException e) - { - ShowBuildErrorDialog($"Failed to create destination directory for the API assemblies. Exception message: {e.Message}"); - return false; - } - } - - string assemblyFile = assemblyName + ".dll"; - string assemblySrc = Path.Combine(srcDir, assemblyFile); - string assemblyDst = Path.Combine(dstDir, assemblyFile); - - if (!File.Exists(assemblyDst) || File.GetLastWriteTime(assemblySrc) > File.GetLastWriteTime(assemblyDst) || - Internal.MetadataIsApiAssemblyInvalidated(apiType)) - { - string xmlFile = $"{assemblyName}.xml"; - string pdbFile = $"{assemblyName}.pdb"; - - try - { - File.Copy(Path.Combine(srcDir, xmlFile), Path.Combine(dstDir, xmlFile)); - } - catch (IOException e) - { - Godot.GD.PushWarning(e.ToString()); - } - - try - { - File.Copy(Path.Combine(srcDir, pdbFile), Path.Combine(dstDir, pdbFile)); - } - catch (IOException e) - { - Godot.GD.PushWarning(e.ToString()); - } - - try - { - File.Copy(assemblySrc, assemblyDst); - } - catch (IOException e) - { - ShowBuildErrorDialog($"Failed to copy {assemblyFile}. Exception message: {e.Message}"); - return false; - } - - Internal.MetadataSetApiAssemblyInvalidated(apiType, false); - } - - return true; - } - - public static bool MakeApiAssembly(ApiAssemblyType apiType, string config) - { - string apiName = apiType == ApiAssemblyType.Core ? ApiAssemblyNames.Core : ApiAssemblyNames.Editor; - - string editorPrebuiltApiDir = Path.Combine(GodotSharpDirs.DataEditorPrebuiltApiDir, config); - string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, config); - - if (File.Exists(Path.Combine(editorPrebuiltApiDir, $"{apiName}.dll"))) - { - using (var copyProgress = new EditorProgress("mono_copy_prebuilt_api_assembly", $"Copying prebuilt {apiName} assembly...", 1)) - { - copyProgress.Step($"Copying {apiName} assembly", 0); - return CopyApiAssembly(editorPrebuiltApiDir, resAssembliesDir, apiName, apiType); - } - } - - const string apiSolutionName = ApiAssemblyNames.SolutionName; - - using (var pr = new EditorProgress($"mono_build_release_{apiSolutionName}", $"Building {apiSolutionName} solution...", 3)) - { - pr.Step($"Generating {apiSolutionName} solution", 0); - - string apiSlnDir = Path.Combine(GodotSharpDirs.MonoSolutionsDir, _ApiFolderName(ApiAssemblyType.Core)); - string apiSlnFile = Path.Combine(apiSlnDir, $"{apiSolutionName}.sln"); - - if (!Directory.Exists(apiSlnDir) || !File.Exists(apiSlnFile)) - { - var bindingsGenerator = new BindingsGenerator(); - - if (!Godot.OS.IsStdoutVerbose()) - bindingsGenerator.LogPrintEnabled = false; - - Error err = bindingsGenerator.GenerateCsApi(apiSlnDir); - if (err != Error.Ok) - { - ShowBuildErrorDialog($"Failed to generate {apiSolutionName} solution. Error: {err}"); - return false; - } - } - - pr.Step($"Building {apiSolutionName} solution", 1); - - if (!BuildApiSolution(apiSlnDir, config)) - return false; - - pr.Step($"Copying {apiName} assembly", 2); - - // Copy the built assembly to the assemblies directory - string apiAssemblyDir = Path.Combine(apiSlnDir, apiName, "bin", config); - if (!CopyApiAssembly(apiAssemblyDir, resAssembliesDir, apiName, apiType)) - return false; - } - - return true; - } - public static bool BuildProjectBlocking(string config, IEnumerable<string> godotDefines) { if (!File.Exists(GodotSharpDirs.ProjectSlnPath)) return true; // No solution to build - string apiConfig = config == "Release" ? "Release" : "Debug"; - - if (!MakeApiAssembly(ApiAssemblyType.Core, apiConfig)) - return false; - - if (!MakeApiAssembly(ApiAssemblyType.Editor, apiConfig)) - return false; + // Make sure to update the API assemblies if they happen to be missing. Just in + // case the user decided to delete them at some point after they were loaded. + Internal.UpdateApiAssembliesFromPrebuilt(); using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1)) { diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 422752bb72..90dec43412 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -27,7 +27,7 @@ namespace GodotTools private MonoDevelopInstance monoDevelopInstance; private MonoDevelopInstance visualStudioForMacInstance; - private WeakReference<GodotSharpExport> exportPluginWeak; + private WeakRef exportPluginWeak; // TODO Use WeakReference once we have proper serialization public MonoBottomPanel MonoBottomPanel { get; private set; } @@ -72,13 +72,9 @@ namespace GodotTools return false; } - string apiConfig = "Debug"; - - if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Core, apiConfig)) - return false; - - if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Editor, apiConfig)) - return false; + // Make sure to update the API assemblies if they happen to be missing. Just in + // case the user decided to delete them at some point after they were loaded. + Internal.UpdateApiAssembliesFromPrebuilt(); pr.Step("Done".TTR()); @@ -94,70 +90,6 @@ namespace GodotTools } } - private static int _makeApiSolutionsAttempts = 100; - private static bool _makeApiSolutionsRecursionGuard = false; - - private void _MakeApiSolutionsIfNeeded() - { - // I'm sick entirely of ProgressDialog - - if (Internal.IsMessageQueueFlushing() || Engine.GetMainLoop() == null) - { - if (_makeApiSolutionsAttempts == 0) // This better never happen or I swear... - throw new TimeoutException(); - - if (Engine.GetMainLoop() != null) - { - if (!Engine.GetMainLoop().IsConnected("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded))) - Engine.GetMainLoop().Connect("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded)); - } - else - { - CallDeferred(nameof(_MakeApiSolutionsIfNeededImpl)); - } - - _makeApiSolutionsAttempts--; - return; - } - - // Recursion guard needed because signals don't play well with ProgressDialog either, but unlike - // the message queue, with signals the collateral damage should be minimal in the worst case. - if (!_makeApiSolutionsRecursionGuard) - { - _makeApiSolutionsRecursionGuard = true; - - // Oneshot signals don't play well with ProgressDialog either, so we do it this way instead - if (Engine.GetMainLoop().IsConnected("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded))) - Engine.GetMainLoop().Disconnect("idle_frame", this, nameof(_MakeApiSolutionsIfNeeded)); - - _MakeApiSolutionsIfNeededImpl(); - - _makeApiSolutionsRecursionGuard = false; - } - } - - private void _MakeApiSolutionsIfNeededImpl() - { - // If the project has a solution and C# project make sure the API assemblies are present and up to date - - string api_config = "Debug"; - string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, api_config); - - if (!File.Exists(Path.Combine(resAssembliesDir, $"{ApiAssemblyNames.Core}.dll")) || - Internal.MetadataIsApiAssemblyInvalidated(ApiAssemblyType.Core)) - { - if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Core, api_config)) - return; - } - - if (!File.Exists(Path.Combine(resAssembliesDir, $"{ApiAssemblyNames.Editor}.dll")) || - Internal.MetadataIsApiAssemblyInvalidated(ApiAssemblyType.Editor)) - { - if (!GodotSharpBuilds.MakeApiAssembly(ApiAssemblyType.Editor, api_config)) - return; // Redundant? I don't think so! - } - } - private void _RemoveCreateSlnMenuOption() { menuPopup.RemoveItem(menuPopup.GetItemIndex((int) MenuOptions.CreateSln)); @@ -465,9 +397,6 @@ namespace GodotTools if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath)) { - // Defer this task because EditorProgress calls Main::iterarion() and the main loop is not yet initialized. - CallDeferred(nameof(_MakeApiSolutionsIfNeeded)); - // Make sure the existing project has Api assembly references configured correctly CSharpProject.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath); } @@ -521,7 +450,7 @@ namespace GodotTools // Export plugin var exportPlugin = new GodotSharpExport(); AddExportPlugin(exportPlugin); - exportPluginWeak = new WeakReference<GodotSharpExport>(exportPlugin); + exportPluginWeak = WeakRef(exportPlugin); GodotSharpBuilds.Initialize(); } @@ -530,13 +459,15 @@ namespace GodotTools { base.Dispose(disposing); - if (exportPluginWeak.TryGetTarget(out var exportPlugin)) + if (exportPluginWeak != null) { // We need to dispose our export plugin before the editor destroys EditorSettings. // Otherwise, if the GC disposes it at a later time, EditorExportPlatformAndroid // will be freed after EditorSettings already was, and its device polling thread // will try to access the EditorSettings singleton, resulting in null dereferencing. - exportPlugin.Dispose(); + (exportPluginWeak.GetRef() as GodotSharpExport)?.Dispose(); + + exportPluginWeak.Dispose(); } } diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs index c33cb8b785..9526dd3c6f 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs @@ -10,6 +10,9 @@ namespace GodotTools.Internals public const string CSharpLanguageType = "CSharpScript"; public const string CSharpLanguageExtension = "cs"; + public static string UpdateApiAssembliesFromPrebuilt() => + internal_UpdateApiAssembliesFromPrebuilt(); + public static string FullTemplatesDir => internal_FullTemplatesDir(); @@ -17,14 +20,6 @@ namespace GodotTools.Internals public static bool IsOsxAppBundleInstalled(string bundleId) => internal_IsOsxAppBundleInstalled(bundleId); - public static bool MetadataIsApiAssemblyInvalidated(ApiAssemblyType apiType) => - internal_MetadataIsApiAssemblyInvalidated(apiType); - - public static void MetadataSetApiAssemblyInvalidated(ApiAssemblyType apiType, bool invalidated) => - internal_MetadataSetApiAssemblyInvalidated(apiType, invalidated); - - public static bool IsMessageQueueFlushing() => internal_IsMessageQueueFlushing(); - public static bool GodotIs32Bits() => internal_GodotIs32Bits(); public static bool GodotIsRealTDouble() => internal_GodotIsRealTDouble(); @@ -54,6 +49,9 @@ namespace GodotTools.Internals // Internal Calls [MethodImpl(MethodImplOptions.InternalCall)] + private static extern string internal_UpdateApiAssembliesFromPrebuilt(); + + [MethodImpl(MethodImplOptions.InternalCall)] private static extern string internal_FullTemplatesDir(); [MethodImpl(MethodImplOptions.InternalCall)] @@ -63,15 +61,6 @@ namespace GodotTools.Internals private static extern bool internal_IsOsxAppBundleInstalled(string bundleId); [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool internal_MetadataIsApiAssemblyInvalidated(ApiAssemblyType apiType); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void internal_MetadataSetApiAssemblyInvalidated(ApiAssemblyType apiType, bool invalidated); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern bool internal_IsMessageQueueFlushing(); - - [MethodImpl(MethodImplOptions.InternalCall)] private static extern bool internal_GodotIs32Bits(); [MethodImpl(MethodImplOptions.InternalCall)] |