From 322d27f01ebf62e3a7b539a096ae1ffb14e23d99 Mon Sep 17 00:00:00 2001 From: latkin Date: Mon, 1 Jun 2015 13:32:19 -0700 Subject: [PATCH] Proper handling of VSUTDCF options in up-to-date check, and safer TryGetActiveConfigurationAndPlatform - Use `IVsSolutionBuildManager5.FindActiveProjectCfgName` instead of `IVsSolutionBuildManager2.FindActiveProjectCfg` in `TryGetActiveConfigurationAndPlatform`, as it is not sensitive to sync context - Give proper consideration to the VSUTDCF options flags passed to QueryStartUpToDateCheck fixes #471 closes #479 --- .../unittests/Tests.ProjectSystem.UpToDate.fs | 52 +++++++++++++++++++ .../Project/ProjectConfig.cs | 18 +++++-- .../Project/ProjectNode.cs | 4 +- .../Common.Source.CSharp/Project/Utilities.cs | 22 ++------ .../vs/FsPkgs/FSharp.Project/FS/Project.fs | 2 +- 5 files changed, 74 insertions(+), 24 deletions(-) diff --git a/vsintegration/src/unittests/Tests.ProjectSystem.UpToDate.fs b/vsintegration/src/unittests/Tests.ProjectSystem.UpToDate.fs index 57e2be8df..72fa6922f 100644 --- a/vsintegration/src/unittests/Tests.ProjectSystem.UpToDate.fs +++ b/vsintegration/src/unittests/Tests.ProjectSystem.UpToDate.fs @@ -327,6 +327,58 @@ type UpToDate() = Assert.IsFalse(config.IsFastUpToDateCheckEnabled()) )) + [] + member public this.UTDOptionsFlags () = + this.MakeProjectAndDo(["file1.fs"], [], "", (fun project -> + let configNameDebugx86 = ConfigCanonicalName("Debug", "x86") + let debugConfigx86 = project.ConfigProvider.GetProjectConfiguration(configNameDebugx86) + let buildableConfig = + match debugConfigx86.get_BuildableProjectCfg() with + | 0, bc -> bc + | _ -> failwith "get_BuildableProjectCfg failed" + + let testFlag flag expected = + let supported = Array.zeroCreate 1 + let ready = Array.zeroCreate 1 + buildableConfig.QueryStartUpToDateCheck(flag, supported, ready) |> ignore + Assert.IsTrue(supported.[0] = expected) + Assert.IsTrue(ready.[0] = expected) + + [ VSConstants.VSUTDCF_DTEEONLY, 1 + VSConstants.VSUTDCF_PACKAGE, 0 + VSConstants.VSUTDCF_PRIVATE, 1 + VSConstants.VSUTDCF_REBUILD, 1 ] + |> List.iter (fun (flag, expected) -> testFlag flag expected) + )) + + [] + member public this.UTDOptionsFlagsUTDDisabled () = + this.MakeProjectAndDo(["file1.fs"], [], @" + + true + + ", (fun project -> + let configNameDebugx86 = ConfigCanonicalName("Debug", "x86") + let debugConfigx86 = project.ConfigProvider.GetProjectConfiguration(configNameDebugx86) + let buildableConfig = + match debugConfigx86.get_BuildableProjectCfg() with + | 0, bc -> bc + | _ -> failwith "get_BuildableProjectCfg failed" + + let testFlag flag expected = + let supported = Array.zeroCreate 1 + let ready = Array.zeroCreate 1 + buildableConfig.QueryStartUpToDateCheck(flag, supported, ready) |> ignore + Assert.AreEqual(supported.[0], expected) + Assert.AreEqual(ready.[0], expected) + + [ VSConstants.VSUTDCF_DTEEONLY, 1 + VSConstants.VSUTDCF_PACKAGE, 0 + VSConstants.VSUTDCF_PRIVATE, 0 + VSConstants.VSUTDCF_REBUILD, 0 ] + |> List.iter (fun (flag, expected) -> testFlag flag expected) + )) + [] type ``UpToDate PreserveNewest`` () = diff --git a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectConfig.cs b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectConfig.cs index 161e26d9f..b0e7c34b7 100644 --- a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectConfig.cs +++ b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectConfig.cs @@ -1591,7 +1591,8 @@ internal bool IsUpToDate(OutputWindowLogger logger, bool testing) // in batch build it is possible that config is out of sync. // in this case, don't assume we are up to date ConfigCanonicalName activeConfig = default(ConfigCanonicalName); - if(!Utilities.TryGetActiveConfigurationAndPlatform(ServiceProvider.GlobalProvider, this.project, out activeConfig) || + + if(!Utilities.TryGetActiveConfigurationAndPlatform(ServiceProvider.GlobalProvider, this.project.ProjectIDGuid, out activeConfig) || activeConfig != this.ConfigCanonicalName) { logger.WriteLine("Not up to date: active confic does not match project config. Active: {0} Project: {1}", activeConfig, this.ConfigCanonicalName); @@ -1836,12 +1837,21 @@ public virtual int QueryStartUpToDateCheck(uint options, int[] supported, int[] CCITracing.TraceCall(); config.PrepareBuild(false); - int utdSupported = config.IsFastUpToDateCheckEnabled() ? 1 : 0; + // criteria (same as C# project system): + // - Fast UTD never enabled for package operations + // - Fast UTD always enabled for DTEE operations + // - Otherwise fast UTD enabled as long as it's not explicitly disabled by the project + bool utdSupported = + ((options & VSConstants.VSUTDCF_PACKAGE) == 0) && + (((options & VSConstants.VSUTDCF_DTEEONLY) != 0) || config.IsFastUpToDateCheckEnabled()); + + int utdSupportedFlag = utdSupported ? 1 : 0; if (supported != null && supported.Length > 0) - supported[0] = utdSupported; + supported[0] = utdSupportedFlag; if (ready != null && ready.Length > 0) - ready[0] = utdSupported; + ready[0] = utdSupportedFlag; + return VSConstants.S_OK; } diff --git a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectNode.cs b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectNode.cs index 3167a39ef..b1c2a5d5f 100644 --- a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectNode.cs +++ b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/ProjectNode.cs @@ -4150,7 +4150,7 @@ internal virtual void SetConfiguration(ConfigCanonicalName configCanonicalName) // REVIEW/TODO: shall we abandon accessing automation here and just look at MSBuild state? EnvDTE.Project automationObject = this.GetAutomationObject() as EnvDTE.Project; ConfigCanonicalName currentConfigName; - if (Utilities.TryGetActiveConfigurationAndPlatform(this.Site, InteropSafeIVsHierarchy, out currentConfigName)) + if (Utilities.TryGetActiveConfigurationAndPlatform(this.Site, this.ProjectIDGuid, out currentConfigName)) { if (currentConfigName == configCanonicalName) return; } @@ -4346,7 +4346,7 @@ internal virtual void OnHandleConfigurationRelatedGlobalProperties(object sender } ConfigCanonicalName configCanonicalName; - if (!Utilities.TryGetActiveConfigurationAndPlatform(this.Site, InteropSafeIVsHierarchy, out configCanonicalName)) + if (!Utilities.TryGetActiveConfigurationAndPlatform(this.Site, this.ProjectIDGuid, out configCanonicalName)) { throw new InvalidOperationException(); } diff --git a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/Utilities.cs b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/Utilities.cs index f72d32b48..a032944d8 100644 --- a/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/Utilities.cs +++ b/vsintegration/src/vs/FsPkgs/FSharp.Project/Common.Source.CSharp/Project/Utilities.cs @@ -940,20 +940,14 @@ public static string CanonicalizeFileNameNoThrow(string anyFileName) /// The name of the active configuration. /// The name of the platform. /// true if successfull. - /*internal, but public for FSharp.Project.dll*/ public static bool TryGetActiveConfigurationAndPlatform(System.IServiceProvider serviceProvider, IVsHierarchy hierarchy, out ConfigCanonicalName configCanonicalName) + /*internal, but public for FSharp.Project.dll*/ public static bool TryGetActiveConfigurationAndPlatform(System.IServiceProvider serviceProvider, Guid projectId, out ConfigCanonicalName configCanonicalName) { if (serviceProvider == null) { throw new ArgumentNullException("serviceProvider"); } - if (hierarchy == null) - { - throw new ArgumentNullException("hierarchy"); - } - - - IVsSolutionBuildManager2 solutionBuildManager = serviceProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; + IVsSolutionBuildManager5 solutionBuildManager = serviceProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager5; if (solutionBuildManager == null) { @@ -961,17 +955,11 @@ public static string CanonicalizeFileNameNoThrow(string anyFileName) return false; } - IVsProjectCfg[] activeConfigs = new IVsProjectCfg[1]; - ErrorHandler.ThrowOnFailure(solutionBuildManager.FindActiveProjectCfg(IntPtr.Zero, IntPtr.Zero, hierarchy, activeConfigs)); - - IVsProjectCfg activeCfg = activeConfigs[0]; - - // Can it be that the activeCfg is null? - System.Diagnostics.Debug.Assert(activeCfg != null, "Cannot find the active configuration"); - string canonicalName; - ErrorHandler.ThrowOnFailure(activeCfg.get_CanonicalName(out canonicalName)); + ErrorHandler.ThrowOnFailure(solutionBuildManager.FindActiveProjectCfgName(projectId, out canonicalName)); + configCanonicalName = new ConfigCanonicalName(canonicalName); + return true; } diff --git a/vsintegration/src/vs/FsPkgs/FSharp.Project/FS/Project.fs b/vsintegration/src/vs/FsPkgs/FSharp.Project/FS/Project.fs index adee7db23..2844cc40d 100644 --- a/vsintegration/src/vs/FsPkgs/FSharp.Project/FS/Project.fs +++ b/vsintegration/src/vs/FsPkgs/FSharp.Project/FS/Project.fs @@ -2137,7 +2137,7 @@ See also ...\SetupAuthoring\FSharp\Registry\FSProjSys_Registration.wxs, e.g. if GetCaption(pHierProj) = GetCaption(projNode.InteropSafeIVsHierarchy) then // This code matches what ProjectNode.SetConfiguration would do; that method cannot be called during a build, but at this // current moment in time, it is 'safe' to do this update. - let _,currentConfigName = Utilities.TryGetActiveConfigurationAndPlatform(projNode.Site, projNode.InteropSafeIVsHierarchy) + let _,currentConfigName = Utilities.TryGetActiveConfigurationAndPlatform(projNode.Site, projNode.ProjectIDGuid) MSBuildProject.SetGlobalProperty(projNode.BuildProject, ProjectFileConstants.Configuration, currentConfigName.ConfigName) MSBuildProject.SetGlobalProperty(projNode.BuildProject, ProjectFileConstants.Platform, currentConfigName.MSBuildPlatform) projNode.UpdateMSBuildState() -- GitLab