fsprojects / Paket

A dependency manager for .NET with support for NuGet packages and Git repositories.
https://fsprojects.github.io/Paket/
MIT License
2.01k stars 520 forks source link

`paket update` crashes when a project contains a target that manipulates references #3794

Open jbaehr opened 4 years ago

jbaehr commented 4 years ago

Description

I have a project file which contains the following target:

  <Target Name="Workaround31298" Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.7.2'">
    <!-- This target is a workaroud for https://github.com/dotnet/runtime/issues/31298 -->
    <ItemGroup>
      <Reference Remove="System.IO.FileSystem.Primitives" />
    </ItemGroup>
  </Target>
  <Target Name="BeforeResolveReferences" DependsOnTargets="Workaround31298"/>

Background for those interested, but irrelevant for this issue: This project consumes, indirectly, System.IO.Packaging. This package declares empty dependencies for netstandard20 and for net461 it requires System.IO.FileSystem.Primitives. My project targets net472 and Paket considers the net461 dependency branch (this it is inline with nuget.exe). So my project gets a reference to this fs.primitives.dll, too. Unfortunately, the latest version of this System.IO.FileSystem.Primitives package contains an older version of the dll then the net472 facade, which is installed as part of the .NET Framework. The build system detects this and replaces the reference. But because the replacement is a framework dll it does not get copied into the output dir. This again breaks the incremental build over and over again as the dll is missing from the out dir. So to get the incremental build working again, I use this target to remove the unneeded reference. I did not manually remove the actual reference inserted by Paket, because this one would be recreated on the next update/install. Never mess with generated code.

When I now perform a paket update everything works fine up to the point where paket touches the project files. There it crashes.

Repro steps

  1. Place the above msbuild snipped inside an arbitrary C#-Project (below the import of "Microsoft.CSharp.targets")

  2. run paket update (or paket install, this doesn't matter)

Expected behavior

The update should run through. Paket should ignore the "Reference" items inside targets.

Actual behavior

Tested with paket 5.181.1 as well as 5.242.1.

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at Paket.ProjectFileModule.getCustomModelNodes@665.Invoke(XmlNode node)
   at Microsoft.FSharp.Primitives.Basics.List.filter[T](FSharpFunc`2 predicate, FSharpList`1 l)
   at Paket.ProjectFileModule.deleteCustomModelNodes(InstallModel model, ProjectFile project)
   at Paket.ProjectFileModule.contexts@1202-9.Invoke(KeyValuePair`2 kv)
   at Microsoft.FSharp.Collections.Internal.IEnumerator.map@74.DoMoveNext(b& curr)
   at Microsoft.FSharp.Collections.Internal.IEnumerator.MapEnumerator`1.System-Collections-IEnumerator-MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at Microsoft.FSharp.Collections.SeqModule.ToArray[T](IEnumerable`1 source)
   at Microsoft.FSharp.Collections.SeqModule.SortBy@1108.Invoke(Unit unitVar0)
   at Microsoft.FSharp.Collections.SeqModule.mkDelayedSeq@468.Invoke(Unit unitVar0)
   at Microsoft.FSharp.Collections.SeqModule.revamp@573.Invoke(Unit unitVar0)
   at Paket.ProjectFileModule.updateReferences[a,b,c](FSharpMap`2 completeModel, FSharpMap`2 directPackages, FSharpMap`2 usedPackages, ProjectFile project)
   at Paket.InstallProcess.InstallIntoProjects[a](InstallerOptions options, Boolean forceTouch, DependenciesFile dependenciesFile, LockFile lockFile, FSharpList`1 projectsAndReferences, FSharpMap`2 updatedGroups)
   at Paket.UpdateProcess.SmartInstall(DependenciesFile dependenciesFile, UpdateMode updateMode, UpdaterOptions options)
   at <StartupCode$Paket-Core>.$PublicAPI.UpdatePackage@371-3.Invoke(Unit unitVar0)
   at Paket.Utils.RunInLockedAccessMode[a](String lockedFolder, FSharpFunc`2 action)
   at Paket.Program.handleCommand@827-16.Invoke(ParseResults`1 results)
   at Paket.Program.processWithValidationEx$cont@42[a](Boolean silent, FSharpFunc`2 commandF, a result, Unit unitVar)
   at Paket.Program.processWithValidation[T](Boolean silent, FSharpFunc`2 validateF, FSharpFunc`2 commandF, ParseResults`1 result)
   at Paket.Program.handleCommand(Boolean silent, Command command)
   at Paket.Program.main()
   at <StartupCode$paket>.$Paket.Program.main@()
Segmentation fault

Known workarounds

  1. Rename the item in the above msbuild snipped from "Reference" to "Foo". (It does not help remove a dummy reference, i.e. that fact that System.IO.FileSystem.Primitives was inserted by paket is irrelevant.)
  2. run paket update
  3. rename the item back
romerod commented 4 years ago

Had the same problem and found a different workaround: Add nuget System.IO.FileSystem.Primitives to paket.dependencies and add the following to the paket.references files:

System.IO.FileSystem.Primitives
  exclude System.IO.FileSystem.Primitives.dll

Manually add the reference to the projects:
<Reference Include="System.IO.FileSystem.Primitives" />

jbaehr commented 4 years ago

@romerod Thanks, this workaround for https://github.com/dotnet/runtime/issues/31298 is indeed much better as it does not make Paket crash ;-)

As I only build for net472 I do not even need a reference to System.IO.FileSystem.Primitives, so just the two lines to the paket.references of the affected project are sufficient.