microsoft / CodeContracts

Source code for the CodeContracts tools for .NET
Other
882 stars 151 forks source link

MSI installations conflicts with NuGet #368

Open yaakov-h opened 8 years ago

yaakov-h commented 8 years ago

As mentioned in #13, the NuGet package does not automatically install the targets file in the project.

If I add the following import after Microsoft.CSharp.targets:

  <PropertyGroup>
    <CodeContractsInstallDir>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\packages\DotNet.Contracts.1.10.10126.4\'))</CodeContractsInstallDir>
  </PropertyGroup>
  <Import Project="$(CodeContractsInstallDir)\MsBuild\v$(VisualStudioVersion)\Microsoft.CodeContracts.targets"/>

I get the following build error:

Severity Code Description Project File Line Suppression State
Error "obj\Debug\Decl\ContractNuGetTest.dll;obj\Debug\Decl\ContractNuGetTest.dll" is an invalid value for the "OutputAssembly" parameter of the "Csc" task. Multiple items cannot be passed into a parameter of type "Microsoft.Build.Framework.ITaskItem". ContractNuGetTest

Judging by MSBuild diagnostic output, Microsoft.CodeContracts.targets from the MSI is being included, which means that the targets file from NuGet comes in afterwards and is adding items to now-not-empty ItemGroups.

If I edit the csproj file to reflect the following:

  <PropertyGroup>
    <DontImportCodeContracts>True</DontImportCodeContracts>
  </PropertyGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <PropertyGroup>
    <CodeContractsInstallDir>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\packages\DotNet.Contracts.1.10.10126.4\'))</CodeContractsInstallDir>
  </PropertyGroup>
  <Import Project="$(CodeContractsInstallDir)\MsBuild\v$(VisualStudioVersion)\Microsoft.CodeContracts.targets"/>

Then Contracts work from NuGet, overriding any MSI-installed Code Contracts on the system.

So, I see three problems:

  1. Contracts from NuGet aren't automatically set up
  2. Contracts from the MSI take precedence over Contracts from NuGet. I'm not sure if this one is solvable.
  3. Contracts from NuGet conflict with Contracts from the MSI, it isn't a clean replacement.

I think the simplest solution to this is:

  1. Add a property named CodeContractsPackaged which acts the same as DontImportCodeContracts
  2. Use NuGet to set this property and install the Code Contracts .targets file in the project.
yaakov-h commented 8 years ago

Just re-reading this - scratch (1) on the solution above, we should want the NuGet package to override MSI-installed contracts even when the MSI is an older version. We should therefore use DontImportCodeContracts as-is.